@deck.gl/maplibre 9.4.0-beta.1
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/LICENSE +19 -0
- package/README.md +5 -0
- package/dist/compatibility.d.ts +16 -0
- package/dist/compatibility.d.ts.map +1 -0
- package/dist/compatibility.js +42 -0
- package/dist/compatibility.js.map +1 -0
- package/dist/deck-utils.d.ts +24 -0
- package/dist/deck-utils.d.ts.map +1 -0
- package/dist/deck-utils.js +238 -0
- package/dist/deck-utils.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/layer-group.d.ts +18 -0
- package/dist/layer-group.d.ts.map +1 -0
- package/dist/layer-group.js +33 -0
- package/dist/layer-group.js.map +1 -0
- package/dist/layer-utils.d.ts +7 -0
- package/dist/layer-utils.d.ts.map +1 -0
- package/dist/layer-utils.js +10 -0
- package/dist/layer-utils.js.map +1 -0
- package/dist/overlay.d.ts +51 -0
- package/dist/overlay.d.ts.map +1 -0
- package/dist/overlay.js +296 -0
- package/dist/overlay.js.map +1 -0
- package/dist/resolve-layer-groups.d.ts +4 -0
- package/dist/resolve-layer-groups.d.ts.map +1 -0
- package/dist/resolve-layer-groups.js +65 -0
- package/dist/resolve-layer-groups.js.map +1 -0
- package/package.json +49 -0
- package/src/compatibility.ts +58 -0
- package/src/deck-utils.ts +309 -0
- package/src/index.ts +6 -0
- package/src/layer-group.ts +62 -0
- package/src/layer-utils.ts +17 -0
- package/src/overlay.ts +388 -0
- package/src/resolve-layer-groups.ts +84 -0
package/src/overlay.ts
ADDED
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
// deck.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import {Deck, assert} from '@deck.gl/core';
|
|
6
|
+
import {
|
|
7
|
+
createMapLibreInterleavedDeck,
|
|
8
|
+
getMapLibreDefaultParameters,
|
|
9
|
+
getMapLibreDefaultView,
|
|
10
|
+
getMapLibreViewState,
|
|
11
|
+
MAPLIBRE_VIEW_ID,
|
|
12
|
+
removeMapLibreDeckInstance
|
|
13
|
+
} from './deck-utils';
|
|
14
|
+
import {getMapLibreProjection} from './compatibility';
|
|
15
|
+
import {resolveMapLibreLayerGroups} from './resolve-layer-groups';
|
|
16
|
+
|
|
17
|
+
import type {DeckProps} from '@deck.gl/core';
|
|
18
|
+
import type {MjolnirGestureEvent, MjolnirPointerEvent} from 'mjolnir.js';
|
|
19
|
+
import type {ControlPosition, IControl, Map as MapLibreMap} from 'maplibre-gl';
|
|
20
|
+
|
|
21
|
+
type MapLibreInputEvent = {
|
|
22
|
+
type: string;
|
|
23
|
+
originalEvent?: Event;
|
|
24
|
+
point?: {x: number; y: number};
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/** Properties for MapLibreOverlay. */
|
|
28
|
+
export type MapLibreOverlayProps = Omit<
|
|
29
|
+
DeckProps,
|
|
30
|
+
| 'width'
|
|
31
|
+
| 'height'
|
|
32
|
+
| 'gl'
|
|
33
|
+
| 'parent'
|
|
34
|
+
| 'canvas'
|
|
35
|
+
| '_customRender'
|
|
36
|
+
| 'viewState'
|
|
37
|
+
| 'initialViewState'
|
|
38
|
+
| 'controller'
|
|
39
|
+
> & {
|
|
40
|
+
/**
|
|
41
|
+
* If true, deck.gl layers are inserted into MapLibre's layer stack and share its WebGL2 context.
|
|
42
|
+
* @default false
|
|
43
|
+
*/
|
|
44
|
+
interleaved?: boolean;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/** Renders deck.gl layers over a MapLibre map and synchronizes with its camera. */
|
|
48
|
+
export default class MapLibreOverlay implements IControl {
|
|
49
|
+
private _props: MapLibreOverlayProps;
|
|
50
|
+
private _deck?: Deck<any>;
|
|
51
|
+
private _map?: MapLibreMap;
|
|
52
|
+
private _container?: HTMLDivElement;
|
|
53
|
+
private readonly _interleaved: boolean;
|
|
54
|
+
|
|
55
|
+
private _lastMouseDownPoint?: {x: number; y: number; clientX: number; clientY: number};
|
|
56
|
+
|
|
57
|
+
/** Creates a MapLibre overlay. */
|
|
58
|
+
constructor(props: MapLibreOverlayProps) {
|
|
59
|
+
const {interleaved = false} = props;
|
|
60
|
+
this._interleaved = interleaved;
|
|
61
|
+
this._props = this._filterProps(props);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private _filterProps(props: MapLibreOverlayProps): MapLibreOverlayProps {
|
|
65
|
+
const {interleaved: _, useDevicePixels, device, ...deckProps} = props;
|
|
66
|
+
if (!this._interleaved) {
|
|
67
|
+
if (useDevicePixels !== undefined) {
|
|
68
|
+
Object.assign(deckProps, {useDevicePixels});
|
|
69
|
+
}
|
|
70
|
+
if (device !== undefined) {
|
|
71
|
+
Object.assign(deckProps, {device});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return deckProps as MapLibreOverlayProps;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Updates partial properties of the underlying Deck instance. */
|
|
78
|
+
setProps(props: MapLibreOverlayProps): void {
|
|
79
|
+
if (this._interleaved && props.layers) {
|
|
80
|
+
resolveMapLibreLayerGroups(this._map, this._props.layers, props.layers);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
Object.assign(this._props, this._filterProps(props));
|
|
84
|
+
|
|
85
|
+
if (this._deck && this._map) {
|
|
86
|
+
this._deck.setProps({
|
|
87
|
+
...this._props,
|
|
88
|
+
views: this._getViews(this._map),
|
|
89
|
+
parameters: {
|
|
90
|
+
...getMapLibreDefaultParameters(this._map, this._interleaved),
|
|
91
|
+
...this._props.parameters
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Called when the control is added to a map. */
|
|
98
|
+
onAdd(map: MapLibreMap): HTMLDivElement {
|
|
99
|
+
this._map = map;
|
|
100
|
+
try {
|
|
101
|
+
return this._interleaved ? this._onAddInterleaved(map) : this._onAddOverlaid(map);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
if (this._deck) {
|
|
104
|
+
if (this._interleaved) {
|
|
105
|
+
this._onRemoveInterleaved(map);
|
|
106
|
+
} else {
|
|
107
|
+
this._onRemoveOverlaid(map);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
this._deck = undefined;
|
|
111
|
+
this._map = undefined;
|
|
112
|
+
this._container = undefined;
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Called when the control is removed from a map. */
|
|
118
|
+
onRemove(_map: MapLibreMap): void {
|
|
119
|
+
const map = this._map;
|
|
120
|
+
|
|
121
|
+
if (map) {
|
|
122
|
+
if (this._interleaved) {
|
|
123
|
+
this._onRemoveInterleaved(map);
|
|
124
|
+
} else {
|
|
125
|
+
this._onRemoveOverlaid(map);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
this._deck = undefined;
|
|
130
|
+
this._map = undefined;
|
|
131
|
+
this._container = undefined;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Default control position. */
|
|
135
|
+
getDefaultPosition(): ControlPosition {
|
|
136
|
+
return 'top-left';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Forwards to Deck.pickObject. */
|
|
140
|
+
pickObject(params: Parameters<Deck['pickObject']>[0]): ReturnType<Deck['pickObject']> {
|
|
141
|
+
assert(this._deck);
|
|
142
|
+
return this._deck.pickObject(params);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Forwards to Deck.pickMultipleObjects. */
|
|
146
|
+
pickMultipleObjects(
|
|
147
|
+
params: Parameters<Deck['pickMultipleObjects']>[0]
|
|
148
|
+
): ReturnType<Deck['pickMultipleObjects']> {
|
|
149
|
+
assert(this._deck);
|
|
150
|
+
return this._deck.pickMultipleObjects(params);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Forwards to Deck.pickObjects. */
|
|
154
|
+
pickObjects(params: Parameters<Deck['pickObjects']>[0]): ReturnType<Deck['pickObjects']> {
|
|
155
|
+
assert(this._deck);
|
|
156
|
+
return this._deck.pickObjects(params);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** Removes the control from its map and releases resources. */
|
|
160
|
+
finalize(): void {
|
|
161
|
+
this._map?.removeControl(this);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Returns the basemap canvas in interleaved mode and Deck's canvas otherwise. */
|
|
165
|
+
getCanvas(): HTMLCanvasElement | null {
|
|
166
|
+
if (!this._map) {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
return this._interleaved ? this._map.getCanvas() : this._deck!.getCanvas();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private _onAddOverlaid(map: MapLibreMap): HTMLDivElement {
|
|
173
|
+
const container = document.createElement('div');
|
|
174
|
+
Object.assign(container.style, {
|
|
175
|
+
position: 'absolute',
|
|
176
|
+
left: 0,
|
|
177
|
+
top: 0,
|
|
178
|
+
textAlign: 'initial',
|
|
179
|
+
pointerEvents: 'none'
|
|
180
|
+
});
|
|
181
|
+
this._container = container;
|
|
182
|
+
|
|
183
|
+
this._deck = new Deck<any>({
|
|
184
|
+
...this._props,
|
|
185
|
+
parent: container,
|
|
186
|
+
deviceProps: {
|
|
187
|
+
...this._props.deviceProps,
|
|
188
|
+
createCanvasContext: {
|
|
189
|
+
...(typeof this._props.deviceProps?.createCanvasContext === 'object'
|
|
190
|
+
? this._props.deviceProps.createCanvasContext
|
|
191
|
+
: undefined),
|
|
192
|
+
pixelSizeSource: 'css-dpr'
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
parameters: {
|
|
196
|
+
...getMapLibreDefaultParameters(map, false),
|
|
197
|
+
...this._props.parameters
|
|
198
|
+
},
|
|
199
|
+
views: this._getViews(map),
|
|
200
|
+
viewState: getMapLibreViewState(map)
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
map.on('resize', this._updateContainerSize);
|
|
204
|
+
map.on('render', this._updateViewState);
|
|
205
|
+
map.on('mousedown', this._handleMouseEvent);
|
|
206
|
+
map.on('dragstart', this._handleMouseEvent);
|
|
207
|
+
map.on('drag', this._handleMouseEvent);
|
|
208
|
+
map.on('dragend', this._handleMouseEvent);
|
|
209
|
+
map.on('mousemove', this._handleMouseEvent);
|
|
210
|
+
map.on('mouseout', this._handleMouseEvent);
|
|
211
|
+
map.on('click', this._handleMouseEvent);
|
|
212
|
+
map.on('dblclick', this._handleMouseEvent);
|
|
213
|
+
|
|
214
|
+
this._updateContainerSize();
|
|
215
|
+
return container;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
private _onAddInterleaved(map: MapLibreMap): HTMLDivElement {
|
|
219
|
+
this._deck = createMapLibreInterleavedDeck(map, {
|
|
220
|
+
...this._props,
|
|
221
|
+
views: this._getViews(map),
|
|
222
|
+
parameters: {
|
|
223
|
+
...getMapLibreDefaultParameters(map, true),
|
|
224
|
+
...this._props.parameters
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
map.on('styledata', this._handleStyleChange);
|
|
229
|
+
resolveMapLibreLayerGroups(map, [], this._props.layers);
|
|
230
|
+
|
|
231
|
+
return document.createElement('div');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private _onRemoveOverlaid(map: MapLibreMap): void {
|
|
235
|
+
map.off('resize', this._updateContainerSize);
|
|
236
|
+
map.off('render', this._updateViewState);
|
|
237
|
+
map.off('mousedown', this._handleMouseEvent);
|
|
238
|
+
map.off('dragstart', this._handleMouseEvent);
|
|
239
|
+
map.off('drag', this._handleMouseEvent);
|
|
240
|
+
map.off('dragend', this._handleMouseEvent);
|
|
241
|
+
map.off('mousemove', this._handleMouseEvent);
|
|
242
|
+
map.off('mouseout', this._handleMouseEvent);
|
|
243
|
+
map.off('click', this._handleMouseEvent);
|
|
244
|
+
map.off('dblclick', this._handleMouseEvent);
|
|
245
|
+
this._deck?.finalize();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private _onRemoveInterleaved(map: MapLibreMap): void {
|
|
249
|
+
map.off('styledata', this._handleStyleChange);
|
|
250
|
+
try {
|
|
251
|
+
resolveMapLibreLayerGroups(map, this._props.layers, []);
|
|
252
|
+
} finally {
|
|
253
|
+
removeMapLibreDeckInstance(map);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
private _handleStyleChange = () => {
|
|
258
|
+
resolveMapLibreLayerGroups(this._map, this._props.layers, this._props.layers);
|
|
259
|
+
if (!this._map) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (getMapLibreProjection(this._map)) {
|
|
264
|
+
this._deck?.setProps({views: this._getViews(this._map)});
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
private _updateContainerSize = () => {
|
|
269
|
+
if (this._map && this._container) {
|
|
270
|
+
const {clientWidth, clientHeight} = this._map.getContainer();
|
|
271
|
+
Object.assign(this._container.style, {
|
|
272
|
+
width: `${clientWidth}px`,
|
|
273
|
+
height: `${clientHeight}px`
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
private _getViews(map: MapLibreMap): any {
|
|
279
|
+
if (!this._props.views) {
|
|
280
|
+
return getMapLibreDefaultView(map);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const views = Array.isArray(this._props.views) ? this._props.views : [this._props.views];
|
|
284
|
+
const hasMapLibreView = views.some((view: any) => view.id === MAPLIBRE_VIEW_ID);
|
|
285
|
+
if (hasMapLibreView) {
|
|
286
|
+
return this._props.views;
|
|
287
|
+
}
|
|
288
|
+
return [getMapLibreDefaultView(map), ...views];
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
private _updateViewState = () => {
|
|
292
|
+
const deck = this._deck;
|
|
293
|
+
const map = this._map;
|
|
294
|
+
if (deck && map) {
|
|
295
|
+
deck.setProps({
|
|
296
|
+
views: this._getViews(map),
|
|
297
|
+
viewState: getMapLibreViewState(map)
|
|
298
|
+
});
|
|
299
|
+
if (deck.isInitialized) {
|
|
300
|
+
deck.redraw();
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
// eslint-disable-next-line complexity
|
|
306
|
+
private _handleMouseEvent = (event: MapLibreInputEvent) => {
|
|
307
|
+
const deck = this._deck;
|
|
308
|
+
if (!deck || !deck.isInitialized) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const mockEvent: {
|
|
313
|
+
type: string;
|
|
314
|
+
deltaX?: number;
|
|
315
|
+
deltaY?: number;
|
|
316
|
+
offsetCenter: {x: number; y: number};
|
|
317
|
+
srcEvent: MapLibreInputEvent;
|
|
318
|
+
tapCount?: number;
|
|
319
|
+
} = {
|
|
320
|
+
type: event.type,
|
|
321
|
+
offsetCenter: event.point || {x: 0, y: 0},
|
|
322
|
+
srcEvent: event
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
const lastDown = this._lastMouseDownPoint;
|
|
326
|
+
if (!event.point && lastDown && event.originalEvent instanceof MouseEvent) {
|
|
327
|
+
mockEvent.deltaX = event.originalEvent.clientX - lastDown.clientX;
|
|
328
|
+
mockEvent.deltaY = event.originalEvent.clientY - lastDown.clientY;
|
|
329
|
+
mockEvent.offsetCenter = {
|
|
330
|
+
x: lastDown.x + mockEvent.deltaX,
|
|
331
|
+
y: lastDown.y + mockEvent.deltaY
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
switch (mockEvent.type) {
|
|
336
|
+
case 'mousedown':
|
|
337
|
+
deck._onPointerDown(mockEvent as unknown as MjolnirPointerEvent);
|
|
338
|
+
if (!(event.originalEvent instanceof MouseEvent)) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
this._lastMouseDownPoint = {
|
|
342
|
+
...mockEvent.offsetCenter,
|
|
343
|
+
clientX: event.originalEvent.clientX,
|
|
344
|
+
clientY: event.originalEvent.clientY
|
|
345
|
+
};
|
|
346
|
+
break;
|
|
347
|
+
|
|
348
|
+
case 'dragstart':
|
|
349
|
+
mockEvent.type = 'panstart';
|
|
350
|
+
deck._onEvent(mockEvent as unknown as MjolnirGestureEvent);
|
|
351
|
+
break;
|
|
352
|
+
|
|
353
|
+
case 'drag':
|
|
354
|
+
mockEvent.type = 'panmove';
|
|
355
|
+
deck._onEvent(mockEvent as unknown as MjolnirGestureEvent);
|
|
356
|
+
break;
|
|
357
|
+
|
|
358
|
+
case 'dragend':
|
|
359
|
+
mockEvent.type = 'panend';
|
|
360
|
+
deck._onEvent(mockEvent as unknown as MjolnirGestureEvent);
|
|
361
|
+
break;
|
|
362
|
+
|
|
363
|
+
case 'click':
|
|
364
|
+
mockEvent.tapCount = 1;
|
|
365
|
+
deck._onEvent(mockEvent as unknown as MjolnirGestureEvent);
|
|
366
|
+
break;
|
|
367
|
+
|
|
368
|
+
case 'dblclick':
|
|
369
|
+
mockEvent.type = 'click';
|
|
370
|
+
mockEvent.tapCount = 2;
|
|
371
|
+
deck._onEvent(mockEvent as unknown as MjolnirGestureEvent);
|
|
372
|
+
break;
|
|
373
|
+
|
|
374
|
+
case 'mousemove':
|
|
375
|
+
mockEvent.type = 'pointermove';
|
|
376
|
+
deck._onPointerMove(mockEvent as unknown as MjolnirPointerEvent);
|
|
377
|
+
break;
|
|
378
|
+
|
|
379
|
+
case 'mouseout':
|
|
380
|
+
mockEvent.type = 'pointerleave';
|
|
381
|
+
deck._onPointerMove(mockEvent as unknown as MjolnirPointerEvent);
|
|
382
|
+
break;
|
|
383
|
+
|
|
384
|
+
default:
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// deck.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import {_flatten as flatten} from '@deck.gl/core';
|
|
6
|
+
|
|
7
|
+
import MapLibreLayerGroup from './layer-group';
|
|
8
|
+
import {getMapLibreLayerGroupId} from './layer-utils';
|
|
9
|
+
|
|
10
|
+
import type {Layer, LayersList} from '@deck.gl/core';
|
|
11
|
+
import type {Map as MapLibreMap} from 'maplibre-gl';
|
|
12
|
+
import type {MapLibreLayerProps} from './layer-utils';
|
|
13
|
+
|
|
14
|
+
const LAYER_GROUPS = new WeakMap<MapLibreMap, Map<string, MapLibreLayerGroup>>();
|
|
15
|
+
|
|
16
|
+
// eslint-disable-next-line complexity, max-statements
|
|
17
|
+
export function resolveMapLibreLayerGroups(
|
|
18
|
+
map?: MapLibreMap,
|
|
19
|
+
oldLayers?: LayersList,
|
|
20
|
+
newLayers?: LayersList
|
|
21
|
+
): void {
|
|
22
|
+
if (!map || !map.isStyleLoaded()) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let layerGroups = LAYER_GROUPS.get(map);
|
|
27
|
+
if (!layerGroups) {
|
|
28
|
+
layerGroups = new Map();
|
|
29
|
+
LAYER_GROUPS.set(map, layerGroups);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const layers = flatten(newLayers, Boolean) as Layer<MapLibreLayerProps>[];
|
|
33
|
+
const newLayerGroupIds = new Set(layers.map(getMapLibreLayerGroupId));
|
|
34
|
+
|
|
35
|
+
if (oldLayers !== newLayers) {
|
|
36
|
+
const previousLayers = flatten(oldLayers, Boolean) as Layer<MapLibreLayerProps>[];
|
|
37
|
+
const previousLayerGroupIds = new Set(previousLayers.map(getMapLibreLayerGroupId));
|
|
38
|
+
for (const groupId of previousLayerGroupIds) {
|
|
39
|
+
if (!newLayerGroupIds.has(groupId) && layerGroups.has(groupId)) {
|
|
40
|
+
if (map.getLayer(groupId)) {
|
|
41
|
+
map.removeLayer(groupId);
|
|
42
|
+
}
|
|
43
|
+
layerGroups.delete(groupId);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
for (const layer of layers) {
|
|
49
|
+
const groupId = getMapLibreLayerGroupId(layer);
|
|
50
|
+
if (layerGroups.has(groupId)) {
|
|
51
|
+
if (!map.getLayer(groupId)) {
|
|
52
|
+
map.addLayer(layerGroups.get(groupId)!, layer.props.beforeId);
|
|
53
|
+
}
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (map.getLayer(groupId)) {
|
|
58
|
+
throw new Error(`MapLibre style already contains a non-deck layer with id ${groupId}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const group = new MapLibreLayerGroup({
|
|
62
|
+
id: groupId,
|
|
63
|
+
beforeId: layer.props.beforeId
|
|
64
|
+
});
|
|
65
|
+
layerGroups.set(groupId, group);
|
|
66
|
+
map.addLayer(group, layer.props.beforeId);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
for (const groupId of newLayerGroupIds) {
|
|
70
|
+
const group = layerGroups.get(groupId)!;
|
|
71
|
+
const mapLayers = map.getLayersOrder();
|
|
72
|
+
const expectedGroupIndex = group.beforeId
|
|
73
|
+
? mapLayers.indexOf(group.beforeId)
|
|
74
|
+
: mapLayers.length;
|
|
75
|
+
if (expectedGroupIndex < 0) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const currentGroupIndex = mapLayers.indexOf(groupId);
|
|
80
|
+
if (currentGroupIndex !== expectedGroupIndex - 1) {
|
|
81
|
+
map.moveLayer(groupId, group.beforeId);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|