@orbat-mapper/tactical-draw-adapter-maplibre 0.2.0-alpha.21 → 0.2.0-alpha.23

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
@@ -17,7 +17,20 @@ interface MapLibreGroupBundle {
17
17
  readonly sourceId: string;
18
18
  readonly layerIds: Map<PaintChannel, string>;
19
19
  features: readonly Feature[];
20
- featureSignature: string;
20
+ /** Features most recently submitted to the native source, after MapLibre-specific promotion. */
21
+ sourceFeatures: readonly Feature[];
22
+ /** Whether the native source has received its first complete dataset. */
23
+ sourceInitialized: boolean;
24
+ /** Unset while the stored value describes older features than `features` holds. */
25
+ featureSignature: string | undefined;
26
+ /**
27
+ * Last `FeatureGroup.revision` seen for this bundle, when the producer
28
+ * supplied one. Two consecutive groups with the same `revision` are known
29
+ * to carry byte-identical `features`, so it stands in for `featureSignature`
30
+ * without paying to re-stringify the whole group. A missing revision on
31
+ * either side falls back to the signature comparison — see `applyFeatureGroups`.
32
+ */
33
+ revision?: number;
21
34
  requiredIconIds: ReadonlySet<string>;
22
35
  }
23
36
  type MapLibreEventToken = (e: any) => void;
package/dist/index.mjs CHANGED
@@ -28,6 +28,49 @@ function sameOrder(a, b) {
28
28
  return true;
29
29
  }
30
30
  /**
31
+ * Replace the contents of shared-id features while adding/removing ids that
32
+ * entered or left a stable group bundle. Remove stale keys explicitly instead
33
+ * of combining `removeAllProperties` with `addOrUpdateProperties`: MapLibre's
34
+ * tile-index diff treats the former as exclusive and otherwise drops the
35
+ * replacement properties, including the promoted feature id.
36
+ */
37
+ function buildGeoJSONSourceDiff(previousFeatures, nextFeatures) {
38
+ const previousById = new Map(previousFeatures.map((feature) => [feature.id, feature]));
39
+ const nextById = new Map(nextFeatures.map((feature) => [feature.id, feature]));
40
+ const remove = previousFeatures.filter((feature) => !nextById.has(feature.id)).map((feature) => feature.id);
41
+ const add = [];
42
+ const update = [];
43
+ for (const feature of nextFeatures) {
44
+ const previous = previousById.get(feature.id);
45
+ if (!previous) {
46
+ add.push(feature);
47
+ continue;
48
+ }
49
+ if (feature.geometry === null) {
50
+ remove.push(feature.id);
51
+ add.push(feature);
52
+ continue;
53
+ }
54
+ const previousProperties = previous.properties ?? {};
55
+ const nextProperties = feature.properties ?? {};
56
+ const removeProperties = Object.keys(previousProperties).filter((key) => !Object.hasOwn(nextProperties, key));
57
+ update.push({
58
+ id: feature.id,
59
+ newGeometry: feature.geometry,
60
+ ...removeProperties.length > 0 ? { removeProperties } : {},
61
+ addOrUpdateProperties: Object.entries(nextProperties).map(([key, value]) => ({
62
+ key,
63
+ value
64
+ }))
65
+ });
66
+ }
67
+ return {
68
+ ...remove.length > 0 ? { remove } : {},
69
+ ...add.length > 0 ? { add } : {},
70
+ ...update.length > 0 ? { update } : {}
71
+ };
72
+ }
73
+ /**
31
74
  * Find the largest subset of bundles whose relative order already matches the
32
75
  * desired stack. Reorders then move only the remaining bundles.
33
76
  */
@@ -800,12 +843,19 @@ var MapLibreAdapter = class extends BaseMapAdapter {
800
843
  bundle = this.createGroupBundle(layerId, handle);
801
844
  handle.groupBundles.set(group.id, bundle);
802
845
  }
803
- const featureSignature = JSON.stringify(group.features);
804
- const contentChanged = isNewBundle || bundle.featureSignature !== featureSignature;
846
+ let contentChanged;
847
+ if (!isNewBundle && bundle.revision !== void 0 && group.revision !== void 0) {
848
+ contentChanged = bundle.revision !== group.revision;
849
+ if (contentChanged) bundle.featureSignature = void 0;
850
+ } else {
851
+ const featureSignature = JSON.stringify(group.features);
852
+ contentChanged = isNewBundle || bundle.featureSignature !== featureSignature;
853
+ bundle.featureSignature = featureSignature;
854
+ }
805
855
  const requiredIconIds = this.requiredIconIds(group);
806
856
  const resourcesChanged = bundle.requiredIconIds.size !== requiredIconIds.size || [...bundle.requiredIconIds].some((id) => !requiredIconIds.has(id));
807
857
  bundle.features = group.features;
808
- bundle.featureSignature = featureSignature;
858
+ bundle.revision = group.revision;
809
859
  bundle.requiredIconIds = requiredIconIds;
810
860
  if (this.reconcileGroupChannels(handle, bundle, groupPaintChannels(group.features, handle.style))) bundlesNeedingOrder.add(group.id);
811
861
  if (contentChanged || resourcesChanged) this.updateGroupBundleSource(bundle);
@@ -824,6 +874,8 @@ var MapLibreAdapter = class extends BaseMapAdapter {
824
874
  sourceId,
825
875
  layerIds: /* @__PURE__ */ new Map(),
826
876
  features: [],
877
+ sourceFeatures: [],
878
+ sourceInitialized: false,
827
879
  featureSignature: "[]",
828
880
  requiredIconIds: /* @__PURE__ */ new Set()
829
881
  };
@@ -917,10 +969,12 @@ var MapLibreAdapter = class extends BaseMapAdapter {
917
969
  const source = this.map.getSource(bundle.sourceId);
918
970
  if (!source) return;
919
971
  const features = [...bundle.requiredIconIds].every((id) => this.map.hasImage(id)) ? bundle.features.map((feature) => this.promoteFeature(feature)) : [];
920
- const result = source.setData({
972
+ const result = bundle.sourceInitialized && typeof source.updateData === "function" ? source.updateData(buildGeoJSONSourceDiff(bundle.sourceFeatures, features), true) : source.setData({
921
973
  type: "FeatureCollection",
922
974
  features
923
975
  }, true);
976
+ bundle.sourceFeatures = features;
977
+ bundle.sourceInitialized = true;
924
978
  if (isPromiseLike(result)) Promise.resolve(result).catch(() => {});
925
979
  }
926
980
  orderGroupBundles(handle, previousGroupIds, desiredGroupIds, forcedGroupIds) {
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.21",
3
+ "version": "0.2.0-alpha.23",
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.26",
41
- "@orbat-mapper/tactical-draw": "^0.2.0-alpha.36"
40
+ "@orbat-mapper/tactical-draw": "^0.2.0-alpha.38",
41
+ "@orbat-mapper/control-measures": "^0.2.0-alpha.26"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "maplibre-gl": ">=5.8.0 <6.0.0"