@deck.gl/google-maps 9.2.8 → 9.2.10

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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Use deck.gl as a custom Google Maps overlay",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
- "version": "9.2.8",
6
+ "version": "9.2.10",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -49,5 +49,5 @@
49
49
  "@luma.gl/core": "~9.2.6",
50
50
  "@luma.gl/webgl": "~9.2.6"
51
51
  },
52
- "gitHead": "3c54db674548a7a0d18c4d572689f455b3532441"
52
+ "gitHead": "7527990f1bac132b5ce65026a448c6c86a9268cb"
53
53
  }
@@ -9,13 +9,13 @@ import {
9
9
  createDeckInstance,
10
10
  destroyDeckInstance,
11
11
  getViewPropsFromOverlay,
12
- getViewPropsFromCoordinateTransformer
12
+ getViewPropsFromCoordinateTransformer,
13
+ POSITIONING_CONTAINER_ID
13
14
  } from './utils';
14
15
  import {Deck} from '@deck.gl/core';
15
16
 
16
17
  import type {DeckProps, MapViewState} from '@deck.gl/core';
17
18
  import type {Device} from '@luma.gl/core';
18
-
19
19
  const HIDE_ALL_LAYERS = () => false;
20
20
  const GL_STATE: GLParameters = {
21
21
  depthMask: true,
@@ -53,6 +53,7 @@ export default class GoogleMapsOverlay {
53
53
  private _map: google.maps.Map | null = null;
54
54
  private _deck: Deck | null = null;
55
55
  private _overlay: google.maps.WebGLOverlayView | google.maps.OverlayView | null = null;
56
+ private _positioningOverlay: google.maps.OverlayView | null = null;
56
57
 
57
58
  constructor(props: GoogleMapsOverlayProps) {
58
59
  this.setProps({...defaultProps, ...props});
@@ -72,6 +73,7 @@ export default class GoogleMapsOverlay {
72
73
  (this._overlay as google.maps.WebGLOverlayView).requestRedraw();
73
74
  }
74
75
  this._overlay?.setMap(null);
76
+ this._positioningOverlay?.setMap(null);
75
77
  this._map = null;
76
78
  }
77
79
  if (map) {
@@ -129,7 +131,6 @@ export default class GoogleMapsOverlay {
129
131
 
130
132
  /* Private API */
131
133
  _createOverlay(map: google.maps.Map) {
132
- const {interleaved} = this.props;
133
134
  const {VECTOR, UNINITIALIZED} = google.maps.RenderingType;
134
135
  const renderingType = map.getRenderingType();
135
136
  if (renderingType === UNINITIALIZED) {
@@ -137,26 +138,46 @@ export default class GoogleMapsOverlay {
137
138
  }
138
139
 
139
140
  const isVectorMap = renderingType === VECTOR && google.maps.WebGLOverlayView;
140
- const OverlayView = isVectorMap ? google.maps.WebGLOverlayView : google.maps.OverlayView;
141
- const overlay = new OverlayView();
142
-
143
- if (overlay instanceof google.maps.WebGLOverlayView) {
144
- if (interleaved) {
145
- overlay.onAdd = noop;
146
- overlay.onContextRestored = this._onContextRestored.bind(this);
147
- overlay.onDraw = this._onDrawVectorInterleaved.bind(this);
148
- } else {
149
- overlay.onAdd = this._onAdd.bind(this);
150
- overlay.onContextRestored = noop;
151
- overlay.onDraw = this._onDrawVectorOverlay.bind(this);
152
- }
153
- overlay.onContextLost = this._onContextLost.bind(this);
141
+ if (isVectorMap) {
142
+ this._createOverlayVector(map);
154
143
  } else {
155
- overlay.onAdd = this._onAdd.bind(this);
156
- overlay.draw = this._onDrawRaster.bind(this);
144
+ this._createOverlayRaster(map);
157
145
  }
158
- overlay.onRemove = this._onRemove.bind(this);
146
+ }
159
147
 
148
+ /**
149
+ * Create overlays for vector maps.
150
+ * Uses OverlayView for DOM positioning (correct z-index) and
151
+ * WebGLOverlayView for camera data (smooth animations).
152
+ * In interleaved mode, WebGLOverlayView also provides the shared GL context.
153
+ */
154
+ _createOverlayVector(map: google.maps.Map) {
155
+ const interleaved = this.props.interleaved ?? defaultProps.interleaved;
156
+ // Create positioning overlay for proper DOM placement
157
+ const positioningOverlay = new google.maps.OverlayView();
158
+ positioningOverlay.onAdd = this._onAddVectorOverlay.bind(this);
159
+ positioningOverlay.draw = this._updateContainerSize.bind(this);
160
+ positioningOverlay.onRemove = this._onRemove.bind(this);
161
+ this._positioningOverlay = positioningOverlay;
162
+ this._positioningOverlay.setMap(map);
163
+
164
+ // Create WebGL overlay for camera data (and GL context if interleaved)
165
+ const overlay = new google.maps.WebGLOverlayView();
166
+ overlay.onAdd = noop;
167
+ overlay.onContextRestored = interleaved ? this._onContextRestored.bind(this) : noop;
168
+ overlay.onDraw = this._onDrawVector.bind(this);
169
+ overlay.onContextLost = interleaved ? this._onContextLost.bind(this) : noop;
170
+ overlay.onRemove = interleaved ? this._onRemove.bind(this) : noop;
171
+ this._overlay = overlay;
172
+ this._overlay.setMap(map);
173
+ }
174
+
175
+ _createOverlayRaster(map: google.maps.Map) {
176
+ // Raster maps use standard OverlayView
177
+ const overlay = new google.maps.OverlayView();
178
+ overlay.onAdd = this._onAdd.bind(this);
179
+ overlay.draw = this._onDrawRaster.bind(this);
180
+ overlay.onRemove = this._onRemove.bind(this);
160
181
  this._overlay = overlay;
161
182
  this._overlay.setMap(map);
162
183
  }
@@ -166,6 +187,45 @@ export default class GoogleMapsOverlay {
166
187
  this._deck = createDeckInstance(this._map, this._overlay, this._deck, this.props);
167
188
  }
168
189
 
190
+ _onAddVectorOverlay() {
191
+ // For non-interleaved vector maps, create a positioning container
192
+ // that Google Maps will place correctly in the DOM with proper z-index
193
+ const overlay = this._positioningOverlay as google.maps.OverlayView;
194
+ const panes = overlay.getPanes();
195
+ if (panes) {
196
+ const container = document.createElement('div');
197
+ container.id = POSITIONING_CONTAINER_ID;
198
+ container.style.position = 'absolute';
199
+ panes.overlayLayer.appendChild(container);
200
+ }
201
+
202
+ // @ts-ignore (TS2345) map is defined at this stage
203
+ // Pass the positioning overlay for deck canvas creation (not WebGL overlay)
204
+ this._deck = createDeckInstance(this._map, overlay, this._deck, this.props);
205
+ }
206
+
207
+ _updateContainerSize() {
208
+ // Update positioning container size and position to match map
209
+ if (!this._map) return;
210
+
211
+ const container = this._map
212
+ .getDiv()
213
+ .querySelector(`#${POSITIONING_CONTAINER_ID}`) as HTMLElement;
214
+ if (!container) return;
215
+
216
+ const mapContainer = this._map.getDiv().firstChild as HTMLElement;
217
+ if (!mapContainer) return;
218
+
219
+ const width = mapContainer.offsetWidth;
220
+ const height = mapContainer.offsetHeight;
221
+
222
+ container.style.width = `${width}px`;
223
+ container.style.height = `${height}px`;
224
+ // Position at top-left (overlayLayer uses centered coords, so offset by half)
225
+ container.style.left = `${-width / 2}px`;
226
+ container.style.top = `${-height / 2}px`;
227
+ }
228
+
169
229
  _onContextRestored({gl}) {
170
230
  if (!this._map || !this._overlay) {
171
231
  return;
@@ -240,23 +300,21 @@ export default class GoogleMapsOverlay {
240
300
  deck.redraw();
241
301
  }
242
302
 
243
- // Vector code path
244
- _onDrawVectorInterleaved({gl, transformer}) {
303
+ _onDrawVector({gl, transformer}) {
245
304
  if (!this._deck || !this._map) {
246
305
  return;
247
306
  }
248
307
 
249
308
  const deck = this._deck;
309
+ const {interleaved} = this.props;
250
310
 
251
311
  deck.setProps({
252
312
  ...getViewPropsFromCoordinateTransformer(this._map, transformer),
253
-
254
313
  // Using external gl context - do not set css size
255
- width: null,
256
- height: null
314
+ ...(interleaved && {width: null, height: null})
257
315
  });
258
316
 
259
- if (deck.isInitialized) {
317
+ if (interleaved && deck.isInitialized) {
260
318
  // @ts-expect-error
261
319
  const device: Device = deck.device;
262
320
 
@@ -287,19 +345,8 @@ export default class GoogleMapsOverlay {
287
345
  });
288
346
  });
289
347
  }
348
+ } else if (!interleaved) {
349
+ deck.redraw();
290
350
  }
291
351
  }
292
-
293
- _onDrawVectorOverlay({transformer}) {
294
- if (!this._deck || !this._map) {
295
- return;
296
- }
297
-
298
- const deck = this._deck;
299
-
300
- deck.setProps({
301
- ...getViewPropsFromCoordinateTransformer(this._map, transformer)
302
- });
303
- deck.redraw();
304
- }
305
352
  }
package/src/utils.ts CHANGED
@@ -6,6 +6,7 @@
6
6
  import {Deck, MapView} from '@deck.gl/core';
7
7
  import {Matrix4, Vector2} from '@math.gl/core';
8
8
  import type {MjolnirGestureEvent, MjolnirPointerEvent} from 'mjolnir.js';
9
+ export const POSITIONING_CONTAINER_ID = 'deck-gl-google-maps-container';
9
10
 
10
11
  // https://en.wikipedia.org/wiki/Web_Mercator_projection#Formulas
11
12
  const MAX_LATITUDE = 85.05113;
@@ -45,7 +46,8 @@ export function createDeckInstance(
45
46
 
46
47
  const newDeck = new Deck({
47
48
  ...props,
48
- useDevicePixels: props.interleaved ? true : props.useDevicePixels,
49
+ // Default to true for high-DPI displays, but allow user override
50
+ useDevicePixels: props.useDevicePixels ?? true,
49
51
  style: props.interleaved ? null : {pointerEvents: 'none'},
50
52
  parent: getContainer(overlay, props.style),
51
53
  views: new MapView({repeat: true}),
@@ -80,12 +82,17 @@ function getContainer(
80
82
  container.style.position = 'absolute';
81
83
  Object.assign(container.style, style);
82
84
 
83
- // The DOM structure has a different structure depending on whether
84
- // the Google map is rendered as vector or raster
85
- if ('getPanes' in overlay) {
85
+ const googleMapsContainer = (overlay.getMap() as google.maps.Map).getDiv();
86
+
87
+ // Check if there's a pre-created positioning container (for vector maps)
88
+ const positioningContainer = googleMapsContainer.querySelector(`#${POSITIONING_CONTAINER_ID}`);
89
+
90
+ if (positioningContainer) {
91
+ // Vector maps (both interleaved and non-interleaved): Use positioning container
92
+ positioningContainer.appendChild(container);
93
+ } else if ('getPanes' in overlay) {
94
+ // Raster maps: Append to overlayLayer pane
86
95
  overlay.getPanes()?.overlayLayer.appendChild(container);
87
- } else {
88
- overlay.getMap()?.getDiv().appendChild(container);
89
96
  }
90
97
  return container;
91
98
  }