@orbat-mapper/tactical-draw-adapter-maplibre 0.5.0 → 0.7.0
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/dist/index.d.mts +57 -1
- package/dist/index.mjs +122 -28
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -39,7 +39,11 @@ declare class PinResources {
|
|
|
39
39
|
private invalidateDepth;
|
|
40
40
|
private restore;
|
|
41
41
|
constructor(map: Map$1);
|
|
42
|
-
|
|
42
|
+
/**
|
|
43
|
+
* `pixelRatio` is the device pixels per CSS pixel the atlas is rasterized
|
|
44
|
+
* at; it is part of the roster key, so a change rebuilds the atlas.
|
|
45
|
+
*/
|
|
46
|
+
setRoster(pins: readonly PinRender[], pixelRatio?: number): void;
|
|
43
47
|
load(gl: WebGL2RenderingContext): Promise<PinResourceSnapshot | undefined>;
|
|
44
48
|
dispose(): void;
|
|
45
49
|
}
|
|
@@ -143,6 +147,13 @@ interface MapLibreLayerHandle {
|
|
|
143
147
|
sourceId: string;
|
|
144
148
|
/** MapLibre layer ids created for this logical layer (fill, line, circle, symbol) */
|
|
145
149
|
mlLayerIds: string[];
|
|
150
|
+
/**
|
|
151
|
+
* Anchor for overlay-band bundle layers while terrain is active — this
|
|
152
|
+
* handle's own `-circle` layer (ADR-0057). Stored explicitly rather than
|
|
153
|
+
* derived from `mlLayerIds` by position/suffix so the terrain-banding code
|
|
154
|
+
* doesn't depend on `createLayer`'s layer-creation order.
|
|
155
|
+
*/
|
|
156
|
+
overlayAnchorId: string;
|
|
146
157
|
groupBundles: Map<string, MapLibreGroupBundle>;
|
|
147
158
|
groupOrder: string[];
|
|
148
159
|
nextGroupBundleId: number;
|
|
@@ -155,6 +166,8 @@ interface MapLibreLayerHandle {
|
|
|
155
166
|
* skip calling it at all rather than pay for that every drag frame.
|
|
156
167
|
*/
|
|
157
168
|
lastPinBatch?: readonly PinRender[];
|
|
169
|
+
/** The pixel ratio passed alongside `lastPinBatch`. */
|
|
170
|
+
lastPinPixelRatio?: number;
|
|
158
171
|
}
|
|
159
172
|
type PaintChannel = "fill" | "fill-pattern" | "line" | "circle" | "icon" | "text";
|
|
160
173
|
interface MapLibreGroupBundle {
|
|
@@ -214,13 +227,41 @@ interface MapLibreAdapterOptions {
|
|
|
214
227
|
* the refit until the animation ends.
|
|
215
228
|
*/
|
|
216
229
|
viewChangeMode?: "continuous" | "settle";
|
|
230
|
+
/**
|
|
231
|
+
* While MapLibre terrain is active, paint fill/line layers in one band below
|
|
232
|
+
* circle/icon/text/pin layers so terrain draping stays in few passes
|
|
233
|
+
* (ADR-0057). `false` keeps exact per-graphic paint order under terrain, at
|
|
234
|
+
* one draping pass per graphic. @default true
|
|
235
|
+
*/
|
|
236
|
+
terrainBanding?: boolean;
|
|
237
|
+
/**
|
|
238
|
+
* Device pixels per CSS pixel at which pin symbols are rasterized into their
|
|
239
|
+
* texture atlas. Defaults to the map's pixel ratio capped at 2, which bounds
|
|
240
|
+
* texture memory on dense screens. Set it (e.g. to the map's `pixelRatio`)
|
|
241
|
+
* for offscreen renders above 2× so pins stay as sharp as the output.
|
|
242
|
+
*/
|
|
243
|
+
pinPixelRatio?: number;
|
|
217
244
|
}
|
|
218
245
|
declare class MapLibreAdapter extends BaseMapAdapter<MapLibreLayerHandle, MapLibreEventToken, MapLibreViewToken> {
|
|
219
246
|
private map;
|
|
220
247
|
private readonly viewChangeMode;
|
|
221
248
|
private readonly pendingIconImages;
|
|
222
249
|
readonly scalesGroundPointSymbolsNatively = true;
|
|
250
|
+
private terrainActive;
|
|
251
|
+
private terrainBanding;
|
|
252
|
+
private readonly pinPixelRatio?;
|
|
253
|
+
private readonly handleTerrainChange;
|
|
223
254
|
constructor(map: maplibregl.Map, options?: MapLibreAdapterOptions);
|
|
255
|
+
/** Switches `terrainBanding` at runtime, re-banding every group if the effective state changes. */
|
|
256
|
+
setTerrainBanding(enabled: boolean): void;
|
|
257
|
+
protected destroyEngineResources(): void;
|
|
258
|
+
/**
|
|
259
|
+
* Insertion anchor for a new bundle layer: below the handle's layers, or —
|
|
260
|
+
* for an overlay-band layer under terrain — below the overlay anchor, so it
|
|
261
|
+
* never lands between draped layers and fragments a render-to-texture stack
|
|
262
|
+
* (ADR-0057).
|
|
263
|
+
*/
|
|
264
|
+
private insertionAnchor;
|
|
224
265
|
private toContinuousLng;
|
|
225
266
|
protected createLayer(layerId: LayerId, style?: StyleOptions): MapLibreLayerHandle;
|
|
226
267
|
protected destroyLayer(handle: MapLibreLayerHandle): void;
|
|
@@ -234,6 +275,21 @@ declare class MapLibreAdapter extends BaseMapAdapter<MapLibreLayerHandle, MapLib
|
|
|
234
275
|
private updateSurfaceSizing;
|
|
235
276
|
private buildGroupLayer;
|
|
236
277
|
private updateGroupBundleSource;
|
|
278
|
+
/**
|
|
279
|
+
* Reorders bundle layers below `handle.mlLayerIds`. Walks groups back to
|
|
280
|
+
* front with a `beforeId` cursor, the same LIS-based stable-subset
|
|
281
|
+
* optimization as before.
|
|
282
|
+
*
|
|
283
|
+
* While terrain is active (ADR-0057), bundle layers instead split into two
|
|
284
|
+
* independently-tracked bands so every graphic contributes at most two
|
|
285
|
+
* render-to-texture stacks instead of one per graphic: a draped band
|
|
286
|
+
* (image overlays, fill/fill-pattern/line surfaces) anchored below the
|
|
287
|
+
* handle's own `-fill` layer, and an overlay band (the pin layer,
|
|
288
|
+
* circle/icon/text surfaces) anchored below the handle's own `-circle`
|
|
289
|
+
* layer. Without terrain, both cursors stay equal throughout, collapsing
|
|
290
|
+
* back to the single-cursor algorithm and the exact atomic per-graphic
|
|
291
|
+
* order (ADR-0039).
|
|
292
|
+
*/
|
|
237
293
|
private orderGroupBundles;
|
|
238
294
|
private nativeLayerIds;
|
|
239
295
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -81,11 +81,15 @@ var PinResources = class {
|
|
|
81
81
|
map.on("webglcontextrestored", this.restore);
|
|
82
82
|
map.on("move", this.invalidateDepth);
|
|
83
83
|
}
|
|
84
|
-
|
|
84
|
+
/**
|
|
85
|
+
* `pixelRatio` is the device pixels per CSS pixel the atlas is rasterized
|
|
86
|
+
* at; it is part of the roster key, so a change rebuilds the atlas.
|
|
87
|
+
*/
|
|
88
|
+
setRoster(pins, pixelRatio = 1) {
|
|
85
89
|
this.needsDepth = pins.some((pin) => pin.presentation.occlusion === "terrain");
|
|
86
90
|
const resources = /* @__PURE__ */ new Map();
|
|
87
91
|
for (const pin of pins) {
|
|
88
|
-
const scale = pin.presentation.sizePixels / pin.octagonSize *
|
|
92
|
+
const scale = pin.presentation.sizePixels / pin.octagonSize * pixelRatio;
|
|
89
93
|
if (scale > (resources.get(pin.resource.id)?.scale ?? 0)) resources.set(pin.resource.id, {
|
|
90
94
|
pin,
|
|
91
95
|
scale
|
|
@@ -239,14 +243,15 @@ void main() {
|
|
|
239
243
|
else if(kind < 1.5) {
|
|
240
244
|
vec2 delta = tp-gp; float len = length(delta);
|
|
241
245
|
vec2 dir = len > .0001 ? delta/len : vec2(0,1);
|
|
242
|
-
|
|
246
|
+
// Widen by 1px so the fragment edge fade has room to run.
|
|
247
|
+
vec2 p = mix(gp,tp,c.y) + vec2(-dir.y,dir.x) * (c.x-.5)*(a_shape.x+1.);
|
|
243
248
|
clip = vec4(p/u_view*2., mix(ground.z/ground.w,target.z/target.w,c.y), 1.);
|
|
244
249
|
offset = vec2(0);
|
|
245
250
|
} else { offset = (c - vec2(.5,0)) * a_shape.xy + a_shape.zw; }
|
|
246
251
|
clip.xy += offset * 2. / u_view * clip.w;
|
|
247
252
|
if (ground.w <= 0. || target.w <= 0.) clip = vec4(2,2,2,1);
|
|
248
253
|
gl_Position=clip;
|
|
249
|
-
v_local=(c-.5)*a_shape.xy;
|
|
254
|
+
v_local=(c-.5)*(a_shape.xy + (kind > .5 && kind < 1.5 ? vec2(1,0) : vec2(0)));
|
|
250
255
|
v_uv=mix(a_uv.xy,a_uv.zw,vec2(c.x,1.-c.y));
|
|
251
256
|
v_bounds=a_uv; v_color=a_color; v_shape=a_shape; v_flags=a_flags; v_radius=a_target.w;
|
|
252
257
|
}`;
|
|
@@ -288,6 +293,10 @@ void main() {
|
|
|
288
293
|
if(kind < .5) {
|
|
289
294
|
float edge=length(v_local)-v_shape.x*.5;
|
|
290
295
|
paint.a *= 1.-smoothstep(-1.,0.,edge);
|
|
296
|
+
} else if(kind < 1.5) {
|
|
297
|
+
// World-mode stems lean with perspective; fade the long edges over one device pixel.
|
|
298
|
+
float aa=max(fwidth(v_local.x),1e-4);
|
|
299
|
+
paint.a *= clamp((v_shape.x*.5-abs(v_local.x))/aa+.5,0.,1.);
|
|
291
300
|
} else if(kind > 4.5) {
|
|
292
301
|
// One optional halo instance; reuse the canonical atlas, including text and HQ staff.
|
|
293
302
|
vec2 size = v_shape.xy - vec2(2. * v_radius);
|
|
@@ -1305,13 +1314,44 @@ function coordinatesEqual(a, b) {
|
|
|
1305
1314
|
}
|
|
1306
1315
|
return true;
|
|
1307
1316
|
}
|
|
1308
|
-
|
|
1309
|
-
|
|
1317
|
+
/**
|
|
1318
|
+
* Paint channels MapLibre renders into a terrain render-to-texture stack
|
|
1319
|
+
* (background/fill/line/raster/hillshade) rather than directly onto the
|
|
1320
|
+
* screen. See ADR-0057.
|
|
1321
|
+
*/
|
|
1322
|
+
const DRAPED_CHANNELS = new Set([
|
|
1323
|
+
"fill",
|
|
1324
|
+
"fill-pattern",
|
|
1325
|
+
"line"
|
|
1326
|
+
]);
|
|
1327
|
+
function isDrapedChannel(channel) {
|
|
1328
|
+
return DRAPED_CHANNELS.has(channel);
|
|
1329
|
+
}
|
|
1330
|
+
/**
|
|
1331
|
+
* Bottom-most layer of a bundle, used as the next (earlier) group's anchor in
|
|
1332
|
+
* `orderGroupBundles`. With a `band` (terrain active, ADR-0057), only that
|
|
1333
|
+
* band's layers count: image overlays are always draped, the pin layer is
|
|
1334
|
+
* always overlay, and paint surfaces follow `isDrapedChannel`.
|
|
1335
|
+
*/
|
|
1336
|
+
function firstBundleLayerId(bundle, band) {
|
|
1337
|
+
if (bundle.pinLayer && band !== "draped") return bundle.pinLayer.id;
|
|
1338
|
+
if (band !== "overlay") for (const overlay of bundle.overlays.values()) return overlay.layerId;
|
|
1310
1339
|
for (const key of bundle.paintOrder) {
|
|
1311
1340
|
const surface = bundle.paintSurfaces.get(key);
|
|
1312
|
-
if (surface)
|
|
1341
|
+
if (!surface) continue;
|
|
1342
|
+
if (!band || isDrapedChannel(surface.channel) === (band === "draped")) return surface.layerId;
|
|
1313
1343
|
}
|
|
1314
1344
|
}
|
|
1345
|
+
/** Hides an always-empty handle-level anchor layer; see `createLayer`. */
|
|
1346
|
+
function hiddenLayer(layer) {
|
|
1347
|
+
return {
|
|
1348
|
+
...layer,
|
|
1349
|
+
layout: {
|
|
1350
|
+
..."layout" in layer ? layer.layout : {},
|
|
1351
|
+
visibility: "none"
|
|
1352
|
+
}
|
|
1353
|
+
};
|
|
1354
|
+
}
|
|
1315
1355
|
function sameOrder(a, b) {
|
|
1316
1356
|
if (a.length !== b.length) return false;
|
|
1317
1357
|
for (let index = 0; index < a.length; index++) if (a[index] !== b[index]) return false;
|
|
@@ -1915,10 +1955,40 @@ var MapLibreAdapter = class extends BaseMapAdapter {
|
|
|
1915
1955
|
viewChangeMode;
|
|
1916
1956
|
pendingIconImages = /* @__PURE__ */ new Set();
|
|
1917
1957
|
scalesGroundPointSymbolsNatively = true;
|
|
1958
|
+
terrainActive = false;
|
|
1959
|
+
terrainBanding;
|
|
1960
|
+
pinPixelRatio;
|
|
1961
|
+
handleTerrainChange = () => {
|
|
1962
|
+
const active = this.terrainBanding && !!this.map.getTerrain?.();
|
|
1963
|
+
if (active === this.terrainActive) return;
|
|
1964
|
+
this.terrainActive = active;
|
|
1965
|
+
for (const handle of this.layers.values()) this.orderGroupBundles(handle, handle.groupOrder, handle.groupOrder, new Set(handle.groupOrder));
|
|
1966
|
+
};
|
|
1918
1967
|
constructor(map, options = {}) {
|
|
1919
1968
|
super();
|
|
1920
1969
|
this.map = map;
|
|
1921
1970
|
this.viewChangeMode = options.viewChangeMode ?? "continuous";
|
|
1971
|
+
this.terrainBanding = options.terrainBanding ?? true;
|
|
1972
|
+
this.pinPixelRatio = options.pinPixelRatio;
|
|
1973
|
+
this.handleTerrainChange();
|
|
1974
|
+
this.map.on("terrain", this.handleTerrainChange);
|
|
1975
|
+
}
|
|
1976
|
+
/** Switches `terrainBanding` at runtime, re-banding every group if the effective state changes. */
|
|
1977
|
+
setTerrainBanding(enabled) {
|
|
1978
|
+
this.terrainBanding = enabled;
|
|
1979
|
+
this.handleTerrainChange();
|
|
1980
|
+
}
|
|
1981
|
+
destroyEngineResources() {
|
|
1982
|
+
this.map.off("terrain", this.handleTerrainChange);
|
|
1983
|
+
}
|
|
1984
|
+
/**
|
|
1985
|
+
* Insertion anchor for a new bundle layer: below the handle's layers, or —
|
|
1986
|
+
* for an overlay-band layer under terrain — below the overlay anchor, so it
|
|
1987
|
+
* never lands between draped layers and fragments a render-to-texture stack
|
|
1988
|
+
* (ADR-0057).
|
|
1989
|
+
*/
|
|
1990
|
+
insertionAnchor(handle, draped) {
|
|
1991
|
+
return this.terrainActive && !draped ? handle.overlayAnchorId : handle.mlLayerIds[0];
|
|
1922
1992
|
}
|
|
1923
1993
|
toContinuousLng(lng) {
|
|
1924
1994
|
return nearestWorldCopyLng(lng, this.map.getCenter().lng);
|
|
@@ -1932,25 +2002,25 @@ var MapLibreAdapter = class extends BaseMapAdapter {
|
|
|
1932
2002
|
});
|
|
1933
2003
|
const mlLayerIds = [];
|
|
1934
2004
|
const fillId = `${layerId}-fill`;
|
|
1935
|
-
this.map.addLayer({
|
|
2005
|
+
this.map.addLayer(hiddenLayer({
|
|
1936
2006
|
id: fillId,
|
|
1937
2007
|
type: "fill",
|
|
1938
2008
|
source: sourceId,
|
|
1939
2009
|
filter: buildFillFilter(false),
|
|
1940
2010
|
paint: buildFillPaint(style)
|
|
1941
|
-
});
|
|
2011
|
+
}));
|
|
1942
2012
|
mlLayerIds.push(fillId);
|
|
1943
2013
|
const fillPatternId = `${layerId}-fill-pattern`;
|
|
1944
|
-
this.map.addLayer({
|
|
2014
|
+
this.map.addLayer(hiddenLayer({
|
|
1945
2015
|
id: fillPatternId,
|
|
1946
2016
|
type: "fill",
|
|
1947
2017
|
source: sourceId,
|
|
1948
2018
|
filter: buildFillFilter(true),
|
|
1949
2019
|
paint: FILL_PATTERN_PAINT
|
|
1950
|
-
});
|
|
2020
|
+
}));
|
|
1951
2021
|
mlLayerIds.push(fillPatternId);
|
|
1952
2022
|
const lineId = `${layerId}-line`;
|
|
1953
|
-
this.map.addLayer({
|
|
2023
|
+
this.map.addLayer(hiddenLayer({
|
|
1954
2024
|
id: lineId,
|
|
1955
2025
|
type: "line",
|
|
1956
2026
|
source: sourceId,
|
|
@@ -1972,28 +2042,29 @@ var MapLibreAdapter = class extends BaseMapAdapter {
|
|
|
1972
2042
|
"line-cap": "round",
|
|
1973
2043
|
"line-join": "round"
|
|
1974
2044
|
}
|
|
1975
|
-
});
|
|
2045
|
+
}));
|
|
1976
2046
|
mlLayerIds.push(lineId);
|
|
1977
2047
|
const circleId = `${layerId}-circle`;
|
|
1978
|
-
this.map.addLayer({
|
|
2048
|
+
this.map.addLayer(hiddenLayer({
|
|
1979
2049
|
id: circleId,
|
|
1980
2050
|
type: "circle",
|
|
1981
2051
|
source: sourceId,
|
|
1982
2052
|
filter: buildCirclePointFilter(style),
|
|
1983
2053
|
paint: buildCirclePaint(style)
|
|
1984
|
-
});
|
|
2054
|
+
}));
|
|
1985
2055
|
mlLayerIds.push(circleId);
|
|
1986
2056
|
const iconId = `${layerId}-icon`;
|
|
1987
|
-
this.map.addLayer(buildIconLayer(iconId, sourceId));
|
|
2057
|
+
this.map.addLayer(hiddenLayer(buildIconLayer(iconId, sourceId)));
|
|
1988
2058
|
mlLayerIds.push(iconId);
|
|
1989
2059
|
if (style?.text) {
|
|
1990
2060
|
const symbolId = `${layerId}-symbol`;
|
|
1991
|
-
this.map.addLayer(buildSymbolLayer(symbolId, sourceId, style.text));
|
|
2061
|
+
this.map.addLayer(hiddenLayer(buildSymbolLayer(symbolId, sourceId, style.text)));
|
|
1992
2062
|
mlLayerIds.push(symbolId);
|
|
1993
2063
|
}
|
|
1994
2064
|
return {
|
|
1995
2065
|
sourceId,
|
|
1996
2066
|
mlLayerIds,
|
|
2067
|
+
overlayAnchorId: circleId,
|
|
1997
2068
|
groupBundles: /* @__PURE__ */ new Map(),
|
|
1998
2069
|
groupOrder: [],
|
|
1999
2070
|
nextGroupBundleId: 0,
|
|
@@ -2038,10 +2109,12 @@ var MapLibreAdapter = class extends BaseMapAdapter {
|
|
|
2038
2109
|
const allPins = groups.flatMap((group) => group.pinBatch ?? []);
|
|
2039
2110
|
if (allPins.length) {
|
|
2040
2111
|
handle.pinResources ??= new PinResources(this.map);
|
|
2112
|
+
const pixelRatio = this.pinPixelRatio ?? Math.min(this.map.getPixelRatio(), 2);
|
|
2041
2113
|
const previousBatch = handle.lastPinBatch;
|
|
2042
|
-
if (!(previousBatch !== void 0 && previousBatch.length === allPins.length && allPins.every((pin, index) => pin === previousBatch[index]))) {
|
|
2043
|
-
handle.pinResources.setRoster(allPins);
|
|
2114
|
+
if (!(previousBatch !== void 0 && handle.lastPinPixelRatio === pixelRatio && previousBatch.length === allPins.length && allPins.every((pin, index) => pin === previousBatch[index]))) {
|
|
2115
|
+
handle.pinResources.setRoster(allPins, pixelRatio);
|
|
2044
2116
|
handle.lastPinBatch = allPins;
|
|
2117
|
+
handle.lastPinPixelRatio = pixelRatio;
|
|
2045
2118
|
}
|
|
2046
2119
|
}
|
|
2047
2120
|
const desiredGroupIds = new Set(groups.map((group) => group.id));
|
|
@@ -2062,7 +2135,7 @@ var MapLibreAdapter = class extends BaseMapAdapter {
|
|
|
2062
2135
|
if (group.pinBatch) {
|
|
2063
2136
|
if (!bundle.pinLayer) {
|
|
2064
2137
|
const custom = new PinLayer(`${bundle.sourceId}-pins`, handle.pinResources, this.emitPinStatus);
|
|
2065
|
-
this.map.addLayer(custom, handle
|
|
2138
|
+
this.map.addLayer(custom, this.insertionAnchor(handle, false));
|
|
2066
2139
|
bundle.pinLayer = custom;
|
|
2067
2140
|
bundlesNeedingOrder.add(group.id);
|
|
2068
2141
|
}
|
|
@@ -2236,7 +2309,7 @@ var MapLibreAdapter = class extends BaseMapAdapter {
|
|
|
2236
2309
|
featureId
|
|
2237
2310
|
]
|
|
2238
2311
|
};
|
|
2239
|
-
this.map.addLayer(layer, handle
|
|
2312
|
+
this.map.addLayer(layer, this.insertionAnchor(handle, isDrapedChannel(channel)));
|
|
2240
2313
|
bundle.paintSurfaces.set(key, {
|
|
2241
2314
|
layerId,
|
|
2242
2315
|
channel,
|
|
@@ -2332,23 +2405,44 @@ var MapLibreAdapter = class extends BaseMapAdapter {
|
|
|
2332
2405
|
bundle.sourceInitialized = true;
|
|
2333
2406
|
if (isPromiseLike(result)) Promise.resolve(result).catch(() => {});
|
|
2334
2407
|
}
|
|
2408
|
+
/**
|
|
2409
|
+
* Reorders bundle layers below `handle.mlLayerIds`. Walks groups back to
|
|
2410
|
+
* front with a `beforeId` cursor, the same LIS-based stable-subset
|
|
2411
|
+
* optimization as before.
|
|
2412
|
+
*
|
|
2413
|
+
* While terrain is active (ADR-0057), bundle layers instead split into two
|
|
2414
|
+
* independently-tracked bands so every graphic contributes at most two
|
|
2415
|
+
* render-to-texture stacks instead of one per graphic: a draped band
|
|
2416
|
+
* (image overlays, fill/fill-pattern/line surfaces) anchored below the
|
|
2417
|
+
* handle's own `-fill` layer, and an overlay band (the pin layer,
|
|
2418
|
+
* circle/icon/text surfaces) anchored below the handle's own `-circle`
|
|
2419
|
+
* layer. Without terrain, both cursors stay equal throughout, collapsing
|
|
2420
|
+
* back to the single-cursor algorithm and the exact atomic per-graphic
|
|
2421
|
+
* order (ADR-0039).
|
|
2422
|
+
*/
|
|
2335
2423
|
orderGroupBundles(handle, previousGroupIds, desiredGroupIds, forcedGroupIds) {
|
|
2336
|
-
|
|
2337
|
-
if (!
|
|
2424
|
+
const rootBeforeId = handle.mlLayerIds[0];
|
|
2425
|
+
if (!rootBeforeId) return;
|
|
2426
|
+
let drapedBeforeId = rootBeforeId;
|
|
2427
|
+
let overlayBeforeId = this.terrainActive ? handle.overlayAnchorId : rootBeforeId;
|
|
2338
2428
|
const stableGroupIds = sameOrder(previousGroupIds, desiredGroupIds) ? null : longestStableGroupIds(previousGroupIds, desiredGroupIds);
|
|
2339
2429
|
for (let index = desiredGroupIds.length - 1; index >= 0; index--) {
|
|
2340
2430
|
const groupId = desiredGroupIds[index];
|
|
2341
2431
|
const bundle = handle.groupBundles.get(groupId);
|
|
2342
2432
|
if (!bundle) continue;
|
|
2343
2433
|
if (forcedGroupIds.has(groupId) || stableGroupIds !== null && !stableGroupIds.has(groupId)) {
|
|
2344
|
-
if (bundle.pinLayer && this.map.getLayer(bundle.pinLayer.id)) this.map.moveLayer(bundle.pinLayer.id,
|
|
2345
|
-
for (const overlay of bundle.overlays.values()) if (this.map.getLayer(overlay.layerId)) this.map.moveLayer(overlay.layerId,
|
|
2434
|
+
if (bundle.pinLayer && this.map.getLayer(bundle.pinLayer.id)) this.map.moveLayer(bundle.pinLayer.id, overlayBeforeId);
|
|
2435
|
+
for (const overlay of bundle.overlays.values()) if (this.map.getLayer(overlay.layerId)) this.map.moveLayer(overlay.layerId, drapedBeforeId);
|
|
2346
2436
|
for (const key of bundle.paintOrder) {
|
|
2347
2437
|
const surface = bundle.paintSurfaces.get(key);
|
|
2348
|
-
if (surface
|
|
2438
|
+
if (!surface || !this.map.getLayer(surface.layerId)) continue;
|
|
2439
|
+
this.map.moveLayer(surface.layerId, isDrapedChannel(surface.channel) ? drapedBeforeId : overlayBeforeId);
|
|
2349
2440
|
}
|
|
2350
2441
|
}
|
|
2351
|
-
|
|
2442
|
+
if (this.terrainActive) {
|
|
2443
|
+
drapedBeforeId = firstBundleLayerId(bundle, "draped") ?? drapedBeforeId;
|
|
2444
|
+
overlayBeforeId = firstBundleLayerId(bundle, "overlay") ?? overlayBeforeId;
|
|
2445
|
+
} else drapedBeforeId = overlayBeforeId = firstBundleLayerId(bundle) ?? drapedBeforeId;
|
|
2352
2446
|
}
|
|
2353
2447
|
}
|
|
2354
2448
|
nativeLayerIds(handle) {
|
|
@@ -2589,7 +2683,7 @@ var MapLibreAdapter = class extends BaseMapAdapter {
|
|
|
2589
2683
|
for (const bundle of handle.groupBundles.values()) for (const surface of bundle.paintSurfaces.values()) this.applyChannelStyle(surface.layerId, surface.channel, style, resolvedStyle, surface.featureId);
|
|
2590
2684
|
if (style.text && !handle.mlLayerIds.some((id) => id.endsWith("-symbol"))) {
|
|
2591
2685
|
const symbolId = `${layerId}-symbol`;
|
|
2592
|
-
this.map.addLayer(buildSymbolLayer(symbolId, handle.sourceId, resolvedStyle.text));
|
|
2686
|
+
this.map.addLayer(hiddenLayer(buildSymbolLayer(symbolId, handle.sourceId, resolvedStyle.text)));
|
|
2593
2687
|
handle.mlLayerIds.push(symbolId);
|
|
2594
2688
|
}
|
|
2595
2689
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orbat-mapper/tactical-draw-adapter-maplibre",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "MapLibre GL JS engine adapter for @orbat-mapper/tactical-draw. Draw and edit tactical control measures (MIL-STD-2525 / APP-6) on a MapLibre map.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Orbat Mapper",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@orbat-mapper/control-measures": "^0.27.0",
|
|
41
|
-
"@orbat-mapper/tactical-draw": "^0.10.
|
|
41
|
+
"@orbat-mapper/tactical-draw": "^0.10.1"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"maplibre-gl": ">=5.8.0 <7.0.0"
|