@orbat-mapper/tactical-draw-adapter-maplibre 0.2.0-alpha.8 → 0.2.0-alpha.9

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 CHANGED
@@ -13,10 +13,20 @@ type MapLibreEventToken = (e: any) => void;
13
13
  interface MapLibreViewToken {
14
14
  fn: () => void;
15
15
  }
16
+ interface MapLibreAdapterOptions {
17
+ /**
18
+ * How view changes propagate to view-state refits. "continuous" (default)
19
+ * refits on every frame of an animated zoom/rotate/pitch; "settle" defers
20
+ * the refit until the animation ends.
21
+ */
22
+ viewChangeMode?: "continuous" | "settle";
23
+ }
16
24
  declare class MapLibreAdapter extends BaseMapAdapter<MapLibreLayerHandle, MapLibreEventToken, MapLibreViewToken> {
17
25
  private map;
26
+ private readonly viewChangeMode;
18
27
  private readonly pendingIconImages;
19
- constructor(map: maplibregl.Map);
28
+ readonly scalesGroundPointSymbolsNatively = true;
29
+ constructor(map: maplibregl.Map, options?: MapLibreAdapterOptions);
20
30
  private toContinuousLng;
21
31
  protected createLayer(layerId: LayerId, style?: StyleOptions): MapLibreLayerHandle;
22
32
  protected destroyLayer(handle: MapLibreLayerHandle): void;
@@ -27,6 +37,7 @@ declare class MapLibreAdapter extends BaseMapAdapter<MapLibreLayerHandle, MapLib
27
37
  protected detachNativeEvent(entry: NativeEventEntry<MapLibreEventToken>): void;
28
38
  protected attachViewChange(handler: () => void): MapLibreViewToken;
29
39
  protected detachViewChange(token: MapLibreViewToken): void;
40
+ private viewChangeEvents;
30
41
  createEditPointerDriver(): EditPointerDriver;
31
42
  setLayerStyle(layerId: LayerId, style: StyleOptions): void;
32
43
  toLonLat(coordinate: number[]): Position;
@@ -48,4 +59,4 @@ declare class MapLibreAdapter extends BaseMapAdapter<MapLibreLayerHandle, MapLib
48
59
  setGlobeMode(enabled: boolean): void;
49
60
  }
50
61
  //#endregion
51
- export { MapLibreAdapter };
62
+ export { MapLibreAdapter, type MapLibreAdapterOptions };
package/dist/index.mjs CHANGED
@@ -80,11 +80,7 @@ function buildIconLayer(id, source) {
80
80
  ],
81
81
  layout: {
82
82
  "icon-image": ["get", "iconId"],
83
- "icon-size": [
84
- "coalesce",
85
- ["get", "iconScale"],
86
- 1
87
- ],
83
+ "icon-size": buildIconSizeExpression(),
88
84
  "icon-rotate": [
89
85
  "*",
90
86
  [
@@ -162,6 +158,60 @@ function buildTextSizeExpression(text) {
162
158
  ];
163
159
  }
164
160
  /**
161
+ * Per-feature icon size, same zoom-stop scheme as `buildTextSizeExpression`:
162
+ * a ground-sized point symbol carries `iconSizeMeters`/`iconOctagonSize` (and
163
+ * optional `iconMinPixels`/`iconMaxPixels`), so the meters→pixels clamp is
164
+ * evaluated inside the style layer at every integer zoom stop and the symbol
165
+ * scales smoothly through animated zooms. Anything else falls back to the
166
+ * host-computed `iconScale` snapshot.
167
+ */
168
+ function buildIconSizeExpression() {
169
+ const minExpr = [
170
+ "coalesce",
171
+ ["get", "iconMinPixels"],
172
+ 0
173
+ ];
174
+ const maxExpr = [
175
+ "coalesce",
176
+ ["get", "iconMaxPixels"],
177
+ 1e9
178
+ ];
179
+ const scaleAtZoom = (zoom) => {
180
+ return [
181
+ "case",
182
+ ["has", "iconSizeMeters"],
183
+ [
184
+ "/",
185
+ [
186
+ "max",
187
+ minExpr,
188
+ [
189
+ "min",
190
+ maxExpr,
191
+ [
192
+ "*",
193
+ ["get", "iconSizeMeters"],
194
+ Math.pow(2, zoom + 9) / WEB_MERCATOR_CIRCUMFERENCE
195
+ ]
196
+ ]
197
+ ],
198
+ ["get", "iconOctagonSize"]
199
+ ],
200
+ [
201
+ "coalesce",
202
+ ["get", "iconScale"],
203
+ 1
204
+ ]
205
+ ];
206
+ };
207
+ return [
208
+ "interpolate",
209
+ ["linear"],
210
+ ["zoom"],
211
+ ...Array.from({ length: 25 }, (_, zoom) => [zoom, scaleAtZoom(zoom)]).flat()
212
+ ];
213
+ }
214
+ /**
165
215
  * Build the paint expression for a fill layer with per-feature
166
216
  * `properties.style.fillColor` overlay. Mirrors `buildCirclePaint`.
167
217
  */
@@ -287,10 +337,13 @@ function buildLinePaint(style) {
287
337
  }
288
338
  var MapLibreAdapter = class extends BaseMapAdapter {
289
339
  map;
340
+ viewChangeMode;
290
341
  pendingIconImages = /* @__PURE__ */ new Set();
291
- constructor(map) {
342
+ scalesGroundPointSymbolsNatively = true;
343
+ constructor(map, options = {}) {
292
344
  super();
293
345
  this.map = map;
346
+ this.viewChangeMode = options.viewChangeMode ?? "continuous";
294
347
  }
295
348
  toContinuousLng(lng) {
296
349
  return nearestWorldCopyLng(lng, this.map.getCenter().lng);
@@ -420,17 +473,19 @@ var MapLibreAdapter = class extends BaseMapAdapter {
420
473
  }
421
474
  attachViewChange(handler) {
422
475
  const fn = () => handler();
423
- this.map.on("zoom", fn);
424
- this.map.on("rotate", fn);
425
- this.map.on("pitch", fn);
426
- this.map.on("moveend", fn);
476
+ for (const event of this.viewChangeEvents()) this.map.on(event, fn);
427
477
  return { fn };
428
478
  }
429
479
  detachViewChange(token) {
430
- this.map.off("zoom", token.fn);
431
- this.map.off("rotate", token.fn);
432
- this.map.off("pitch", token.fn);
433
- this.map.off("moveend", token.fn);
480
+ for (const event of this.viewChangeEvents()) this.map.off(event, token.fn);
481
+ }
482
+ viewChangeEvents() {
483
+ return this.viewChangeMode === "settle" ? ["moveend"] : [
484
+ "zoom",
485
+ "rotate",
486
+ "pitch",
487
+ "moveend"
488
+ ];
434
489
  }
435
490
  createEditPointerDriver() {
436
491
  const map = this.map;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orbat-mapper/tactical-draw-adapter-maplibre",
3
- "version": "0.2.0-alpha.8",
3
+ "version": "0.2.0-alpha.9",
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.2.0-alpha.15",
41
- "@orbat-mapper/tactical-draw": "^0.2.0-alpha.23"
41
+ "@orbat-mapper/tactical-draw": "^0.2.0-alpha.24"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "maplibre-gl": ">=4.0.0 <6.0.0"