@orbat-mapper/tactical-draw-adapter-maplibre 0.2.0-alpha.11 → 0.2.0-alpha.12

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
@@ -25,12 +25,17 @@ declare class MapLibreAdapter extends BaseMapAdapter<MapLibreLayerHandle, MapLib
25
25
  private map;
26
26
  private readonly viewChangeMode;
27
27
  private readonly pendingIconImages;
28
+ private readonly pendingLayerUpdates;
29
+ private readonly deferredLayerRemovals;
28
30
  readonly scalesGroundPointSymbolsNatively = true;
29
31
  constructor(map: maplibregl.Map, options?: MapLibreAdapterOptions);
30
32
  private toContinuousLng;
31
33
  protected createLayer(layerId: LayerId, style?: StyleOptions): MapLibreLayerHandle;
32
34
  protected destroyLayer(handle: MapLibreLayerHandle): void;
33
35
  protected applyFeatureOps(layerId: LayerId, ops: FeatureOps): void;
36
+ private updateSourceData;
37
+ private flushDeferredLayerRemoval;
38
+ deferLayerRemovalUntilLayerUpdate(layerId: LayerId, updatedLayerId: LayerId): void;
34
39
  protected applyIconResources(resources: readonly IconResource[]): void;
35
40
  protected removeIconResource(id: string): void;
36
41
  protected attachNativeEvent(type: "click" | "pointermove" | "dblclick", onEvent: (lonLat: Position, pixel: PixelCoordinate, originalEvent: unknown) => void): NativeEventEntry<MapLibreEventToken>;
package/dist/index.mjs CHANGED
@@ -1,6 +1,9 @@
1
1
  import { project, unproject } from "@orbat-mapper/control-measures";
2
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
+ function isPromiseLike(value) {
5
+ return (typeof value === "object" || typeof value === "function") && value !== null && typeof value.then === "function";
6
+ }
4
7
  function emptyFC() {
5
8
  return {
6
9
  type: "FeatureCollection",
@@ -340,6 +343,8 @@ var MapLibreAdapter = class extends BaseMapAdapter {
340
343
  map;
341
344
  viewChangeMode;
342
345
  pendingIconImages = /* @__PURE__ */ new Set();
346
+ pendingLayerUpdates = /* @__PURE__ */ new Map();
347
+ deferredLayerRemovals = /* @__PURE__ */ new Map();
343
348
  scalesGroundPointSymbolsNatively = true;
344
349
  constructor(map, options = {}) {
345
350
  super();
@@ -419,25 +424,73 @@ var MapLibreAdapter = class extends BaseMapAdapter {
419
424
  };
420
425
  }
421
426
  destroyLayer(handle) {
427
+ for (const [layerId, layerHandle] of this.layers) {
428
+ if (layerHandle !== handle) continue;
429
+ this.pendingLayerUpdates.get(layerId)?.cancel();
430
+ this.pendingLayerUpdates.delete(layerId);
431
+ this.deferredLayerRemovals.delete(layerId);
432
+ break;
433
+ }
422
434
  for (const mlId of handle.mlLayerIds) if (this.map.getLayer(mlId)) this.map.removeLayer(mlId);
423
435
  if (this.map.getSource(handle.sourceId)) this.map.removeSource(handle.sourceId);
424
436
  }
425
437
  applyFeatureOps(layerId, ops) {
438
+ const deferred = this.deferredLayerRemovals.get(layerId);
439
+ const isPureRemoval = ops.adds.length === 0 && ops.updates.length === 0 && (ops.removes?.length ?? 0) > 0;
440
+ if (deferred && isPureRemoval) {
441
+ deferred.after.then(() => this.flushDeferredLayerRemoval(layerId, deferred), () => this.flushDeferredLayerRemoval(layerId, deferred));
442
+ return;
443
+ }
444
+ if (deferred) this.deferredLayerRemovals.delete(layerId);
445
+ this.updateSourceData(layerId, ops.full);
446
+ }
447
+ updateSourceData(layerId, features) {
426
448
  const handle = this.layers.get(layerId);
427
449
  if (!handle) return;
428
450
  const source = this.map.getSource(handle.sourceId);
429
451
  if (!source) return;
430
- const features = ops.full.map((f) => f.id !== void 0 ? {
452
+ const promotedFeatures = features.map((f) => f.id !== void 0 ? {
431
453
  ...f,
432
454
  properties: {
433
455
  ...f.properties ?? {},
434
456
  _fid: f.id
435
457
  }
436
458
  } : f);
437
- source.setData({
438
- type: "FeatureCollection",
439
- features
459
+ let resolveSourceData;
460
+ const sourceDataCompletion = new Promise((resolve) => {
461
+ resolveSourceData = resolve;
440
462
  });
463
+ const onSourceData = (event) => {
464
+ if (event.sourceDataType !== "content") return;
465
+ source.off("data", onSourceData);
466
+ resolveSourceData();
467
+ };
468
+ source.on("data", onSourceData);
469
+ const result = source.setData({
470
+ type: "FeatureCollection",
471
+ features: promotedFeatures
472
+ }, true);
473
+ const supportsCompletionPromise = isPromiseLike(result);
474
+ if (supportsCompletionPromise) source.off("data", onSourceData);
475
+ const completion = supportsCompletionPromise ? Promise.resolve(result) : sourceDataCompletion;
476
+ const pending = {
477
+ completion,
478
+ cancel() {
479
+ source.off("data", onSourceData);
480
+ }
481
+ };
482
+ this.pendingLayerUpdates.set(layerId, pending);
483
+ completion.catch(() => {});
484
+ }
485
+ flushDeferredLayerRemoval(layerId, deferred) {
486
+ if (this.deferredLayerRemovals.get(layerId) !== deferred) return;
487
+ this.deferredLayerRemovals.delete(layerId);
488
+ this.updateSourceData(layerId, this.getLayerFeatures(layerId));
489
+ }
490
+ deferLayerRemovalUntilLayerUpdate(layerId, updatedLayerId) {
491
+ const pending = this.pendingLayerUpdates.get(updatedLayerId);
492
+ if (!pending || !this.layers.has(layerId)) return;
493
+ this.deferredLayerRemovals.set(layerId, { after: pending.completion });
441
494
  }
442
495
  applyIconResources(resources) {
443
496
  if (typeof Image === "undefined") return;
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.11",
3
+ "version": "0.2.0-alpha.12",
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.16",
41
- "@orbat-mapper/tactical-draw": "^0.2.0-alpha.26"
40
+ "@orbat-mapper/tactical-draw": "^0.2.0-alpha.27",
41
+ "@orbat-mapper/control-measures": "^0.2.0-alpha.16"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "maplibre-gl": ">=4.0.0 <6.0.0"