@orbat-mapper/tactical-draw-adapter-maplibre 0.2.0-alpha.0 → 0.2.0-alpha.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/README.md CHANGED
@@ -1,13 +1,11 @@
1
1
  # @orbat-mapper/tactical-draw-adapter-maplibre
2
2
 
3
- The [MapLibre GL JS](https://maplibre.org/maplibre-gl-js/docs/) engine adapter for
4
- the `@orbat-mapper/tactical-draw` toolkit. It implements the `MapAdapter` contract
5
- from `@orbat-mapper/tactical-draw` on top of MapLibre, so the engine-agnostic
6
- draw/edit controllers — sessions, draw rules, gestures, handle rendering — run
7
- unchanged against a MapLibre map.
3
+ [MapLibre GL JS](https://maplibre.org/maplibre-gl-js/docs/) bindings for
4
+ `@orbat-mapper/tactical-draw`. `MapLibreAdapter` implements the `MapAdapter`
5
+ contract, so the draw/edit sessions, draw rules, gestures, and handle
6
+ rendering from `tactical-draw` run unchanged on a MapLibre map.
8
7
 
9
- `maplibre-gl` is declared as a **peer dependency**, so you bring your own single
10
- copy and never install an engine you don't use.
8
+ `maplibre-gl` is a peer dependency — your app supplies the version.
11
9
 
12
10
  ## Installation
13
11
 
@@ -34,8 +32,11 @@ const adapter = new MapLibreAdapter(map);
34
32
  const draw = new TacticalDraw(adapter);
35
33
  ```
36
34
 
37
- Hand the adapter to `TacticalDraw` and drive draw/edit exactly as with any other
38
- engine adapter in the family.
35
+ ## Quick Links
36
+
37
+ - [`@orbat-mapper/tactical-draw`](https://www.npmjs.com/package/@orbat-mapper/tactical-draw) — the draw/edit core this adapter plugs into
38
+ - [`@orbat-mapper/control-measures`](https://www.npmjs.com/package/@orbat-mapper/control-measures) — generates the control measures as GeoJSON
39
+ - [GitHub repository](https://github.com/orbat-mapper/tactical-graphics)
39
40
 
40
41
  ## License
41
42
 
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { BaseMapAdapter, EditPointerDriver, FeatureOps, LayerId, MapCursor, NativeEventEntry, PickHandler, PickOptions, PixelCoordinate, StyleOptions } from "@orbat-mapper/tactical-draw";
1
+ import { BaseMapAdapter, EditPointerDriver, FeatureOps, IconResource, LayerId, MapCursor, NativeEventEntry, PickHandler, PickOptions, PixelCoordinate, StyleOptions } from "@orbat-mapper/tactical-draw";
2
2
  import maplibregl from "maplibre-gl";
3
3
  import { Position } from "geojson";
4
4
 
@@ -13,21 +13,37 @@ 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;
18
- constructor(map: maplibregl.Map);
26
+ private readonly viewChangeMode;
27
+ private readonly pendingIconImages;
28
+ readonly scalesGroundPointSymbolsNatively = true;
29
+ constructor(map: maplibregl.Map, options?: MapLibreAdapterOptions);
30
+ private toContinuousLng;
19
31
  protected createLayer(layerId: LayerId, style?: StyleOptions): MapLibreLayerHandle;
20
32
  protected destroyLayer(handle: MapLibreLayerHandle): void;
21
33
  protected applyFeatureOps(layerId: LayerId, ops: FeatureOps): void;
34
+ protected applyIconResources(resources: readonly IconResource[]): void;
35
+ protected removeIconResource(id: string): void;
22
36
  protected attachNativeEvent(type: "click" | "pointermove" | "dblclick", onEvent: (lonLat: Position, pixel: PixelCoordinate, originalEvent: unknown) => void): NativeEventEntry<MapLibreEventToken>;
23
37
  protected detachNativeEvent(entry: NativeEventEntry<MapLibreEventToken>): void;
24
38
  protected attachViewChange(handler: () => void): MapLibreViewToken;
25
39
  protected detachViewChange(token: MapLibreViewToken): void;
40
+ private viewChangeEvents;
26
41
  createEditPointerDriver(): EditPointerDriver;
27
42
  setLayerStyle(layerId: LayerId, style: StyleOptions): void;
28
43
  toLonLat(coordinate: number[]): Position;
29
44
  fromLonLat(position: Position): number[];
30
45
  getPixelFromCoordinate(position: Position): PixelCoordinate | null;
46
+ getCoordinateFromPixel(pixel: PixelCoordinate): Position | null;
31
47
  getViewportSize(): {
32
48
  width: number;
33
49
  height: number;
@@ -39,8 +55,9 @@ declare class MapLibreAdapter extends BaseMapAdapter<MapLibreLayerHandle, MapLib
39
55
  setDoubleClickZoomEnabled(enabled: boolean): void;
40
56
  getResolution(): number | undefined;
41
57
  getZoom(): number | undefined;
58
+ getBearing(): number;
42
59
  onPick(layerId: LayerId, handler: PickHandler, opts?: PickOptions): () => void;
43
60
  setGlobeMode(enabled: boolean): void;
44
61
  }
45
62
  //#endregion
46
- export { MapLibreAdapter };
63
+ export { MapLibreAdapter, type MapLibreAdapterOptions };
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { project, unproject } from "@orbat-mapper/control-measures";
2
- import { BaseMapAdapter, PointerCallbackHub, TOUCH_HIT_TOLERANCE_PX, bindAbortable, pickHitTolerance, tryControlMeasureIdFromFeature } from "@orbat-mapper/tactical-draw";
2
+ import { BaseMapAdapter, DEFAULT_TEXT_SIZE_MAX_PIXELS, DEFAULT_TEXT_SIZE_MIN_PIXELS, PointerCallbackHub, TOUCH_HIT_TOLERANCE_PX, bindAbortable, nearestWorldCopyLng, pickHitTolerance, tryControlMeasureIdFromFeature } from "@orbat-mapper/tactical-draw";
3
3
  //#region src/ml-adapter.ts
4
4
  function emptyFC() {
5
5
  return {
@@ -52,51 +52,163 @@ function buildCirclePointFilter(style) {
52
52
  "$type",
53
53
  "Point"
54
54
  ],
55
+ ["!has", "iconId"],
55
56
  ["!has", style.text.labelProperty]
56
57
  ] : [
57
- "==",
58
- "$type",
59
- "Point"
58
+ "all",
59
+ [
60
+ "==",
61
+ "$type",
62
+ "Point"
63
+ ],
64
+ ["!has", "iconId"]
60
65
  ];
61
66
  }
62
- function buildTextSizeExpression() {
63
- const size = [
67
+ function buildIconLayer(id, source) {
68
+ return {
69
+ id,
70
+ type: "symbol",
71
+ source,
72
+ filter: [
73
+ "all",
74
+ [
75
+ "==",
76
+ "$type",
77
+ "Point"
78
+ ],
79
+ ["has", "iconId"]
80
+ ],
81
+ layout: {
82
+ "icon-image": ["get", "iconId"],
83
+ "icon-size": buildIconSizeExpression(),
84
+ "icon-rotate": [
85
+ "*",
86
+ [
87
+ "coalesce",
88
+ ["get", "iconRotation"],
89
+ 0
90
+ ],
91
+ 180 / Math.PI
92
+ ],
93
+ "icon-rotation-alignment": "viewport",
94
+ "icon-pitch-alignment": "viewport",
95
+ "icon-allow-overlap": true,
96
+ "icon-ignore-placement": true
97
+ },
98
+ paint: { "icon-opacity": [
99
+ "coalesce",
100
+ ["get", "iconOpacity"],
101
+ 1
102
+ ] }
103
+ };
104
+ }
105
+ function centeredSvg(resource) {
106
+ const halfWidth = Math.max(resource.anchor[0], resource.width - resource.anchor[0]);
107
+ const halfHeight = Math.max(resource.anchor[1], resource.height - resource.anchor[1]);
108
+ const width = halfWidth * 2;
109
+ const height = halfHeight * 2;
110
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}"><g transform="translate(${halfWidth - resource.anchor[0]} ${halfHeight - resource.anchor[1]})">${resource.svg}</g></svg>`;
111
+ }
112
+ /** Web Mercator world circumference in meters (2π × 6378137). */
113
+ const WEB_MERCATOR_CIRCUMFERENCE = 40075016.686;
114
+ /**
115
+ * Per-feature text size (ADR-0028): a ground-anchored label carries
116
+ * `textSizeMeters` and renders at `textSizeMeters / resolution`, clamped to
117
+ * the layer's `textSizeMinPixels`/`textSizeMaxPixels` band; a screen-anchored
118
+ * one carries `textSizePixels` and renders at that constant; neither renders
119
+ * the 14px engine default. Layout properties only take zoom as an
120
+ * `interpolate`/`step` input, so the ground conversion is evaluated at every
121
+ * integer zoom stop (resolution = world circumference / 512·2^zoom pixels,
122
+ * matching `getResolution`); the linear ramp between stops approximates the
123
+ * exponential exactly closely enough at 1-zoom granularity.
124
+ */
125
+ function buildTextSizeExpression(text) {
126
+ const minPx = text.textSizeMinPixels ?? DEFAULT_TEXT_SIZE_MIN_PIXELS;
127
+ const maxPx = text.textSizeMaxPixels ?? DEFAULT_TEXT_SIZE_MAX_PIXELS;
128
+ const screenOrDefault = [
64
129
  "coalesce",
65
130
  ["get", "textSizePixels"],
66
131
  14
67
132
  ];
68
- const referenceZoom = [
133
+ const sizeAtZoom = (zoom) => {
134
+ return [
135
+ "case",
136
+ ["has", "textSizeMeters"],
137
+ [
138
+ "min",
139
+ maxPx,
140
+ [
141
+ "max",
142
+ minPx,
143
+ [
144
+ "*",
145
+ ["get", "textSizeMeters"],
146
+ Math.pow(2, zoom + 9) / WEB_MERCATOR_CIRCUMFERENCE
147
+ ]
148
+ ]
149
+ ],
150
+ screenOrDefault
151
+ ];
152
+ };
153
+ return [
154
+ "interpolate",
155
+ ["linear"],
156
+ ["zoom"],
157
+ ...Array.from({ length: 25 }, (_, zoom) => [zoom, sizeAtZoom(zoom)]).flat()
158
+ ];
159
+ }
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 = [
69
170
  "coalesce",
70
- ["get", "textSizeZoom"],
171
+ ["get", "iconMinPixels"],
71
172
  0
72
173
  ];
73
- const sizeAtZoom = (zoom) => [
74
- "min",
75
- 254,
76
- [
174
+ const maxExpr = [
175
+ "coalesce",
176
+ ["get", "iconMaxPixels"],
177
+ 1e9
178
+ ];
179
+ const scaleAtZoom = (zoom) => {
180
+ return [
77
181
  "case",
78
- ["has", "textSizeZoom"],
182
+ ["has", "iconSizeMeters"],
79
183
  [
80
- "*",
81
- size,
184
+ "/",
82
185
  [
83
- "^",
84
- 2,
186
+ "max",
187
+ minExpr,
85
188
  [
86
- "-",
87
- zoom,
88
- referenceZoom
189
+ "min",
190
+ maxExpr,
191
+ [
192
+ "*",
193
+ ["get", "iconSizeMeters"],
194
+ Math.pow(2, zoom + 9) / WEB_MERCATOR_CIRCUMFERENCE
195
+ ]
89
196
  ]
90
- ]
197
+ ],
198
+ ["get", "iconOctagonSize"]
91
199
  ],
92
- size
93
- ]
94
- ];
200
+ [
201
+ "coalesce",
202
+ ["get", "iconScale"],
203
+ 1
204
+ ]
205
+ ];
206
+ };
95
207
  return [
96
208
  "interpolate",
97
209
  ["linear"],
98
210
  ["zoom"],
99
- ...Array.from({ length: 25 }, (_, zoom) => [zoom, sizeAtZoom(zoom)]).flat()
211
+ ...Array.from({ length: 25 }, (_, zoom) => [zoom, scaleAtZoom(zoom)]).flat()
100
212
  ];
101
213
  }
102
214
  /**
@@ -136,6 +248,22 @@ function buildSymbolLayer(symbolId, sourceId, text) {
136
248
  ],
137
249
  "#000"
138
250
  ];
251
+ const textAnchor = text.labelProperty ? [
252
+ "case",
253
+ [
254
+ "==",
255
+ ["get", "textAnchor"],
256
+ "start"
257
+ ],
258
+ "left",
259
+ [
260
+ "==",
261
+ ["get", "textAnchor"],
262
+ "end"
263
+ ],
264
+ "right",
265
+ "center"
266
+ ] : "center";
139
267
  return {
140
268
  id: symbolId,
141
269
  type: "symbol",
@@ -143,8 +271,9 @@ function buildSymbolLayer(symbolId, sourceId, text) {
143
271
  layout: {
144
272
  "text-field": text.labelProperty ? ["get", text.labelProperty] : text.text ?? "",
145
273
  "text-font": ["Open Sans Regular"],
146
- "text-size": buildTextSizeExpression(),
274
+ "text-size": buildTextSizeExpression(text),
147
275
  "text-rotate": textRotate,
276
+ "text-anchor": textAnchor,
148
277
  "text-rotation-alignment": "map",
149
278
  "text-pitch-alignment": "map",
150
279
  "text-allow-overlap": true
@@ -208,9 +337,16 @@ function buildLinePaint(style) {
208
337
  }
209
338
  var MapLibreAdapter = class extends BaseMapAdapter {
210
339
  map;
211
- constructor(map) {
340
+ viewChangeMode;
341
+ pendingIconImages = /* @__PURE__ */ new Set();
342
+ scalesGroundPointSymbolsNatively = true;
343
+ constructor(map, options = {}) {
212
344
  super();
213
345
  this.map = map;
346
+ this.viewChangeMode = options.viewChangeMode ?? "continuous";
347
+ }
348
+ toContinuousLng(lng) {
349
+ return nearestWorldCopyLng(lng, this.map.getCenter().lng);
214
350
  }
215
351
  createLayer(layerId, style) {
216
352
  const sourceId = `${layerId}-src`;
@@ -267,6 +403,9 @@ var MapLibreAdapter = class extends BaseMapAdapter {
267
403
  paint: buildCirclePaint(style)
268
404
  });
269
405
  mlLayerIds.push(circleId);
406
+ const iconId = `${layerId}-icon`;
407
+ this.map.addLayer(buildIconLayer(iconId, sourceId));
408
+ mlLayerIds.push(iconId);
270
409
  if (style?.text) {
271
410
  const symbolId = `${layerId}-symbol`;
272
411
  this.map.addLayer(buildSymbolLayer(symbolId, sourceId, style.text));
@@ -299,10 +438,29 @@ var MapLibreAdapter = class extends BaseMapAdapter {
299
438
  features
300
439
  });
301
440
  }
441
+ applyIconResources(resources) {
442
+ if (typeof Image === "undefined") return;
443
+ for (const resource of resources) {
444
+ if (this.map.hasImage(resource.id) || this.pendingIconImages.has(resource.id)) continue;
445
+ this.pendingIconImages.add(resource.id);
446
+ const image = new Image();
447
+ image.onload = () => {
448
+ if (!this.pendingIconImages.has(resource.id)) return;
449
+ this.pendingIconImages.delete(resource.id);
450
+ if (!this.map.hasImage(resource.id)) this.map.addImage(resource.id, image);
451
+ };
452
+ image.onerror = () => this.pendingIconImages.delete(resource.id);
453
+ image.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(centeredSvg(resource))}`;
454
+ }
455
+ }
456
+ removeIconResource(id) {
457
+ this.pendingIconImages.delete(id);
458
+ if (this.map.hasImage(id)) this.map.removeImage(id);
459
+ }
302
460
  attachNativeEvent(type, onEvent) {
303
461
  const mlEvent = type === "pointermove" ? "mousemove" : type === "dblclick" ? "dblclick" : "click";
304
462
  const fn = (e) => {
305
- onEvent([e.lngLat.lng, e.lngLat.lat], [e.point.x, e.point.y], e);
463
+ onEvent([this.toContinuousLng(e.lngLat.lng), e.lngLat.lat], [e.point.x, e.point.y], e);
306
464
  };
307
465
  this.map.on(mlEvent, fn);
308
466
  return {
@@ -315,22 +473,32 @@ var MapLibreAdapter = class extends BaseMapAdapter {
315
473
  }
316
474
  attachViewChange(handler) {
317
475
  const fn = () => handler();
318
- this.map.on("moveend", fn);
319
- this.map.on("zoomend", fn);
476
+ for (const event of this.viewChangeEvents()) this.map.on(event, fn);
320
477
  return { fn };
321
478
  }
322
479
  detachViewChange(token) {
323
- this.map.off("moveend", token.fn);
324
- this.map.off("zoomend", 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
+ ];
325
489
  }
326
490
  createEditPointerDriver() {
327
491
  const map = this.map;
492
+ const toContinuousLng = (lng) => this.toContinuousLng(lng);
328
493
  const hub = new PointerCallbackHub();
329
494
  let dragPanWasEnabled = false;
330
495
  let disposed = false;
331
496
  let touchDragActive = false;
332
497
  let multiTouchCancelled = false;
333
- const TOUCH_INFO = { hitTolerance: TOUCH_HIT_TOLERANCE_PX };
498
+ const touchInfo = (e) => ({
499
+ hitTolerance: TOUCH_HIT_TOLERANCE_PX,
500
+ native: e.originalEvent
501
+ });
334
502
  const preventMapEventDefaults = (e) => {
335
503
  e.preventDefault();
336
504
  e.originalEvent.preventDefault?.();
@@ -338,22 +506,32 @@ var MapLibreAdapter = class extends BaseMapAdapter {
338
506
  };
339
507
  const onDown = (e) => {
340
508
  const px = [e.point.x, e.point.y];
341
- const info = { altKey: e.originalEvent.altKey };
509
+ const info = {
510
+ altKey: e.originalEvent.altKey,
511
+ shiftKey: e.originalEvent.shiftKey,
512
+ native: e.originalEvent
513
+ };
342
514
  hub.fireDown(px, info);
343
515
  };
344
516
  const onMove = (e) => {
345
517
  const px = [e.point.x, e.point.y];
346
- hub.fireMove(px);
518
+ hub.fireMove(px, {
519
+ shiftKey: e.originalEvent.shiftKey,
520
+ native: e.originalEvent
521
+ });
347
522
  };
348
523
  const onUp = (e) => {
349
524
  const px = [e.point.x, e.point.y];
350
- hub.fireUp(px);
525
+ hub.fireUp(px, {
526
+ shiftKey: e.originalEvent.shiftKey,
527
+ native: e.originalEvent
528
+ });
351
529
  };
352
530
  const onTouchStart = (e) => {
353
531
  if (e.points.length !== 1) return;
354
532
  const before = dragPanWasEnabled;
355
533
  const px = [e.point.x, e.point.y];
356
- hub.fireDown(px, TOUCH_INFO);
534
+ hub.fireDown(px, touchInfo(e));
357
535
  touchDragActive = dragPanWasEnabled !== before;
358
536
  if (touchDragActive) preventMapEventDefaults(e);
359
537
  };
@@ -362,20 +540,20 @@ var MapLibreAdapter = class extends BaseMapAdapter {
362
540
  const px = [e.point.x, e.point.y];
363
541
  if (touchCount > 1 && touchDragActive && !multiTouchCancelled) {
364
542
  multiTouchCancelled = true;
365
- hub.fireUp(px, TOUCH_INFO);
543
+ hub.fireUp(px, touchInfo(e));
366
544
  touchDragActive = false;
367
545
  preventMapEventDefaults(e);
368
546
  return;
369
547
  }
370
548
  if (touchCount > 1) return;
371
549
  if (touchCount === 1) multiTouchCancelled = false;
372
- hub.fireMove(px, TOUCH_INFO);
550
+ hub.fireMove(px, touchInfo(e));
373
551
  if (touchDragActive) preventMapEventDefaults(e);
374
552
  };
375
553
  const onTouchEnd = (e) => {
376
554
  multiTouchCancelled = false;
377
555
  const px = [e.point.x, e.point.y];
378
- hub.fireUp(px, TOUCH_INFO);
556
+ hub.fireUp(px, touchInfo(e));
379
557
  touchDragActive = false;
380
558
  };
381
559
  map.on("mousedown", onDown);
@@ -399,12 +577,12 @@ var MapLibreAdapter = class extends BaseMapAdapter {
399
577
  }
400
578
  },
401
579
  toPixel(lonLat) {
402
- const p = map.project(lonLat);
580
+ const p = map.project([toContinuousLng(lonLat[0]), lonLat[1]]);
403
581
  return [p.x, p.y];
404
582
  },
405
583
  fromPixel(pixel) {
406
584
  const ll = map.unproject(pixel);
407
- return [ll.lng, ll.lat];
585
+ return [toContinuousLng(ll.lng), ll.lat];
408
586
  },
409
587
  dispose() {
410
588
  if (disposed) return;
@@ -468,9 +646,13 @@ var MapLibreAdapter = class extends BaseMapAdapter {
468
646
  return project(position[0], position[1]);
469
647
  }
470
648
  getPixelFromCoordinate(position) {
471
- const point = this.map.project(position);
649
+ const point = this.map.project([this.toContinuousLng(position[0]), position[1]]);
472
650
  return [point.x, point.y];
473
651
  }
652
+ getCoordinateFromPixel(pixel) {
653
+ const coordinate = this.map.unproject(pixel);
654
+ return [this.toContinuousLng(coordinate.lng), coordinate.lat];
655
+ }
474
656
  getViewportSize() {
475
657
  const container = this.map.getContainer();
476
658
  return {
@@ -500,13 +682,14 @@ var MapLibreAdapter = class extends BaseMapAdapter {
500
682
  else this.map.doubleClickZoom.disable();
501
683
  }
502
684
  getResolution() {
503
- const zoom = this.map.getZoom();
504
- const center = this.map.getCenter();
505
- return 40075016.686 * Math.cos(center.lat * Math.PI / 180) / Math.pow(2, zoom + 8);
685
+ return WEB_MERCATOR_CIRCUMFERENCE / Math.pow(2, this.map.getZoom() + 9);
506
686
  }
507
687
  getZoom() {
508
688
  return this.map.getZoom();
509
689
  }
690
+ getBearing() {
691
+ return this.map.getBearing() * (Math.PI / 180);
692
+ }
510
693
  onPick(layerId, handler, opts) {
511
694
  const onMlClick = (e) => {
512
695
  const handle = this.layers.get(layerId);
@@ -530,7 +713,7 @@ var MapLibreAdapter = class extends BaseMapAdapter {
530
713
  id: cmId,
531
714
  feature: geojson,
532
715
  pixel: [x, y],
533
- coordinate: [e.lngLat.lng, e.lngLat.lat],
716
+ coordinate: [this.toContinuousLng(e.lngLat.lng), e.lngLat.lat],
534
717
  originalEvent
535
718
  });
536
719
  };
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.0",
3
+ "version": "0.2.0-alpha.10",
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",
@@ -37,8 +37,8 @@
37
37
  "access": "public"
38
38
  },
39
39
  "dependencies": {
40
- "@orbat-mapper/control-measures": "^0.2.0-alpha.0",
41
- "@orbat-mapper/tactical-draw": "^0.2.0-alpha.0"
40
+ "@orbat-mapper/control-measures": "^0.2.0-alpha.16",
41
+ "@orbat-mapper/tactical-draw": "^0.2.0-alpha.25"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "maplibre-gl": ">=4.0.0 <6.0.0"