@deck.gl/mapbox 8.8.7 → 8.9.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/deck-utils.ts CHANGED
@@ -3,13 +3,19 @@ import type {DeckProps, MapViewState, Layer} from '@deck.gl/core';
3
3
  import type MapboxLayer from './mapbox-layer';
4
4
  import type {Map} from 'mapbox-gl';
5
5
 
6
+ import {lngLatToWorld, unitsPerMeter} from '@math.gl/web-mercator';
7
+
6
8
  type UserData = {
7
9
  isExternal: boolean;
8
10
  currentViewport?: WebMercatorViewport | null;
9
11
  mapboxLayers: Set<MapboxLayer<any>>;
10
- mapboxVersion: {minor: number; major: number};
12
+ // mapboxVersion: {minor: number; major: number};
11
13
  };
12
14
 
15
+ // Mercator constants
16
+ const TILE_SIZE = 512;
17
+ const DEGREES_TO_RADIANS = Math.PI / 180;
18
+
13
19
  export function getDeckInstance({
14
20
  map,
15
21
  gl,
@@ -28,11 +34,13 @@ export function getDeckInstance({
28
34
 
29
35
  const deckProps: DeckProps = {
30
36
  useDevicePixels: true,
31
- _customRender: (reason: string) => {
37
+ _customRender: () => {
32
38
  map.triggerRepaint();
33
39
  // customRender may be subscribed by DeckGL React component to update child props
34
40
  // make sure it is still called
35
- customRender?.(reason);
41
+ // Hack - do not pass a redraw reason here to prevent the React component from clearing the context
42
+ // Rerender will be triggered by MapboxLayer's render()
43
+ customRender?.('');
36
44
  },
37
45
  // TODO: import these defaults from a single source of truth
38
46
  parameters: {
@@ -77,7 +85,7 @@ export function getDeckInstance({
77
85
  }
78
86
 
79
87
  (deckInstance.userData as UserData).mapboxLayers = new Set();
80
- (deckInstance.userData as UserData).mapboxVersion = getMapboxVersion(map);
88
+ // (deckInstance.userData as UserData).mapboxVersion = getMapboxVersion(map);
81
89
  map.__deck = deckInstance;
82
90
  map.on('render', () => {
83
91
  if (deckInstance.isInitialized) afterRender(deckInstance, map);
@@ -133,7 +141,16 @@ export function getViewState(map: Map): MapViewState & {
133
141
  };
134
142
  } {
135
143
  const {lng, lat} = map.getCenter();
136
- return {
144
+
145
+ const viewState: MapViewState & {
146
+ repeat: boolean;
147
+ padding: {
148
+ left: number;
149
+ right: number;
150
+ top: number;
151
+ bottom: number;
152
+ };
153
+ } = {
137
154
  // Longitude returned by getCenter can be outside of [-180, 180] when zooming near the anti meridian
138
155
  // https://github.com/visgl/deck.gl/issues/6894
139
156
  longitude: ((lng + 540) % 360) - 180,
@@ -144,49 +161,81 @@ export function getViewState(map: Map): MapViewState & {
144
161
  padding: map.getPadding(),
145
162
  repeat: map.getRenderWorldCopies()
146
163
  };
164
+
165
+ if (map.getTerrain?.()) {
166
+ // When the base map has terrain, we need to target the camera at the terrain surface
167
+ centerCameraOnTerrain(map, viewState);
168
+ }
169
+
170
+ return viewState;
147
171
  }
148
172
 
149
- function getMapboxVersion(map: Map): {minor: number; major: number} {
150
- // parse mapbox version string
151
- let major = 0;
152
- let minor = 0;
153
- // @ts-ignore (2339) undefined property
154
- const version: string = map.version;
155
- if (version) {
156
- [major, minor] = version.split('.').slice(0, 2).map(Number);
173
+ function centerCameraOnTerrain(map: Map, viewState: MapViewState) {
174
+ if (map.getFreeCameraOptions) {
175
+ // mapbox-gl v2
176
+ const {position} = map.getFreeCameraOptions();
177
+ if (!position || position.z === undefined) {
178
+ return;
179
+ }
180
+
181
+ // @ts-ignore transform is not typed
182
+ const height = map.transform.height;
183
+ const {longitude, latitude, pitch} = viewState;
184
+
185
+ // Convert mapbox mercator coordinate to deck common space
186
+ const cameraX = position.x * TILE_SIZE;
187
+ const cameraY = (1 - position.y) * TILE_SIZE;
188
+ const cameraZ = position.z * TILE_SIZE;
189
+
190
+ // Mapbox manipulates zoom in terrain mode, see discussion here: https://github.com/mapbox/mapbox-gl-js/issues/12040
191
+ const center = lngLatToWorld([longitude, latitude]);
192
+ const dx = cameraX - center[0];
193
+ const dy = cameraY - center[1];
194
+ const cameraToCenterDistanceGround = Math.sqrt(dx * dx + dy * dy);
195
+
196
+ const pitchRadians = pitch! * DEGREES_TO_RADIANS;
197
+ const altitudePixels = 1.5 * height;
198
+ const scale = (altitudePixels * Math.sin(pitchRadians)) / cameraToCenterDistanceGround;
199
+ viewState.zoom = Math.log2(scale);
200
+
201
+ const cameraZFromSurface = (altitudePixels * Math.cos(pitchRadians)) / scale;
202
+ const surfaceElevation = cameraZ - cameraZFromSurface;
203
+ viewState.position = [0, 0, surfaceElevation / unitsPerMeter(latitude)];
204
+ }
205
+ // @ts-ignore transform is not typed
206
+ else if (typeof map.transform.elevation === 'number') {
207
+ // maplibre-gl
208
+ // @ts-ignore transform is not typed
209
+ viewState.position = [0, 0, map.transform.elevation];
157
210
  }
158
- return {major, minor};
159
211
  }
160
212
 
213
+ // function getMapboxVersion(map: Map): {minor: number; major: number} {
214
+ // // parse mapbox version string
215
+ // let major = 0;
216
+ // let minor = 0;
217
+ // // @ts-ignore (2339) undefined property
218
+ // const version: string = map.version;
219
+ // if (version) {
220
+ // [major, minor] = version.split('.').slice(0, 2).map(Number);
221
+ // }
222
+ // return {major, minor};
223
+ // }
224
+
161
225
  function getViewport(deck: Deck, map: Map, useMapboxProjection = true): WebMercatorViewport {
162
- const {mapboxVersion} = deck.userData as UserData;
163
-
164
- return new WebMercatorViewport(
165
- Object.assign(
166
- {
167
- id: 'mapbox',
168
- x: 0,
169
- y: 0,
170
- width: deck.width,
171
- height: deck.height
172
- },
173
- getViewState(map),
174
- useMapboxProjection
175
- ? {
176
- // match mapbox's projection matrix
177
- // A change of near plane was made in 1.3.0
178
- // https://github.com/mapbox/mapbox-gl-js/pull/8502
179
- nearZMultiplier:
180
- (mapboxVersion.major === 1 && mapboxVersion.minor >= 3) || mapboxVersion.major >= 2
181
- ? 0.02
182
- : 1 / (deck.height || 1)
183
- }
184
- : {
185
- // use deck.gl's own default
186
- nearZMultiplier: 0.1
187
- }
188
- )
189
- );
226
+ return new WebMercatorViewport({
227
+ id: 'mapbox',
228
+ x: 0,
229
+ y: 0,
230
+ width: deck.width,
231
+ height: deck.height,
232
+ ...getViewState(map),
233
+ nearZMultiplier: useMapboxProjection
234
+ ? // match mapbox-gl@>=1.3.0's projection matrix
235
+ 0.02
236
+ : // use deck.gl's own default
237
+ 0.1
238
+ });
190
239
  }
191
240
 
192
241
  function afterRender(deck: Deck, map: Map): void {
@@ -1 +1 @@
1
- {"version":3,"file":"deck-utils.d.ts","sourceRoot":"","sources":["../src/deck-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAoD,MAAM,eAAe,CAAC;AACtF,OAAO,KAAK,EAAY,YAAY,EAAQ,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,WAAW,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,WAAW,CAAC;AASnC,wBAAgB,eAAe,CAAC,EAC9B,GAAG,EACH,EAAE,EACF,IAAI,EACL,EAAE;IACD,GAAG,EAAE,GAAG,GAAG;QAAC,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;KAAC,CAAC;IAClC,EAAE,EAAE,qBAAqB,CAAC;IAC1B,IAAI,CAAC,EAAE,IAAI,CAAC;CACb,GAAG,IAAI,CAkEP;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,IAAI,CAGlE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,IAAI,CAGrE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,IAAI,CAErE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,IAAI,CAqB7E;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,YAAY,GAAG;IACrD,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH,CAaA"}
1
+ {"version":3,"file":"deck-utils.d.ts","sourceRoot":"","sources":["../src/deck-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAoD,MAAM,eAAe,CAAC;AACtF,OAAO,KAAK,EAAY,YAAY,EAAQ,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,WAAW,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,WAAW,CAAC;AAenC,wBAAgB,eAAe,CAAC,EAC9B,GAAG,EACH,EAAE,EACF,IAAI,EACL,EAAE;IACD,GAAG,EAAE,GAAG,GAAG;QAAC,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;KAAC,CAAC;IAClC,EAAE,EAAE,qBAAqB,CAAC;IAC1B,IAAI,CAAC,EAAE,IAAI,CAAC;CACb,GAAG,IAAI,CAoEP;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,IAAI,CAGlE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,IAAI,CAGrE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,IAAI,CAErE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,IAAI,CAqB7E;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,YAAY,GAAG;IACrD,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH,CA6BA"}
@@ -0,0 +1,185 @@
1
+ import { Deck, WebMercatorViewport, MapView, _flatten as flatten } from '@deck.gl/core';
2
+ export function getDeckInstance({ map, gl, deck }) {
3
+ // Only create one deck instance per context
4
+ if (map.__deck) {
5
+ return map.__deck;
6
+ }
7
+ const customRender = deck?.props._customRender;
8
+ const deckProps = {
9
+ useDevicePixels: true,
10
+ _customRender: (reason) => {
11
+ map.triggerRepaint();
12
+ // customRender may be subscribed by DeckGL React component to update child props
13
+ // make sure it is still called
14
+ customRender?.(reason);
15
+ },
16
+ // TODO: import these defaults from a single source of truth
17
+ parameters: {
18
+ depthMask: true,
19
+ depthTest: true,
20
+ blend: true,
21
+ blendFunc: [gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA],
22
+ polygonOffsetFill: true,
23
+ depthFunc: gl.LEQUAL,
24
+ blendEquation: gl.FUNC_ADD
25
+ },
26
+ views: (deck && deck.props.views) || [new MapView({ id: 'mapbox' })]
27
+ };
28
+ if (!deck || deck.props.gl === gl) {
29
+ // deck is using the WebGLContext created by mapbox
30
+ // block deck from setting the canvas size
31
+ Object.assign(deckProps, {
32
+ gl,
33
+ width: null,
34
+ height: null,
35
+ touchAction: 'unset',
36
+ viewState: getViewState(map)
37
+ });
38
+ // If using the WebGLContext created by deck (React use case), we use deck's viewState to drive the map.
39
+ // Otherwise (pure JS use case), we use the map's viewState to drive deck.
40
+ map.on('move', () => onMapMove(deck, map));
41
+ }
42
+ if (deck) {
43
+ deck.setProps(deckProps);
44
+ deck.userData.isExternal = true;
45
+ }
46
+ else {
47
+ deck = new Deck(deckProps);
48
+ map.on('remove', () => {
49
+ deck.finalize();
50
+ map.__deck = null;
51
+ });
52
+ }
53
+ deck.userData.mapboxLayers = new Set();
54
+ deck.userData.mapboxVersion = getMapboxVersion(map);
55
+ map.__deck = deck;
56
+ map.on('render', () => {
57
+ // @ts-expect-error (2445) protected property
58
+ if (deck.layerManager)
59
+ afterRender(deck, map);
60
+ });
61
+ return deck;
62
+ }
63
+ export function addLayer(deck, layer) {
64
+ deck.userData.mapboxLayers.add(layer);
65
+ updateLayers(deck);
66
+ }
67
+ export function removeLayer(deck, layer) {
68
+ deck.userData.mapboxLayers.delete(layer);
69
+ updateLayers(deck);
70
+ }
71
+ export function updateLayer(deck, layer) {
72
+ updateLayers(deck);
73
+ }
74
+ export function drawLayer(deck, map, layer) {
75
+ let { currentViewport } = deck.userData;
76
+ if (!currentViewport) {
77
+ // This is the first layer drawn in this render cycle.
78
+ // Generate viewport from the current map state.
79
+ currentViewport = getViewport(deck, map, true);
80
+ deck.userData.currentViewport = currentViewport;
81
+ }
82
+ // @ts-expect-error (2445) protected property
83
+ if (!deck.layerManager) {
84
+ return;
85
+ }
86
+ deck._drawLayers('mapbox-repaint', {
87
+ viewports: [currentViewport],
88
+ layerFilter: ({ layer: deckLayer }) => layer.id === deckLayer.id,
89
+ clearCanvas: false
90
+ });
91
+ }
92
+ export function getViewState(map) {
93
+ const { lng, lat } = map.getCenter();
94
+ return {
95
+ // Longitude returned by getCenter can be outside of [-180, 180] when zooming near the anti meridian
96
+ // https://github.com/visgl/deck.gl/issues/6894
97
+ longitude: ((lng + 540) % 360) - 180,
98
+ latitude: lat,
99
+ zoom: map.getZoom(),
100
+ bearing: map.getBearing(),
101
+ pitch: map.getPitch(),
102
+ repeat: map.getRenderWorldCopies()
103
+ };
104
+ }
105
+ function getMapboxVersion(map) {
106
+ // parse mapbox version string
107
+ let major = 0;
108
+ let minor = 0;
109
+ // @ts-ignore (2339) undefined property
110
+ const version = map.version;
111
+ if (version) {
112
+ [major, minor] = version.split('.').slice(0, 2).map(Number);
113
+ }
114
+ return { major, minor };
115
+ }
116
+ function getViewport(deck, map, useMapboxProjection = true) {
117
+ const { mapboxVersion } = deck.userData;
118
+ return new WebMercatorViewport(Object.assign({
119
+ id: 'mapbox',
120
+ x: 0,
121
+ y: 0,
122
+ width: deck.width,
123
+ height: deck.height
124
+ }, getViewState(map), useMapboxProjection
125
+ ? {
126
+ // match mapbox's projection matrix
127
+ // A change of near plane was made in 1.3.0
128
+ // https://github.com/mapbox/mapbox-gl-js/pull/8502
129
+ nearZMultiplier: (mapboxVersion.major === 1 && mapboxVersion.minor >= 3) || mapboxVersion.major >= 2
130
+ ? 0.02
131
+ : 1 / (deck.height || 1)
132
+ }
133
+ : {
134
+ // use deck.gl's own default
135
+ nearZMultiplier: 0.1
136
+ }));
137
+ }
138
+ function afterRender(deck, map) {
139
+ const { mapboxLayers, isExternal } = deck.userData;
140
+ if (isExternal) {
141
+ // Draw non-Mapbox layers
142
+ const mapboxLayerIds = Array.from(mapboxLayers, layer => layer.id);
143
+ const deckLayers = flatten(deck.props.layers, Boolean);
144
+ const hasNonMapboxLayers = deckLayers.some(layer => layer && !mapboxLayerIds.includes(layer.id));
145
+ let viewports = deck.getViewports();
146
+ const mapboxViewportIdx = viewports.findIndex(vp => vp.id === 'mapbox');
147
+ const hasNonMapboxViews = viewports.length > 1 || mapboxViewportIdx < 0;
148
+ if (hasNonMapboxLayers || hasNonMapboxViews) {
149
+ if (mapboxViewportIdx >= 0) {
150
+ viewports = viewports.slice();
151
+ viewports[mapboxViewportIdx] = getViewport(deck, map, false);
152
+ }
153
+ deck._drawLayers('mapbox-repaint', {
154
+ viewports,
155
+ layerFilter: params => (!deck.props.layerFilter || deck.props.layerFilter(params)) &&
156
+ (params.viewport.id !== 'mapbox' || !mapboxLayerIds.includes(params.layer.id)),
157
+ clearCanvas: false
158
+ });
159
+ }
160
+ }
161
+ // End of render cycle, clear generated viewport
162
+ deck.userData.currentViewport = null;
163
+ }
164
+ function onMapMove(deck, map) {
165
+ deck.setProps({
166
+ viewState: getViewState(map)
167
+ });
168
+ // Camera changed, will trigger a map repaint right after this
169
+ // Clear any change flag triggered by setting viewState so that deck does not request
170
+ // a second repaint
171
+ deck.needsRedraw({ clearRedrawFlags: true });
172
+ }
173
+ function updateLayers(deck) {
174
+ if (deck.userData.isExternal) {
175
+ return;
176
+ }
177
+ const layers = [];
178
+ let layerIndex = 0;
179
+ deck.userData.mapboxLayers.forEach(deckLayer => {
180
+ const LayerType = deckLayer.props.type;
181
+ const layer = new LayerType(deckLayer.props, { _offset: layerIndex++ });
182
+ layers.push(layer);
183
+ });
184
+ deck.setProps({ layers });
185
+ }
package/typed/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { default as MapboxLayer } from './mapbox-layer';
2
+ export { default as MapboxOverlay } from './mapbox-overlay';
@@ -0,0 +1,37 @@
1
+ import { getDeckInstance, addLayer, removeLayer, updateLayer, drawLayer } from './deck-utils';
2
+ export default class MapboxLayer {
3
+ /* eslint-disable no-this-before-super */
4
+ constructor(props) {
5
+ if (!props.id) {
6
+ throw new Error('Layer must have an unique id');
7
+ }
8
+ this.id = props.id;
9
+ this.type = 'custom';
10
+ this.renderingMode = props.renderingMode || '3d';
11
+ this.map = null;
12
+ this.deck = null;
13
+ this.props = props;
14
+ }
15
+ /* Mapbox custom layer methods */
16
+ onAdd(map, gl) {
17
+ this.map = map;
18
+ this.deck = getDeckInstance({ map, gl, deck: this.props.deck });
19
+ addLayer(this.deck, this);
20
+ }
21
+ onRemove() {
22
+ if (this.deck) {
23
+ removeLayer(this.deck, this);
24
+ }
25
+ }
26
+ setProps(props) {
27
+ // id cannot be changed
28
+ Object.assign(this.props, props, { id: this.id });
29
+ // safe guard in case setProps is called before onAdd
30
+ if (this.deck) {
31
+ updateLayer(this.deck, this);
32
+ }
33
+ }
34
+ render() {
35
+ drawLayer(this.deck, this.map, this);
36
+ }
37
+ }
@@ -0,0 +1,139 @@
1
+ import { Deck, assert } from '@deck.gl/core';
2
+ import { getViewState } from './deck-utils';
3
+ /**
4
+ * Implements Mapbox [IControl](https://docs.mapbox.com/mapbox-gl-js/api/markers/#icontrol) interface
5
+ * Renders deck.gl layers over the base map and automatically synchronizes with the map's camera
6
+ */
7
+ export default class MapboxOverlay {
8
+ constructor(props) {
9
+ this._updateContainerSize = () => {
10
+ if (this._map && this._container) {
11
+ const { clientWidth, clientHeight } = this._map.getContainer();
12
+ Object.assign(this._container.style, {
13
+ width: `${clientWidth}px`,
14
+ height: `${clientHeight}px`
15
+ });
16
+ }
17
+ };
18
+ this._updateViewState = () => {
19
+ const deck = this._deck;
20
+ if (deck) {
21
+ // @ts-ignore (2345) map is always defined if deck is
22
+ deck.setProps({ viewState: getViewState(this._map) });
23
+ // Redraw immediately if view state has changed
24
+ deck.redraw();
25
+ }
26
+ };
27
+ this._handleMouseEvent = (event) => {
28
+ const deck = this._deck;
29
+ if (!deck) {
30
+ return;
31
+ }
32
+ const mockEvent = {
33
+ type: event.type,
34
+ offsetCenter: event.point,
35
+ srcEvent: event
36
+ };
37
+ switch (event.type) {
38
+ case 'click':
39
+ mockEvent.tapCount = 1;
40
+ // Hack: because we do not listen to pointer down, perform picking now
41
+ deck._onPointerDown(mockEvent);
42
+ deck._onEvent(mockEvent);
43
+ break;
44
+ case 'dblclick':
45
+ mockEvent.type = 'click';
46
+ mockEvent.tapCount = 2;
47
+ deck._onEvent(mockEvent);
48
+ break;
49
+ case 'mousemove':
50
+ mockEvent.type = 'pointermove';
51
+ deck._onPointerMove(mockEvent);
52
+ break;
53
+ case 'mouseout':
54
+ mockEvent.type = 'pointerleave';
55
+ deck._onPointerMove(mockEvent);
56
+ break;
57
+ default:
58
+ return;
59
+ }
60
+ };
61
+ this._props = { ...props };
62
+ }
63
+ /** Update (partial) props of the underlying Deck instance. */
64
+ setProps(props) {
65
+ Object.assign(this._props, props);
66
+ if ('viewState' in this._props) {
67
+ delete this._props.viewState;
68
+ }
69
+ if (this._deck) {
70
+ this._deck.setProps(this._props);
71
+ }
72
+ }
73
+ /** Called when the control is added to a map */
74
+ onAdd(map) {
75
+ this._map = map;
76
+ /* global document */
77
+ const container = document.createElement('div');
78
+ Object.assign(container.style, {
79
+ position: 'absolute',
80
+ left: 0,
81
+ top: 0,
82
+ pointerEvents: 'none'
83
+ });
84
+ this._container = container;
85
+ this._deck = new Deck({
86
+ ...this._props,
87
+ parent: container,
88
+ viewState: getViewState(map)
89
+ });
90
+ map.on('resize', this._updateContainerSize);
91
+ map.on('render', this._updateViewState);
92
+ map.on('mousemove', this._handleMouseEvent);
93
+ map.on('mouseout', this._handleMouseEvent);
94
+ map.on('click', this._handleMouseEvent);
95
+ map.on('dblclick', this._handleMouseEvent);
96
+ this._updateContainerSize();
97
+ return container;
98
+ }
99
+ /** Called when the control is removed from a map */
100
+ onRemove() {
101
+ const map = this._map;
102
+ if (map) {
103
+ map.off('resize', this._updateContainerSize);
104
+ map.off('render', this._updateViewState);
105
+ map.off('mousemove', this._handleMouseEvent);
106
+ map.off('mouseout', this._handleMouseEvent);
107
+ map.off('click', this._handleMouseEvent);
108
+ map.off('dblclick', this._handleMouseEvent);
109
+ }
110
+ this._deck?.finalize();
111
+ this._deck = undefined;
112
+ this._map = undefined;
113
+ this._container = undefined;
114
+ }
115
+ getDefaultPosition() {
116
+ return 'top-left';
117
+ }
118
+ /** Forwards the Deck.pickObject method */
119
+ pickObject(params) {
120
+ assert(this._deck);
121
+ return this._deck.pickObject(params);
122
+ }
123
+ /** Forwards the Deck.pickMultipleObjects method */
124
+ pickMultipleObjects(params) {
125
+ assert(this._deck);
126
+ return this._deck.pickMultipleObjects(params);
127
+ }
128
+ /** Forwards the Deck.pickObjects method */
129
+ pickObjects(params) {
130
+ assert(this._deck);
131
+ return this._deck.pickObjects(params);
132
+ }
133
+ /** Remove from map and releases all resources */
134
+ finalize() {
135
+ if (this._map) {
136
+ this._map.removeControl(this);
137
+ }
138
+ }
139
+ }