@maplibre/geojson-vt 6.0.1 → 6.0.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"cluster-tile-index.d.ts","sourceRoot":"","sources":["../src/cluster-tile-index.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,OAAO,KAAK,EAAiB,qBAAqB,EAAqB,kBAAkB,EAAoB,wBAAwB,EAAE,6BAA6B,EAAE,gBAAgB,EAAE,aAAa,EAAE,mBAAmB,EAAC,MAAM,eAAe,CAAC;AAQjP,gBAAgB;AAChB,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG;IAClC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,QAAQ,CAAC,mBAAmB,CAW/D,CAAC;AAQF;;GAEG;AACH,qBAAa,gBAAiB,YAAW,kBAAkB;IACvD,OAAO,EAAE,QAAQ,CAAC,mBAAmB,CAAC,CAAC;IACvC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACxC,MAAM,EAAE,6BAA6B,EAAE,CAAC;gBAE5B,OAAO,CAAC,EAAE,mBAAmB;IAQzC;;;OAGG;IACH,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI;IAyBpD;;;;OAIG;IACH,UAAU,CAAC,QAAQ,EAAE,wBAAwB,EAAE,GAAG,IAAI;IAWtD;;;;OAIG;IACH,WAAW,CAAC,QAAQ,EAAE,wBAAwB,EAAE,EAAE,SAAS,EAAE,wBAAwB,EAAE,EAAE,OAAO,EAAE,gBAAgB;IAKlH,OAAO,CAAC,WAAW;IAiDnB;;;;OAIG;IACI,WAAW,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,qBAAqB,EAAE;IAKjG,OAAO,CAAC,mBAAmB;IA0B3B;;;OAGG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,qBAAqB,EAAE;IA4BvD;;;;;OAKG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;IAU/F;;;;;OAKG;IACH,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAmC9D;;;OAGG;IACH,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAIlD,OAAO,CAAC,YAAY;IA4BpB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,eAAe;IA2CvB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,OAAO;IAmFf,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,GAAG;CASd"}
1
+ {"version":3,"file":"cluster-tile-index.d.ts","sourceRoot":"","sources":["../src/cluster-tile-index.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,OAAO,KAAK,EAAiB,qBAAqB,EAAqB,kBAAkB,EAAoB,wBAAwB,EAAE,6BAA6B,EAAE,gBAAgB,EAAE,aAAa,EAAE,mBAAmB,EAAC,MAAM,eAAe,CAAC;AAQjP,gBAAgB;AAChB,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG;IAClC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,QAAQ,CAAC,mBAAmB,CAW/D,CAAC;AAQF;;GAEG;AACH,qBAAa,gBAAiB,YAAW,kBAAkB;IACvD,OAAO,EAAE,QAAQ,CAAC,mBAAmB,CAAC,CAAC;IACvC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACxC,MAAM,EAAE,6BAA6B,EAAE,CAAC;gBAE5B,OAAO,CAAC,EAAE,mBAAmB;IAQzC;;;OAGG;IACH,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI;IAyBpD;;;;OAIG;IACH,UAAU,CAAC,QAAQ,EAAE,wBAAwB,EAAE,GAAG,IAAI;IAWtD;;;;OAIG;IACH,WAAW,CAAC,QAAQ,EAAE,wBAAwB,EAAE,EAAE,SAAS,EAAE,wBAAwB,EAAE,EAAE,OAAO,EAAE,gBAAgB;IAKlH,OAAO,CAAC,WAAW;IAiDnB;;;;OAIG;IACI,WAAW,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,qBAAqB,EAAE;IAKjG,OAAO,CAAC,mBAAmB;IA0B3B;;;OAGG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,qBAAqB,EAAE;IA4BvD;;;;;OAKG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;IAU/F;;;;;OAKG;IACH,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAsC9D;;;OAGG;IACH,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAIlD,OAAO,CAAC,YAAY;IA4BpB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,eAAe;IA2CvB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,OAAO;IAmFf,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,GAAG;CASd"}
@@ -42,6 +42,16 @@ export type GeoJSONVTFeatureDiff = {
42
42
  value: unknown;
43
43
  }[];
44
44
  };
45
+ export type ApplySourceDiffResult = {
46
+ /**
47
+ * The features affected by this update, which should be used to invalidate tiles
48
+ */
49
+ affected: GeoJSONVTInternalFeature[];
50
+ /**
51
+ * The updated source data, which should replace the existing source data in the index
52
+ */
53
+ source: GeoJSONVTInternalFeature[];
54
+ };
45
55
  type HashedGeoJSONVTSourceDiff = {
46
56
  removeAll?: boolean | undefined;
47
57
  remove: Set<string | number>;
@@ -55,10 +65,7 @@ type HashedGeoJSONVTSourceDiff = {
55
65
  * @param options
56
66
  * @returns
57
67
  */
58
- export declare function applySourceDiff(source: GeoJSONVTInternalFeature[], dataDiff: GeoJSONVTSourceDiff, options: GeoJSONVTOptions): {
59
- affected: GeoJSONVTInternalFeature[];
60
- source: GeoJSONVTInternalFeature[];
61
- };
68
+ export declare function applySourceDiff(source: GeoJSONVTInternalFeature[], dataDiff: GeoJSONVTSourceDiff, options: GeoJSONVTOptions): ApplySourceDiffResult;
62
69
  /**
63
70
  * Convert a GeoJSON Source Diff to an idempotent hashed representation using Sets and Maps
64
71
  */
@@ -1 +1 @@
1
- {"version":3,"file":"difference.d.ts","sourceRoot":"","sources":["../src/difference.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEhF,MAAM,MAAM,mBAAmB,GAAG;IAC9B;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAC7B;;OAEG;IACH,GAAG,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;IACxB;;OAEG;IACH,MAAM,CAAC,EAAE,oBAAoB,EAAE,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IAC/B;;OAEG;IACH,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC;IAC/B;;OAEG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B;;OAEG;IACH,qBAAqB,CAAC,EAAE;QACpB,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,OAAO,CAAC;KAClB,EAAE,CAAC;CACP,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC7B,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IAC7B,GAAG,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,oBAAoB,CAAC,CAAC;CACtD,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,wBAAwB,EAAE,EAAE,QAAQ,EAAE,mBAAmB,EAAE,OAAO,EAAE,gBAAgB;;;EAwE3H;AAgED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,yBAAyB,CAejF"}
1
+ {"version":3,"file":"difference.d.ts","sourceRoot":"","sources":["../src/difference.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEhF,MAAM,MAAM,mBAAmB,GAAG;IAC9B;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAC7B;;OAEG;IACH,GAAG,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;IACxB;;OAEG;IACH,MAAM,CAAC,EAAE,oBAAoB,EAAE,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IAC/B;;OAEG;IACH,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC;IAC/B;;OAEG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B;;OAEG;IACH,qBAAqB,CAAC,EAAE;QACpB,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,OAAO,CAAC;KAClB,EAAE,CAAC;CACP,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAChC;;OAEG;IACH,QAAQ,EAAE,wBAAwB,EAAE,CAAC;IACrC;;OAEG;IACH,MAAM,EAAE,wBAAwB,EAAE,CAAC;CACtC,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC7B,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IAC7B,GAAG,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,oBAAoB,CAAC,CAAC;CACtD,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,wBAAwB,EAAE,EAAE,QAAQ,EAAE,mBAAmB,EAAE,OAAO,EAAE,gBAAgB,GAAG,qBAAqB,CA6DnJ;AAqED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,yBAAyB,CAejF"}
@@ -680,89 +680,92 @@ function shiftCoords(points, offset) {
680
680
  function applySourceDiff(source, dataDiff, options) {
681
681
  // convert diff to sets/maps for o(1) lookups
682
682
  const diff = diffToHashed(dataDiff);
683
- // collection for features that will be affected by this update
683
+ // collection for features that will be affected by this update and used to invalidate tiles
684
684
  let affected = [];
685
- // full removal - clear everything before applying diff
686
685
  if (diff.removeAll) {
687
686
  affected = source;
688
687
  source = [];
689
688
  }
690
- // remove/add features and collect affected ones
691
689
  if (diff.remove.size || diff.add.size) {
692
690
  const removeFeatures = [];
693
- // collect source features to be removed
691
+ // Collect features to remove (explicit removals + replacements via add)
694
692
  for (const feature of source) {
695
- const { id } = feature;
696
- // explicit feature removal
697
- if (diff.remove.has(id)) {
698
- removeFeatures.push(feature);
699
- // feature with duplicate id being added
700
- }
701
- else if (diff.add.has(id)) {
693
+ if (diff.remove.has(feature.id) || diff.add.has(feature.id)) {
702
694
  removeFeatures.push(feature);
703
695
  }
704
696
  }
705
- // collect affected and remove from source
706
697
  if (removeFeatures.length) {
707
698
  affected.push(...removeFeatures);
708
699
  const removeIds = new Set(removeFeatures.map(f => f.id));
709
700
  source = source.filter(f => !removeIds.has(f.id));
710
701
  }
711
- // convert and add new features
712
702
  if (diff.add.size) {
713
- // projects and adds simplification info
714
703
  let addFeatures = convertToInternal({ type: 'FeatureCollection', features: Array.from(diff.add.values()) }, options);
715
- // wraps features (ie extreme west and extreme east)
716
704
  addFeatures = wrap(addFeatures, options);
717
705
  affected.push(...addFeatures);
718
706
  source.push(...addFeatures);
719
707
  }
720
708
  }
721
709
  if (diff.update.size) {
710
+ // Features can be duplicated across the antimeridian (wrap) in a single tile, so must update all instances with the same id
722
711
  for (const [id, update] of diff.update) {
723
- const featureIndex = source.findIndex(f => f.id === id);
724
- if (featureIndex === -1)
712
+ const oldFeatures = [];
713
+ const keepFeatures = [];
714
+ for (const feature of source) {
715
+ if (feature.id === id) {
716
+ oldFeatures.push(feature);
717
+ }
718
+ else {
719
+ keepFeatures.push(feature);
720
+ }
721
+ }
722
+ if (!oldFeatures.length)
725
723
  continue;
726
- const feature = source[featureIndex];
727
- // get updated geojsonvt simplified feature
728
- const updatedFeature = getUpdatedFeature(feature, update, options);
729
- if (!updatedFeature)
724
+ const updatedFeatures = getUpdatedFeatures(oldFeatures, update, options);
725
+ if (!updatedFeatures.length)
730
726
  continue;
731
- // track both features for invalidation
732
- affected.push(feature, updatedFeature);
733
- // replace old feature with updated feature
734
- source[featureIndex] = updatedFeature;
727
+ affected.push(...oldFeatures, ...updatedFeatures);
728
+ keepFeatures.push(...updatedFeatures);
729
+ source = keepFeatures;
735
730
  }
736
731
  }
737
732
  return { affected, source };
738
733
  }
739
- // return an updated geojsonvt simplified feature
740
- function getUpdatedFeature(vtFeature, update, options) {
734
+ /**
735
+ * Gets updated simplified feature(s) based on a diff update object.
736
+ * @param vtFeatures - the original features
737
+ * @param update - the update object to apply
738
+ * @param options - the options to use for the wrap method
739
+ * @returns Updated features. If geometry is updated, returns new feature(s) converted from geojson and wrapped. If only properties are updated, returns feature(s) with tags updated.
740
+ */
741
+ function getUpdatedFeatures(vtFeatures, update, options) {
741
742
  const changeGeometry = !!update.newGeometry;
742
743
  const changeProps = update.removeAllProperties ||
743
744
  update.removeProperties?.length > 0 ||
744
745
  update.addOrUpdateProperties?.length > 0;
745
- // if geometry changed, need to create new geojson feature and convert to simplified format
746
+ // if geometry changed, need to create a new geojson feature and convert to internal format
746
747
  if (changeGeometry) {
748
+ const vtFeature = vtFeatures[0];
747
749
  const geojsonFeature = {
748
750
  type: 'Feature',
749
751
  id: vtFeature.id,
750
752
  geometry: update.newGeometry,
751
753
  properties: changeProps ? applyPropertyUpdates(vtFeature.tags, update) : vtFeature.tags
752
754
  };
753
- // projects and adds simplification info
754
755
  let features = convertToInternal({ type: 'FeatureCollection', features: [geojsonFeature] }, options);
755
- // wraps features (ie extreme west and extreme east)
756
756
  features = wrap(features, options);
757
- return features[0];
757
+ return features;
758
758
  }
759
- // only properties changed - update tags directly
760
759
  if (changeProps) {
761
- const feature = { ...vtFeature };
762
- feature.tags = applyPropertyUpdates(feature.tags, update);
763
- return feature;
760
+ const updated = [];
761
+ for (const vtFeature of vtFeatures) {
762
+ const feature = { ...vtFeature };
763
+ feature.tags = applyPropertyUpdates(feature.tags, update);
764
+ updated.push(feature);
765
+ }
766
+ return updated;
764
767
  }
765
- return null;
768
+ return [];
766
769
  }
767
770
  /**
768
771
  * helper to apply property updates from a diff update object to a properties object
@@ -1334,6 +1337,9 @@ class ClusterTileIndex {
1334
1337
  */
1335
1338
  getTile(z, x, y) {
1336
1339
  const tree = this.trees[this.limitZoom(z)];
1340
+ if (!tree) {
1341
+ return null;
1342
+ }
1337
1343
  const z2 = Math.pow(2, z);
1338
1344
  const { extent, radius } = this.options;
1339
1345
  const p = radius / extent;
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).geojsonvt={})}(this,(function(t){"use strict";function e(t,o,i,s){let r=s;const a=o+(i-o>>1);let u,l=i-o;const c=t[o],h=t[o+1],d=t[i],p=t[i+1];for(let e=o+3;e<i;e+=3){const o=n(t[e],t[e+1],c,h,d,p);if(o>r)u=e,r=o;else if(o===r){const t=Math.abs(e-a);t<l&&(u=e,l=t)}}r>s&&(u-o>3&&e(t,o,u,s),t[u+2]=r,i-u>3&&e(t,u,i,s))}function n(t,e,n,o,i,s){let r=i-n,a=s-o;if(0!==r||0!==a){const u=((t-n)*r+(e-o)*a)/(r*r+a*a);u>1?(n=i,o=s):u>0&&(n+=r*u,o+=a*u)}return r=t-n,a=e-o,r*r+a*a}function o(t,e,n,o){const s={type:e,geom:n},r={id:null==t?null:t,type:s.type,geometry:s.geom,tags:o,minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};switch(s.type){case"Point":case"MultiPoint":case"LineString":i(r,s.geom);break;case"Polygon":i(r,s.geom[0]);break;case"MultiLineString":for(const t of s.geom)i(r,t);break;case"MultiPolygon":for(const t of s.geom)i(r,t[0])}return r}function i(t,e){for(let n=0;n<e.length;n+=3)t.minX=Math.min(t.minX,e[n]),t.minY=Math.min(t.minY,e[n+1]),t.maxX=Math.max(t.maxX,e[n]),t.maxY=Math.max(t.maxY,e[n+1])}function s(t,e){const n=[];switch(t.type){case"FeatureCollection":for(let o=0;o<t.features.length;o++)r(n,t.features[o],e,o);break;case"Feature":r(n,t,e);break;default:r(n,{geometry:t,properties:void 0},e)}return n}function r(t,e,n,i){if(!e.geometry)return;if("GeometryCollection"===e.geometry.type)return void function(t,e,n,o,i){for(const s of n.geometries)r(t,{id:e.id,geometry:s,properties:e.properties},o,i)}(t,e,e.geometry,n,i);const s=e.geometry.coordinates;if(!s?.length)return;const h=function(t,e,n){if(e.promoteId)return t.properties?.[e.promoteId];if(e.generateId)return n||0;return t.id}(e,n,i),d=Math.pow(n.tolerance/((1<<n.maxZoom)*n.extent),2);switch(e.geometry.type){case"Point":return void function(t,e,n,i){const s=[];s.push(l(n.coordinates[0]),c(n.coordinates[1]),0),t.push(o(e,"Point",s,i))}(t,h,e.geometry,e.properties);case"MultiPoint":return void function(t,e,n,i){const s=[];for(const t of n.coordinates)s.push(l(t[0]),c(t[1]),0);t.push(o(e,"MultiPoint",s,i))}(t,h,e.geometry,e.properties);case"LineString":return void function(t,e,n,i,s){const r=[];a(n.coordinates,r,i,!1),t.push(o(e,"LineString",r,s))}(t,h,e.geometry,d,e.properties);case"MultiLineString":return void function(t,e,n,i,s,r){if(s.lineMetrics)for(const s of n.coordinates){const n=[];a(s,n,i,!1),t.push(o(e,"LineString",n,r))}else{const s=[];u(n.coordinates,s,i,!1),t.push(o(e,"MultiLineString",s,r))}}(t,h,e.geometry,d,n,e.properties);case"Polygon":return void function(t,e,n,i,s){const r=[];u(n.coordinates,r,i,!0),t.push(o(e,"Polygon",r,s))}(t,h,e.geometry,d,e.properties);case"MultiPolygon":return void function(t,e,n,i,s){const r=[];for(const t of n.coordinates){const e=[];u(t,e,i,!0),r.push(e)}t.push(o(e,"MultiPolygon",r,s))}(t,h,e.geometry,d,e.properties);default:throw new Error("Input data is not a valid GeoJSON object.")}}function a(t,n,o,i){let s,r,a=0;for(let e=0;e<t.length;e++){const o=l(t[e][0]),u=c(t[e][1]);n.push(o,u,0),e>0&&(a+=i?(s*u-o*r)/2:Math.sqrt(Math.pow(o-s,2)+Math.pow(u-r,2))),s=o,r=u}const u=n.length-3;n[2]=1,o>0&&e(n,0,u,o),n[u+2]=1,n.size=Math.abs(a),n.start=0,n.end=n.size}function u(t,e,n,o){for(let i=0;i<t.length;i++){const s=[];a(t[i],s,n,o),e.push(s)}}function l(t){return t/360+.5}function c(t){const e=Math.sin(t*Math.PI/180),n=.5-.25*Math.log((1+e)/(1-e))/Math.PI;return n<0?0:n>1?1:n}function h(t){const e={type:"Feature",geometry:d(t),properties:t.tags};return null!=t.id&&(e.id=t.id),e}function d(t){const{type:e,geometry:n}=t;switch(e){case"Point":return{type:e,coordinates:f(n[0],n[1])};case"MultiPoint":case"LineString":return{type:e,coordinates:p(n)};case"MultiLineString":case"Polygon":return{type:e,coordinates:n.map((t=>p(t)))};case"MultiPolygon":return{type:e,coordinates:n.map((t=>t.map((t=>p(t)))))}}}function p(t){const e=[];for(let n=0;n<t.length;n+=3)e.push(f(t[n],t[n+1]));return e}function f(t,e){return[g(t),m(e)]}function g(t){return 360*(t-.5)}function m(t){const e=(180-360*t)*Math.PI/180;return 360*Math.atan(Math.exp(e))/Math.PI-90}var y;function x(t,e,n,o,i,s,r,a){if(o/=e,s>=(n/=e)&&r<o)return t;if(r<n||s>=o)return null;const u=[];for(const e of t){const t=i===y.X?e.minX:e.minY,s=i===y.X?e.maxX:e.maxY;if(t>=n&&s<o)u.push(e);else if(!(s<n||t>=o))switch(e.type){case"Point":case"MultiPoint":M(e,u,n,o,i);continue;case"LineString":w(e,u,n,o,i,a);continue;case"MultiLineString":P(e,u,n,o,i);continue;case"Polygon":I(e,u,n,o,i);continue;case"MultiPolygon":v(e,u,n,o,i);continue}}return u.length?u:null}function M(t,e,n,i,s){const r=[];if(function(t,e,n,o,i){for(let s=0;s<t.length;s+=3){const r=t[s+i];r>=n&&r<=o&&A(e,t[s],t[s+1],t[s+2])}}(t.geometry,r,n,i,s),!r.length)return;const a=3===r.length?"Point":"MultiPoint";e.push(o(t.id,a,r,t.tags))}function w(t,e,n,i,s,r){const a=[];if(b(t.geometry,a,n,i,s,!1,r.lineMetrics),a.length)if(r.lineMetrics)for(const n of a)e.push(o(t.id,"LineString",n,t.tags));else a.length>1?e.push(o(t.id,"MultiLineString",a,t.tags)):e.push(o(t.id,"LineString",a[0],t.tags))}function P(t,e,n,i,s){const r=[];z(t.geometry,r,n,i,s,!1),r.length&&(1!==r.length?e.push(o(t.id,"MultiLineString",r,t.tags)):e.push(o(t.id,"LineString",r[0],t.tags)))}function I(t,e,n,i,s){const r=[];z(t.geometry,r,n,i,s,!0),r.length&&e.push(o(t.id,"Polygon",r,t.tags))}function v(t,e,n,i,s){const r=[];for(const e of t.geometry){const t=[];z(e,t,n,i,s,!0),t.length&&r.push(t)}r.length&&e.push(o(t.id,"MultiPolygon",r,t.tags))}function b(t,e,n,o,i,s,r){let a=S(t);const u=i===y.X?E:T;let l,c,h=t.start;for(let d=0;d<t.length-3;d+=3){const p=t[d],f=t[d+1],g=t[d+2],m=t[d+3],x=t[d+4],M=i===y.X?p:f,w=i===y.X?m:x;let P=!1;r&&(l=Math.sqrt(Math.pow(p-m,2)+Math.pow(f-x,2))),M<n?w>n&&(c=u(a,p,f,m,x,n),r&&(a.start=h+l*c)):M>o?w<o&&(c=u(a,p,f,m,x,o),r&&(a.start=h+l*c)):A(a,p,f,g),w<n&&M>=n&&(c=u(a,p,f,m,x,n),P=!0),w>o&&M<=o&&(c=u(a,p,f,m,x,o),P=!0),!s&&P&&(r&&(a.end=h+l*c),e.push(a),a=S(t)),r&&(h+=l)}let d=t.length-3;const p=t[d],f=t[d+1],g=t[d+2],m=i===y.X?p:f;m>=n&&m<=o&&A(a,p,f,g),d=a.length-3,s&&d>=3&&(a[d]!==a[0]||a[d+1]!==a[1])&&A(a,a[0],a[1],a[2]),a.length&&e.push(a)}function S(t){const e=[];return e.size=t.size,e.start=t.start,e.end=t.end,e}function z(t,e,n,o,i,s){for(const r of t)b(r,e,n,o,i,s,!1)}function A(t,e,n,o){t.push(e,n,o)}function E(t,e,n,o,i,s){const r=(s-e)/(o-e);return A(t,s,n+(i-n)*r,1),r}function T(t,e,n,o,i,s){const r=(s-n)/(i-n);return A(t,e+(o-e)*r,s,1),r}function X(t,e){const n=e.buffer/e.extent;let o=t;const i=x(t,1,-1-n,n,y.X,-1,2,e),s=x(t,1,1-n,2+n,y.X,-1,2,e);return i||s?(o=x(t,1,-n,1+n,y.X,-1,2,e)||[],i&&(o=Y(i,1).concat(o)),s&&(o=o.concat(Y(s,-1))),o):o}function Y(t,e){const n=[];for(const i of t)switch(i.type){case"Point":case"MultiPoint":case"LineString":{const t=C(i.geometry,e);n.push(o(i.id,i.type,t,i.tags));continue}case"MultiLineString":case"Polygon":{const t=[];for(const n of i.geometry)t.push(C(n,e));n.push(o(i.id,i.type,t,i.tags));continue}case"MultiPolygon":{const t=[];for(const n of i.geometry){const o=[];for(const t of n)o.push(C(t,e));t.push(o)}n.push(o(i.id,i.type,t,i.tags));continue}}return n}function C(t,e){const n=[];n.size=t.size,void 0!==t.start&&(n.start=t.start,n.end=t.end);for(let o=0;o<t.length;o+=3)n.push(t[o]+e,t[o+1],t[o+2]);return n}function L(t,e,n){const o=function(t){if(!t)return{remove:new Set,add:new Map,update:new Map};const e={removeAll:t.removeAll,remove:new Set(t.remove||[]),add:new Map(t.add?.map((t=>[t.id,t]))),update:new Map(t.update?.map((t=>[t.id,t])))};return e}(e);let i=[];if(o.removeAll&&(i=t,t=[]),o.remove.size||o.add.size){const e=[];for(const n of t){const{id:t}=n;(o.remove.has(t)||o.add.has(t))&&e.push(n)}if(e.length){i.push(...e);const n=new Set(e.map((t=>t.id)));t=t.filter((t=>!n.has(t.id)))}if(o.add.size){let e=s({type:"FeatureCollection",features:Array.from(o.add.values())},n);e=X(e,n),i.push(...e),t.push(...e)}}if(o.update.size)for(const[e,s]of o.update){const o=t.findIndex((t=>t.id===e));if(-1===o)continue;const r=t[o],a=O(r,s,n);a&&(i.push(r,a),t[o]=a)}return{affected:i,source:t}}function O(t,e,n){const o=!!e.newGeometry,i=e.removeAllProperties||e.removeProperties?.length>0||e.addOrUpdateProperties?.length>0;if(o){let o=s({type:"FeatureCollection",features:[{type:"Feature",id:t.id,geometry:e.newGeometry,properties:i?_(t.tags,e):t.tags}]},n);return o=X(o,n),o[0]}if(i){const n={...t};return n.tags=_(n.tags,e),n}return null}function _(t,e){if(e.removeAllProperties)return{};const n={...t||{}};if(e.removeProperties)for(const t of e.removeProperties)delete n[t];if(e.addOrUpdateProperties)for(const{key:t,value:o}of e.addOrUpdateProperties)n[t]=o;return n}!function(t){t[t.X=0]="X",t[t.Y=1]="Y"}(y||(y={}));const Z=[Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];class F{static from(t){if(!(t instanceof ArrayBuffer))throw new Error("Data must be an instance of ArrayBuffer.");const[e,n]=new Uint8Array(t,0,2);if(219!==e)throw new Error("Data does not appear to be in a KDBush format.");const o=n>>4;if(1!==o)throw new Error(`Got v${o} data when expected v1.`);const i=Z[15&n];if(!i)throw new Error("Unrecognized array type.");const[s]=new Uint16Array(t,2,1),[r]=new Uint32Array(t,4,1);return new F(r,s,i,t)}constructor(t,e=64,n=Float64Array,o){if(isNaN(t)||t<0)throw new Error(`Unpexpected numItems value: ${t}.`);this.numItems=+t,this.nodeSize=Math.min(Math.max(+e,2),65535),this.ArrayType=n,this.IndexArrayType=t<65536?Uint16Array:Uint32Array;const i=Z.indexOf(this.ArrayType),s=2*t*this.ArrayType.BYTES_PER_ELEMENT,r=t*this.IndexArrayType.BYTES_PER_ELEMENT,a=(8-r%8)%8;if(i<0)throw new Error(`Unexpected typed array class: ${n}.`);o&&o instanceof ArrayBuffer?(this.data=o,this.ids=new this.IndexArrayType(this.data,8,t),this.coords=new this.ArrayType(this.data,8+r+a,2*t),this._pos=2*t,this._finished=!0):(this.data=new ArrayBuffer(8+s+r+a),this.ids=new this.IndexArrayType(this.data,8,t),this.coords=new this.ArrayType(this.data,8+r+a,2*t),this._pos=0,this._finished=!1,new Uint8Array(this.data,0,2).set([219,16+i]),new Uint16Array(this.data,2,1)[0]=e,new Uint32Array(this.data,4,1)[0]=t)}add(t,e){const n=this._pos>>1;return this.ids[n]=n,this.coords[this._pos++]=t,this.coords[this._pos++]=e,n}finish(){const t=this._pos>>1;if(t!==this.numItems)throw new Error(`Added ${t} items when expected ${this.numItems}.`);return U(this.ids,this.coords,this.nodeSize,0,this.numItems-1,0),this._finished=!0,this}range(t,e,n,o){if(!this._finished)throw new Error("Data not yet indexed - call index.finish().");const{ids:i,coords:s,nodeSize:r}=this,a=[0,i.length-1,0],u=[];for(;a.length;){const l=a.pop()||0,c=a.pop()||0,h=a.pop()||0;if(c-h<=r){for(let r=h;r<=c;r++){const a=s[2*r],l=s[2*r+1];a>=t&&a<=n&&l>=e&&l<=o&&u.push(i[r])}continue}const d=h+c>>1,p=s[2*d],f=s[2*d+1];p>=t&&p<=n&&f>=e&&f<=o&&u.push(i[d]),(0===l?t<=p:e<=f)&&(a.push(h),a.push(d-1),a.push(1-l)),(0===l?n>=p:o>=f)&&(a.push(d+1),a.push(c),a.push(1-l))}return u}within(t,e,n){if(!this._finished)throw new Error("Data not yet indexed - call index.finish().");const{ids:o,coords:i,nodeSize:s}=this,r=[0,o.length-1,0],a=[],u=n*n;for(;r.length;){const l=r.pop()||0,c=r.pop()||0,h=r.pop()||0;if(c-h<=s){for(let n=h;n<=c;n++)k(i[2*n],i[2*n+1],t,e)<=u&&a.push(o[n]);continue}const d=h+c>>1,p=i[2*d],f=i[2*d+1];k(p,f,t,e)<=u&&a.push(o[d]),(0===l?t-n<=p:e-n<=f)&&(r.push(h),r.push(d-1),r.push(1-l)),(0===l?t+n>=p:e+n>=f)&&(r.push(d+1),r.push(c),r.push(1-l))}return a}}function U(t,e,n,o,i,s){if(i-o<=n)return;const r=o+i>>1;D(t,e,r,o,i,s),U(t,e,n,o,r-1,1-s),U(t,e,n,r+1,i,1-s)}function D(t,e,n,o,i,s){for(;i>o;){if(i-o>600){const r=i-o+1,a=n-o+1,u=Math.log(r),l=.5*Math.exp(2*u/3),c=.5*Math.sqrt(u*l*(r-l)/r)*(a-r/2<0?-1:1);D(t,e,n,Math.max(o,Math.floor(n-a*l/r+c)),Math.min(i,Math.floor(n+(r-a)*l/r+c)),s)}const r=e[2*n+s];let a=o,u=i;for(j(t,e,o,n),e[2*i+s]>r&&j(t,e,o,i);a<u;){for(j(t,e,a,u),a++,u--;e[2*a+s]<r;)a++;for(;e[2*u+s]>r;)u--}e[2*o+s]===r?j(t,e,o,u):(u++,j(t,e,u,i)),u<=n&&(o=u+1),n<=u&&(i=u-1)}}function j(t,e,n,o){N(t,n,o),N(e,2*n,2*o),N(e,2*n+1,2*o+1)}function N(t,e,n){const o=t[e];t[e]=t[n],t[n]=o}function k(t,e,n,o){const i=t-n,s=e-o;return i*i+s*s}const $={minZoom:0,maxZoom:16,minPoints:2,radius:40,extent:512,nodeSize:64,log:!1,generateId:!1,reduce:null,map:t=>t},G=3,B=5,J=6;class q{options;trees;stride;clusterProps;points;constructor(t){this.options=Object.assign(Object.create($),t),this.trees=new Array(this.options.maxZoom+1),this.stride=this.options.reduce?7:6,this.clusterProps=[],this.points=[]}load(t){const e=[];for(const n of t){if(!n.geometry)continue;const[t,o]=n.geometry.coordinates,[i,s]=[l(t),c(o)],r={id:n.id,type:"Point",geometry:[i,s],tags:n.properties};e.push(r)}this.createIndex(e)}initialize(t){const e=[];for(const n of t)"Point"===n.type&&e.push(n);this.createIndex(e)}updateIndex(t,e,n){this.options=Object.assign(Object.create($),n.clusterOptions),this.initialize(t)}createIndex(t){const{log:e,minZoom:n,maxZoom:o}=this.options;e&&console.time("total time");const i=`prepare ${t.length} points`;e&&console.time(i),this.points=t;const s=[];for(let e=0;e<t.length;e++){const n=t[e];if(!n?.geometry)continue;let[o,i]=n.geometry;o=Math.fround(o),i=Math.fround(i),s.push(o,i,1/0,e,-1,1),this.options.reduce&&s.push(0)}let r=this.trees[o+1]=this.createTree(s);e&&console.timeEnd(i);for(let t=o;t>=n;t--){const n=Date.now();r=this.trees[t]=this.createTree(this.cluster(r,t)),e&&console.log("z%d: %d clusters in %dms",t,r.numItems,Date.now()-n)}e&&console.timeEnd("total time")}getClusters(t,e){return this.getClustersInternal(t,e).map((t=>h(t)))}getClustersInternal(t,e){let n=((t[0]+180)%360+360)%360-180;const o=Math.max(-90,Math.min(90,t[1]));let i=180===t[2]?180:((t[2]+180)%360+360)%360-180;const s=Math.max(-90,Math.min(90,t[3]));if(t[2]-t[0]>=360)n=-180,i=180;else if(n>i){const t=this.getClustersInternal([n,o,180,s],e),r=this.getClustersInternal([-180,o,i,s],e);return t.concat(r)}const r=this.trees[this.limitZoom(e)],a=r.range(l(n),c(s),l(i),c(o)),u=r.flatData,h=[];for(const t of a){const e=this.stride*t;h.push(u[e+B]>1?R(u,e,this.clusterProps):this.points[u[e+G]])}return h}getChildren(t){const e=this.getOriginId(t),n=this.getOriginZoom(t),o=new Error("No cluster with the specified id: "+t),i=this.trees[n];if(!i)throw o;const s=i.flatData;if(e*this.stride>=s.length)throw o;const r=this.options.radius/(this.options.extent*Math.pow(2,n-1)),a=s[e*this.stride],u=s[e*this.stride+1],l=i.within(a,u,r),c=[];for(const e of l){const n=e*this.stride;s[n+4]===t&&c.push(s[n+B]>1?V(s,n,this.clusterProps):h(this.points[s[n+G]]))}if(0===c.length)throw o;return c}getLeaves(t,e,n){e=e||10,n=n||0;const o=[];return this.appendLeaves(o,t,e,n,0),o}getTile(t,e,n){const o=this.trees[this.limitZoom(t)],i=Math.pow(2,t),{extent:s,radius:r}=this.options,a=r/s,u=(n-a)/i,l=(n+1+a)/i,c={transformed:!0,features:[],source:null,x:e,y:n,z:t};return this.addTileFeatures(o.range((e-a)/i,u,(e+1+a)/i,l),o.flatData,e,n,i,c),0===e&&this.addTileFeatures(o.range(1-a/i,u,1,l),o.flatData,i,n,i,c),e===i-1&&this.addTileFeatures(o.range(0,u,a/i,l),o.flatData,-1,n,i,c),c}getClusterExpansionZoom(t){return this.getOriginZoom(t)}appendLeaves(t,e,n,o,i){const s=this.getChildren(e);for(const e of s){const s=e.properties;if(s?.cluster?i+s.point_count<=o?i+=s.point_count:i=this.appendLeaves(t,s.cluster_id,n,o,i):i<o?i++:t.push(e),t.length===n)break}return i}createTree(t){const e=new F(t.length/this.stride|0,this.options.nodeSize,Float32Array);for(let n=0;n<t.length;n+=this.stride)e.add(t[n],t[n+1]);return e.finish(),e.flatData=t,e.data=null,e}addTileFeatures(t,e,n,o,i,s){for(const r of t){const t=r*this.stride,a=e[t+B]>1;let u,l,c;if(a)u=K(e,t,this.clusterProps),l=e[t],c=e[t+1];else{const n=this.points[e[t+G]];u=n.tags,[l,c]=n.geometry}const h={type:1,geometry:[[Math.round(this.options.extent*(l*i-n)),Math.round(this.options.extent*(c*i-o))]],tags:u};let d;d=a||this.options.generateId?e[t+G]:this.points[e[t+G]].id,void 0!==d&&(h.id=d),s.features.push(h)}}limitZoom(t){return Math.max(this.options.minZoom,Math.min(Math.floor(+t),this.options.maxZoom+1))}cluster(t,e){const{radius:n,extent:o,reduce:i,minPoints:s}=this.options,r=n/(o*Math.pow(2,e)),a=t.flatData,u=[],l=this.stride;for(let n=0;n<a.length;n+=l){if(a[n+2]<=e)continue;a[n+2]=e;const o=a[n],c=a[n+1],h=t.within(a[n],a[n+1],r),d=a[n+B];let p=d;for(const t of h){const n=t*l;a[n+2]>e&&(p+=a[n+B])}if(p>d&&p>=s){let t,s=o*d,r=c*d,f=-1;const g=(n/l<<5)+(e+1)+this.points.length;for(const o of h){const u=o*l;if(a[u+2]<=e)continue;a[u+2]=e;const c=a[u+B];s+=a[u]*c,r+=a[u+1]*c,a[u+4]=g,i&&(t||(t=this.map(a,n,!0),f=this.clusterProps.length,this.clusterProps.push(t)),i(t,this.map(a,u)))}a[n+4]=g,u.push(s/p,r/p,1/0,g,-1,p),i&&u.push(f)}else{for(let t=0;t<l;t++)u.push(a[n+t]);if(p>1)for(const t of h){const n=t*l;if(!(a[n+2]<=e)){a[n+2]=e;for(let t=0;t<l;t++)u.push(a[n+t])}}}}return u}getOriginId(t){return t-this.points.length>>5}getOriginZoom(t){return(t-this.points.length)%32}map(t,e,n){if(t[e+B]>1){const o=this.clusterProps[t[e+J]];return n?Object.assign({},o):o}const o=this.points[t[e+G]].tags,i=this.options.map(o);return n&&i===o?Object.assign({},i):i}}function R(t,e,n){return{id:t[e+G],type:"Point",tags:K(t,e,n),geometry:[t[e],t[e+1]]}}function V(t,e,n){return{type:"Feature",id:t[e+G],properties:K(t,e,n),geometry:{type:"Point",coordinates:[g(t[e]),m(t[e+1])]}}}function K(t,e,n){const o=t[e+B],i=o>=1e4?`${Math.round(o/1e3)}k`:o>=1e3?Math.round(o/100)/10+"k":o,s=t[e+J],r=-1===s?{}:Object.assign({},n[s]);return Object.assign(r,{cluster:!0,cluster_id:t[e+G],point_count:o,point_count_abbreviated:i})}const H="geojsonvt_clip_start",Q="geojsonvt_clip_end";function W(t,e,n,o,i){const s=e===i.maxZoom?0:i.tolerance/((1<<e)*i.extent),r={transformed:!1,features:[],source:null,x:n,y:o,z:e,minX:2,minY:1,maxX:-1,maxY:0,numPoints:0,numSimplified:0,numFeatures:t.length};for(const e of t)tt(r,e,s,i);return r}function tt(t,e,n,o){switch(t.minX=Math.min(t.minX,e.minX),t.minY=Math.min(t.minY,e.minY),t.maxX=Math.max(t.maxX,e.maxX),t.maxY=Math.max(t.maxY,e.maxY),e.type){case"Point":case"MultiPoint":return void function(t,e){const n=[];for(let o=0;o<e.geometry.length;o+=3)n.push(e.geometry[o],e.geometry[o+1]),t.numPoints++,t.numSimplified++;if(!n.length)return;const o={type:1,tags:e.tags||null,geometry:n};null!==e.id&&(o.id=e.id);t.features.push(o)}(t,e);case"LineString":return void function(t,e,n,o){const i=[];if(et(i,e.geometry,t,n,!1,!1),!i.length)return;let s=e.tags||null;if(o.lineMetrics){s={};for(const t in e.tags)s[t]=e.tags[t];s[H]=e.geometry.start/e.geometry.size,s[Q]=e.geometry.end/e.geometry.size}const r={type:2,tags:s,geometry:i};null!==e.id&&(r.id=e.id);t.features.push(r)}(t,e,n,o);case"MultiLineString":case"Polygon":return void function(t,e,n){const o=[];for(let i=0;i<e.geometry.length;i++)et(o,e.geometry[i],t,n,"Polygon"===e.type,0===i);if(!o.length)return;const i={type:"Polygon"===e.type?3:2,tags:e.tags||null,geometry:o};null!==e.id&&(i.id=e.id);t.features.push(i)}(t,e,n);case"MultiPolygon":return void function(t,e,n){const o=[];for(let i=0;i<e.geometry.length;i++){const s=e.geometry[i];for(let e=0;e<s.length;e++)et(o,s[e],t,n,!0,0===e)}if(!o.length)return;const i={type:3,tags:e.tags||null,geometry:o};null!==e.id&&(i.id=e.id);t.features.push(i)}(t,e,n)}}function et(t,e,n,o,i,s){const r=o*o;if(o>0&&e.size<(i?r:o))return void(n.numPoints+=e.length/3);const a=[];for(let t=0;t<e.length;t+=3)(0===o||e[t+2]>r)&&(n.numSimplified++,a.push(e[t],e[t+1])),n.numPoints++;i&&function(t,e){let n=0;for(let e=0,o=t.length,i=o-2;e<o;i=e,e+=2)n+=(t[e]-t[i])*(t[e+1]+t[i+1]);if(n>0!==e)return;for(let e=0,n=t.length;e<n/2;e+=2){const o=t[e],i=t[e+1];t[e]=t[n-2-e],t[e+1]=t[n-1-e],t[n-2-e]=o,t[n-1-e]=i}}(a,s),t.push(a)}function nt(t,e){if(t.transformed)return t;const n=1<<t.z,o=t.x,i=t.y;for(const s of t.features)1===s.type?ot(s,e,n,o,i):it(s,e,n,o,i);return t.transformed=!0,t}function ot(t,e,n,o,i){const s=t,r=t.geometry,a=[];for(let t=0;t<r.length;t+=2)a.push(st(r[t],r[t+1],e,n,o,i));return s.geometry=a,s}function it(t,e,n,o,i){const s=t,r=t.geometry,a=[];for(const t of r){const s=[];for(let r=0;r<t.length;r+=2)s.push(st(t[r],t[r+1],e,n,o,i));a.push(s)}return s.geometry=a,s}function st(t,e,n,o,i,s){return[Math.round(n*(t*o-i)),Math.round(n*(e*o-s))]}class rt{options;tileCoords;tiles;stats={};total=0;constructor(t){this.options=t,this.tiles={},this.tileCoords=[],this.stats={},this.total=0}initialize(t){this.splitTile(t,0,0,0),this.options.debug&&(t.length&&console.log("features: %d, points: %d",this.tiles[0].numFeatures,this.tiles[0].numPoints),console.timeEnd("generate tiles"),console.log("tiles generated:",this.total,JSON.stringify(this.stats)))}updateIndex(t,e,n){n.debug>1&&(console.log("invalidating tiles"),console.time("invalidating")),this.invalidateTiles(e),n.debug>1&&console.timeEnd("invalidating");const[o,i,s]=[0,0,0],r=W(t,o,i,s,n);r.source=t;const a=at(o,i,s);if(this.tiles[a]=r,this.tileCoords.push({z:o,x:i,y:s,id:a}),n.debug){const t=`z${o}`;this.stats[t]=(this.stats[t]||0)+1,this.total++}}getClusterExpansionZoom(t){return null}getChildren(t){return null}getLeaves(t,e,n){return null}getTile(t,e,n){const{extent:o,debug:i}=this.options,s=1<<t,r=at(t,e=e+s&s-1,n);if(this.tiles[r])return nt(this.tiles[r],o);i>1&&console.log("drilling down to z%d-%d-%d",t,e,n);let a,u=t,l=e,c=n;for(;!a&&u>0;)u--,l>>=1,c>>=1,a=this.tiles[at(u,l,c)];return a?.source?(i>1&&(console.log("found parent tile z%d-%d-%d",u,l,c),console.time("drilling down")),this.splitTile(a.source,u,l,c,t,e,n),i>1&&console.timeEnd("drilling down"),this.tiles[r]?nt(this.tiles[r],o):null):null}splitTile(t,e,n,o,i,s,r){const a=[t,e,n,o],u=this.options,l=u.debug;for(;a.length;){o=a.pop(),n=a.pop(),e=a.pop(),t=a.pop();const c=1<<e,h=at(e,n,o);let d=this.tiles[h];if(!d&&(l>1&&console.time("creation"),d=this.tiles[h]=W(t,e,n,o,u),this.tileCoords.push({z:e,x:n,y:o,id:h}),l)){l>1&&(console.log("tile z%d-%d-%d (features: %d, points: %d, simplified: %d)",e,n,o,d.numFeatures,d.numPoints,d.numSimplified),console.timeEnd("creation"));const t=`z${e}`;this.stats[t]=(this.stats[t]||0)+1,this.total++}if(d.source=t,null==i){if(e===u.indexMaxZoom||d.numPoints<=u.indexMaxPoints)continue}else{if(e===u.maxZoom||e===i)continue;if(null!=i){const t=i-e;if(n!==s>>t||o!==r>>t)continue}}if(d.source=null,!t.length)continue;l>1&&console.time("clipping");const p=.5*u.buffer/u.extent,f=.5-p,g=.5+p,m=1+p;let M=null,w=null,P=null,I=null;const v=x(t,c,n-p,n+g,y.X,d.minX,d.maxX,u),b=x(t,c,n+f,n+m,y.X,d.minX,d.maxX,u);v&&(M=x(v,c,o-p,o+g,y.Y,d.minY,d.maxY,u),w=x(v,c,o+f,o+m,y.Y,d.minY,d.maxY,u)),b&&(P=x(b,c,o-p,o+g,y.Y,d.minY,d.maxY,u),I=x(b,c,o+f,o+m,y.Y,d.minY,d.maxY,u)),l>1&&console.timeEnd("clipping"),a.push(M||[],e+1,2*n,2*o),a.push(w||[],e+1,2*n,2*o+1),a.push(P||[],e+1,2*n+1,2*o),a.push(I||[],e+1,2*n+1,2*o+1)}}invalidateTiles(t){if(!t.length)return;const e=this.options,{debug:n}=e;let o=1/0,i=-1/0,s=1/0,r=-1/0;for(const e of t)o=Math.min(o,e.minX),i=Math.max(i,e.maxX),s=Math.min(s,e.minY),r=Math.max(r,e.maxY);const a=e.buffer/e.extent,u=new Set;for(const e in this.tiles){const l=this.tiles[e],c=1<<l.z,h=(l.x-a)/c,d=(l.x+1+a)/c,p=(l.y-a)/c,f=(l.y+1+a)/c;if(i<h||o>=d||r<p||s>=f)continue;let g=!1;for(const e of t)if(e.maxX>=h&&e.minX<d&&e.maxY>=p&&e.minY<f){g=!0;break}if(g){if(n){n>1&&console.log("invalidate tile z%d-%d-%d (features: %d, points: %d, simplified: %d)",l.z,l.x,l.y,l.numFeatures,l.numPoints,l.numSimplified);const t=`z${l.z}`;this.stats[t]=(this.stats[t]||0)-1,this.total--}delete this.tiles[e],u.add(e)}}u.size&&(this.tileCoords=this.tileCoords.filter((t=>!u.has(t.id))))}}function at(t,e,n){return 32*((1<<t)*n+e)+t}const ut={maxZoom:14,indexMaxZoom:5,indexMaxPoints:1e5,tolerance:3,extent:4096,buffer:64,lineMetrics:!1,promoteId:null,generateId:!1,updateable:!1,cluster:!1,clusterOptions:$,debug:0};t.GEOJSONVT_CLIP_END=Q,t.GEOJSONVT_CLIP_START=H,t.GeoJSONVT=class{get tiles(){return this.tileIndex?.tiles??{}}get stats(){return this.tileIndex.stats}get total(){return this.tileIndex.total}options;source;tileIndex;constructor(t,e){const n=(e=this.options=Object.assign({},ut,e)).debug;if(n&&console.time("preprocess data"),e.maxZoom<0||e.maxZoom>24)throw new Error("maxZoom should be in the 0-24 range");if(e.promoteId&&e.generateId)throw new Error("promoteId and generateId cannot be used together.");let o=s(t,e);n&&(console.timeEnd("preprocess data"),console.log("index: maxZoom: %d, maxPoints: %d",e.indexMaxZoom,e.indexMaxPoints),console.time("generate tiles")),o=X(o,e),e.updateable&&(this.source=o),this.initializeIndex(o,e)}initializeIndex(t,e){this.tileIndex=e.cluster?new q(e.clusterOptions):new rt(e),t.length&&this.tileIndex.initialize(t)}getTile(t,e,n){return e=+e,n=+n,(t=+t)<0||t>24?null:this.tileIndex.getTile(t,e,n)}updateData(t,e){const n=this.options;if(!n.updateable)throw new Error("to update tile geojson `updateable` option must be set to true");let{affected:o,source:i}=L(this.source,t,n);e&&({affected:o,source:i}=this.filterUpdate(i,o,e)),o.length&&(this.source=i,this.tileIndex.updateIndex(i,o,n))}filterUpdate(t,e,n){const o=new Set;for(const i of t)null!=i.id&&(n(h(i))||(e.push(i),o.add(i.id)));return{affected:e,source:t=t.filter((t=>!o.has(t.id)))}}getData(){if(!this.options.updateable)throw new Error("to retrieve data the `updateable` option must be set to true");return{type:"FeatureCollection",features:this.source.map((t=>h(t)))}}updateClusterOptions(t,e){const n=this.options.cluster;this.options.cluster=t,this.options.clusterOptions=e,n!=t?this.initializeIndex(this.source,this.options):this.tileIndex.updateIndex(this.source,[],this.options)}getClusterExpansionZoom(t){return this.tileIndex.getClusterExpansionZoom(t)}getClusterChildren(t){return this.tileIndex.getChildren(t)}getClusterLeaves(t,e,n){return this.tileIndex.getLeaves(t,e,n)}},t.Supercluster=q,t.geoJSONToTile=function(t,e,n,o,i={}){i={...ut,...i};const{wrap:r=!1,clip:a=!1}=i;let u=s(t,i);if(r&&(u=X(u,i)),a||i.lineMetrics){const t=1<<e,s=i.buffer/i.extent,r=x(u,t,n-s,n+1+s,y.X,-1,2,i);u=x(r||[],t,o-s,o+1+s,y.Y,-1,2,i)}return nt(W(u??[],e,n,o,i),i.extent)}}));
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).geojsonvt={})}(this,(function(t){"use strict";function e(t,o,s,i){let r=i;const a=o+(s-o>>1);let u,l=s-o;const c=t[o],h=t[o+1],d=t[s],p=t[s+1];for(let e=o+3;e<s;e+=3){const o=n(t[e],t[e+1],c,h,d,p);if(o>r)u=e,r=o;else if(o===r){const t=Math.abs(e-a);t<l&&(u=e,l=t)}}r>i&&(u-o>3&&e(t,o,u,i),t[u+2]=r,s-u>3&&e(t,u,s,i))}function n(t,e,n,o,s,i){let r=s-n,a=i-o;if(0!==r||0!==a){const u=((t-n)*r+(e-o)*a)/(r*r+a*a);u>1?(n=s,o=i):u>0&&(n+=r*u,o+=a*u)}return r=t-n,a=e-o,r*r+a*a}function o(t,e,n,o){const i={type:e,geom:n},r={id:null==t?null:t,type:i.type,geometry:i.geom,tags:o,minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};switch(i.type){case"Point":case"MultiPoint":case"LineString":s(r,i.geom);break;case"Polygon":s(r,i.geom[0]);break;case"MultiLineString":for(const t of i.geom)s(r,t);break;case"MultiPolygon":for(const t of i.geom)s(r,t[0])}return r}function s(t,e){for(let n=0;n<e.length;n+=3)t.minX=Math.min(t.minX,e[n]),t.minY=Math.min(t.minY,e[n+1]),t.maxX=Math.max(t.maxX,e[n]),t.maxY=Math.max(t.maxY,e[n+1])}function i(t,e){const n=[];switch(t.type){case"FeatureCollection":for(let o=0;o<t.features.length;o++)r(n,t.features[o],e,o);break;case"Feature":r(n,t,e);break;default:r(n,{geometry:t,properties:void 0},e)}return n}function r(t,e,n,s){if(!e.geometry)return;if("GeometryCollection"===e.geometry.type)return void function(t,e,n,o,s){for(const i of n.geometries)r(t,{id:e.id,geometry:i,properties:e.properties},o,s)}(t,e,e.geometry,n,s);const i=e.geometry.coordinates;if(!i?.length)return;const h=function(t,e,n){if(e.promoteId)return t.properties?.[e.promoteId];if(e.generateId)return n||0;return t.id}(e,n,s),d=Math.pow(n.tolerance/((1<<n.maxZoom)*n.extent),2);switch(e.geometry.type){case"Point":return void function(t,e,n,s){const i=[];i.push(l(n.coordinates[0]),c(n.coordinates[1]),0),t.push(o(e,"Point",i,s))}(t,h,e.geometry,e.properties);case"MultiPoint":return void function(t,e,n,s){const i=[];for(const t of n.coordinates)i.push(l(t[0]),c(t[1]),0);t.push(o(e,"MultiPoint",i,s))}(t,h,e.geometry,e.properties);case"LineString":return void function(t,e,n,s,i){const r=[];a(n.coordinates,r,s,!1),t.push(o(e,"LineString",r,i))}(t,h,e.geometry,d,e.properties);case"MultiLineString":return void function(t,e,n,s,i,r){if(i.lineMetrics)for(const i of n.coordinates){const n=[];a(i,n,s,!1),t.push(o(e,"LineString",n,r))}else{const i=[];u(n.coordinates,i,s,!1),t.push(o(e,"MultiLineString",i,r))}}(t,h,e.geometry,d,n,e.properties);case"Polygon":return void function(t,e,n,s,i){const r=[];u(n.coordinates,r,s,!0),t.push(o(e,"Polygon",r,i))}(t,h,e.geometry,d,e.properties);case"MultiPolygon":return void function(t,e,n,s,i){const r=[];for(const t of n.coordinates){const e=[];u(t,e,s,!0),r.push(e)}t.push(o(e,"MultiPolygon",r,i))}(t,h,e.geometry,d,e.properties);default:throw new Error("Input data is not a valid GeoJSON object.")}}function a(t,n,o,s){let i,r,a=0;for(let e=0;e<t.length;e++){const o=l(t[e][0]),u=c(t[e][1]);n.push(o,u,0),e>0&&(a+=s?(i*u-o*r)/2:Math.sqrt(Math.pow(o-i,2)+Math.pow(u-r,2))),i=o,r=u}const u=n.length-3;n[2]=1,o>0&&e(n,0,u,o),n[u+2]=1,n.size=Math.abs(a),n.start=0,n.end=n.size}function u(t,e,n,o){for(let s=0;s<t.length;s++){const i=[];a(t[s],i,n,o),e.push(i)}}function l(t){return t/360+.5}function c(t){const e=Math.sin(t*Math.PI/180),n=.5-.25*Math.log((1+e)/(1-e))/Math.PI;return n<0?0:n>1?1:n}function h(t){const e={type:"Feature",geometry:d(t),properties:t.tags};return null!=t.id&&(e.id=t.id),e}function d(t){const{type:e,geometry:n}=t;switch(e){case"Point":return{type:e,coordinates:f(n[0],n[1])};case"MultiPoint":case"LineString":return{type:e,coordinates:p(n)};case"MultiLineString":case"Polygon":return{type:e,coordinates:n.map((t=>p(t)))};case"MultiPolygon":return{type:e,coordinates:n.map((t=>t.map((t=>p(t)))))}}}function p(t){const e=[];for(let n=0;n<t.length;n+=3)e.push(f(t[n],t[n+1]));return e}function f(t,e){return[g(t),m(e)]}function g(t){return 360*(t-.5)}function m(t){const e=(180-360*t)*Math.PI/180;return 360*Math.atan(Math.exp(e))/Math.PI-90}var y;function x(t,e,n,o,s,i,r,a){if(o/=e,i>=(n/=e)&&r<o)return t;if(r<n||i>=o)return null;const u=[];for(const e of t){const t=s===y.X?e.minX:e.minY,i=s===y.X?e.maxX:e.maxY;if(t>=n&&i<o)u.push(e);else if(!(i<n||t>=o))switch(e.type){case"Point":case"MultiPoint":M(e,u,n,o,s);continue;case"LineString":w(e,u,n,o,s,a);continue;case"MultiLineString":P(e,u,n,o,s);continue;case"Polygon":I(e,u,n,o,s);continue;case"MultiPolygon":v(e,u,n,o,s);continue}}return u.length?u:null}function M(t,e,n,s,i){const r=[];if(function(t,e,n,o,s){for(let i=0;i<t.length;i+=3){const r=t[i+s];r>=n&&r<=o&&A(e,t[i],t[i+1],t[i+2])}}(t.geometry,r,n,s,i),!r.length)return;const a=3===r.length?"Point":"MultiPoint";e.push(o(t.id,a,r,t.tags))}function w(t,e,n,s,i,r){const a=[];if(b(t.geometry,a,n,s,i,!1,r.lineMetrics),a.length)if(r.lineMetrics)for(const n of a)e.push(o(t.id,"LineString",n,t.tags));else a.length>1?e.push(o(t.id,"MultiLineString",a,t.tags)):e.push(o(t.id,"LineString",a[0],t.tags))}function P(t,e,n,s,i){const r=[];z(t.geometry,r,n,s,i,!1),r.length&&(1!==r.length?e.push(o(t.id,"MultiLineString",r,t.tags)):e.push(o(t.id,"LineString",r[0],t.tags)))}function I(t,e,n,s,i){const r=[];z(t.geometry,r,n,s,i,!0),r.length&&e.push(o(t.id,"Polygon",r,t.tags))}function v(t,e,n,s,i){const r=[];for(const e of t.geometry){const t=[];z(e,t,n,s,i,!0),t.length&&r.push(t)}r.length&&e.push(o(t.id,"MultiPolygon",r,t.tags))}function b(t,e,n,o,s,i,r){let a=S(t);const u=s===y.X?E:T;let l,c,h=t.start;for(let d=0;d<t.length-3;d+=3){const p=t[d],f=t[d+1],g=t[d+2],m=t[d+3],x=t[d+4],M=s===y.X?p:f,w=s===y.X?m:x;let P=!1;r&&(l=Math.sqrt(Math.pow(p-m,2)+Math.pow(f-x,2))),M<n?w>n&&(c=u(a,p,f,m,x,n),r&&(a.start=h+l*c)):M>o?w<o&&(c=u(a,p,f,m,x,o),r&&(a.start=h+l*c)):A(a,p,f,g),w<n&&M>=n&&(c=u(a,p,f,m,x,n),P=!0),w>o&&M<=o&&(c=u(a,p,f,m,x,o),P=!0),!i&&P&&(r&&(a.end=h+l*c),e.push(a),a=S(t)),r&&(h+=l)}let d=t.length-3;const p=t[d],f=t[d+1],g=t[d+2],m=s===y.X?p:f;m>=n&&m<=o&&A(a,p,f,g),d=a.length-3,i&&d>=3&&(a[d]!==a[0]||a[d+1]!==a[1])&&A(a,a[0],a[1],a[2]),a.length&&e.push(a)}function S(t){const e=[];return e.size=t.size,e.start=t.start,e.end=t.end,e}function z(t,e,n,o,s,i){for(const r of t)b(r,e,n,o,s,i,!1)}function A(t,e,n,o){t.push(e,n,o)}function E(t,e,n,o,s,i){const r=(i-e)/(o-e);return A(t,i,n+(s-n)*r,1),r}function T(t,e,n,o,s,i){const r=(i-n)/(s-n);return A(t,e+(o-e)*r,i,1),r}function X(t,e){const n=e.buffer/e.extent;let o=t;const s=x(t,1,-1-n,n,y.X,-1,2,e),i=x(t,1,1-n,2+n,y.X,-1,2,e);return s||i?(o=x(t,1,-n,1+n,y.X,-1,2,e)||[],s&&(o=Y(s,1).concat(o)),i&&(o=o.concat(Y(i,-1))),o):o}function Y(t,e){const n=[];for(const s of t)switch(s.type){case"Point":case"MultiPoint":case"LineString":{const t=C(s.geometry,e);n.push(o(s.id,s.type,t,s.tags));continue}case"MultiLineString":case"Polygon":{const t=[];for(const n of s.geometry)t.push(C(n,e));n.push(o(s.id,s.type,t,s.tags));continue}case"MultiPolygon":{const t=[];for(const n of s.geometry){const o=[];for(const t of n)o.push(C(t,e));t.push(o)}n.push(o(s.id,s.type,t,s.tags));continue}}return n}function C(t,e){const n=[];n.size=t.size,void 0!==t.start&&(n.start=t.start,n.end=t.end);for(let o=0;o<t.length;o+=3)n.push(t[o]+e,t[o+1],t[o+2]);return n}function L(t,e,n){const o=function(t){if(!t)return{remove:new Set,add:new Map,update:new Map};const e={removeAll:t.removeAll,remove:new Set(t.remove||[]),add:new Map(t.add?.map((t=>[t.id,t]))),update:new Map(t.update?.map((t=>[t.id,t])))};return e}(e);let s=[];if(o.removeAll&&(s=t,t=[]),o.remove.size||o.add.size){const e=[];for(const n of t)(o.remove.has(n.id)||o.add.has(n.id))&&e.push(n);if(e.length){s.push(...e);const n=new Set(e.map((t=>t.id)));t=t.filter((t=>!n.has(t.id)))}if(o.add.size){let e=i({type:"FeatureCollection",features:Array.from(o.add.values())},n);e=X(e,n),s.push(...e),t.push(...e)}}if(o.update.size)for(const[e,i]of o.update){const o=[],r=[];for(const n of t)n.id===e?o.push(n):r.push(n);if(!o.length)continue;const a=O(o,i,n);a.length&&(s.push(...o,...a),r.push(...a),t=r)}return{affected:s,source:t}}function O(t,e,n){const o=!!e.newGeometry,s=e.removeAllProperties||e.removeProperties?.length>0||e.addOrUpdateProperties?.length>0;if(o){const o=t[0];let r=i({type:"FeatureCollection",features:[{type:"Feature",id:o.id,geometry:e.newGeometry,properties:s?_(o.tags,e):o.tags}]},n);return r=X(r,n),r}if(s){const n=[];for(const o of t){const t={...o};t.tags=_(t.tags,e),n.push(t)}return n}return[]}function _(t,e){if(e.removeAllProperties)return{};const n={...t||{}};if(e.removeProperties)for(const t of e.removeProperties)delete n[t];if(e.addOrUpdateProperties)for(const{key:t,value:o}of e.addOrUpdateProperties)n[t]=o;return n}!function(t){t[t.X=0]="X",t[t.Y=1]="Y"}(y||(y={}));const Z=[Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];class F{static from(t){if(!(t instanceof ArrayBuffer))throw new Error("Data must be an instance of ArrayBuffer.");const[e,n]=new Uint8Array(t,0,2);if(219!==e)throw new Error("Data does not appear to be in a KDBush format.");const o=n>>4;if(1!==o)throw new Error(`Got v${o} data when expected v1.`);const s=Z[15&n];if(!s)throw new Error("Unrecognized array type.");const[i]=new Uint16Array(t,2,1),[r]=new Uint32Array(t,4,1);return new F(r,i,s,t)}constructor(t,e=64,n=Float64Array,o){if(isNaN(t)||t<0)throw new Error(`Unpexpected numItems value: ${t}.`);this.numItems=+t,this.nodeSize=Math.min(Math.max(+e,2),65535),this.ArrayType=n,this.IndexArrayType=t<65536?Uint16Array:Uint32Array;const s=Z.indexOf(this.ArrayType),i=2*t*this.ArrayType.BYTES_PER_ELEMENT,r=t*this.IndexArrayType.BYTES_PER_ELEMENT,a=(8-r%8)%8;if(s<0)throw new Error(`Unexpected typed array class: ${n}.`);o&&o instanceof ArrayBuffer?(this.data=o,this.ids=new this.IndexArrayType(this.data,8,t),this.coords=new this.ArrayType(this.data,8+r+a,2*t),this._pos=2*t,this._finished=!0):(this.data=new ArrayBuffer(8+i+r+a),this.ids=new this.IndexArrayType(this.data,8,t),this.coords=new this.ArrayType(this.data,8+r+a,2*t),this._pos=0,this._finished=!1,new Uint8Array(this.data,0,2).set([219,16+s]),new Uint16Array(this.data,2,1)[0]=e,new Uint32Array(this.data,4,1)[0]=t)}add(t,e){const n=this._pos>>1;return this.ids[n]=n,this.coords[this._pos++]=t,this.coords[this._pos++]=e,n}finish(){const t=this._pos>>1;if(t!==this.numItems)throw new Error(`Added ${t} items when expected ${this.numItems}.`);return U(this.ids,this.coords,this.nodeSize,0,this.numItems-1,0),this._finished=!0,this}range(t,e,n,o){if(!this._finished)throw new Error("Data not yet indexed - call index.finish().");const{ids:s,coords:i,nodeSize:r}=this,a=[0,s.length-1,0],u=[];for(;a.length;){const l=a.pop()||0,c=a.pop()||0,h=a.pop()||0;if(c-h<=r){for(let r=h;r<=c;r++){const a=i[2*r],l=i[2*r+1];a>=t&&a<=n&&l>=e&&l<=o&&u.push(s[r])}continue}const d=h+c>>1,p=i[2*d],f=i[2*d+1];p>=t&&p<=n&&f>=e&&f<=o&&u.push(s[d]),(0===l?t<=p:e<=f)&&(a.push(h),a.push(d-1),a.push(1-l)),(0===l?n>=p:o>=f)&&(a.push(d+1),a.push(c),a.push(1-l))}return u}within(t,e,n){if(!this._finished)throw new Error("Data not yet indexed - call index.finish().");const{ids:o,coords:s,nodeSize:i}=this,r=[0,o.length-1,0],a=[],u=n*n;for(;r.length;){const l=r.pop()||0,c=r.pop()||0,h=r.pop()||0;if(c-h<=i){for(let n=h;n<=c;n++)k(s[2*n],s[2*n+1],t,e)<=u&&a.push(o[n]);continue}const d=h+c>>1,p=s[2*d],f=s[2*d+1];k(p,f,t,e)<=u&&a.push(o[d]),(0===l?t-n<=p:e-n<=f)&&(r.push(h),r.push(d-1),r.push(1-l)),(0===l?t+n>=p:e+n>=f)&&(r.push(d+1),r.push(c),r.push(1-l))}return a}}function U(t,e,n,o,s,i){if(s-o<=n)return;const r=o+s>>1;D(t,e,r,o,s,i),U(t,e,n,o,r-1,1-i),U(t,e,n,r+1,s,1-i)}function D(t,e,n,o,s,i){for(;s>o;){if(s-o>600){const r=s-o+1,a=n-o+1,u=Math.log(r),l=.5*Math.exp(2*u/3),c=.5*Math.sqrt(u*l*(r-l)/r)*(a-r/2<0?-1:1);D(t,e,n,Math.max(o,Math.floor(n-a*l/r+c)),Math.min(s,Math.floor(n+(r-a)*l/r+c)),i)}const r=e[2*n+i];let a=o,u=s;for(j(t,e,o,n),e[2*s+i]>r&&j(t,e,o,s);a<u;){for(j(t,e,a,u),a++,u--;e[2*a+i]<r;)a++;for(;e[2*u+i]>r;)u--}e[2*o+i]===r?j(t,e,o,u):(u++,j(t,e,u,s)),u<=n&&(o=u+1),n<=u&&(s=u-1)}}function j(t,e,n,o){N(t,n,o),N(e,2*n,2*o),N(e,2*n+1,2*o+1)}function N(t,e,n){const o=t[e];t[e]=t[n],t[n]=o}function k(t,e,n,o){const s=t-n,i=e-o;return s*s+i*i}const $={minZoom:0,maxZoom:16,minPoints:2,radius:40,extent:512,nodeSize:64,log:!1,generateId:!1,reduce:null,map:t=>t},G=3,B=5,J=6;class q{options;trees;stride;clusterProps;points;constructor(t){this.options=Object.assign(Object.create($),t),this.trees=new Array(this.options.maxZoom+1),this.stride=this.options.reduce?7:6,this.clusterProps=[],this.points=[]}load(t){const e=[];for(const n of t){if(!n.geometry)continue;const[t,o]=n.geometry.coordinates,[s,i]=[l(t),c(o)],r={id:n.id,type:"Point",geometry:[s,i],tags:n.properties};e.push(r)}this.createIndex(e)}initialize(t){const e=[];for(const n of t)"Point"===n.type&&e.push(n);this.createIndex(e)}updateIndex(t,e,n){this.options=Object.assign(Object.create($),n.clusterOptions),this.initialize(t)}createIndex(t){const{log:e,minZoom:n,maxZoom:o}=this.options;e&&console.time("total time");const s=`prepare ${t.length} points`;e&&console.time(s),this.points=t;const i=[];for(let e=0;e<t.length;e++){const n=t[e];if(!n?.geometry)continue;let[o,s]=n.geometry;o=Math.fround(o),s=Math.fround(s),i.push(o,s,1/0,e,-1,1),this.options.reduce&&i.push(0)}let r=this.trees[o+1]=this.createTree(i);e&&console.timeEnd(s);for(let t=o;t>=n;t--){const n=Date.now();r=this.trees[t]=this.createTree(this.cluster(r,t)),e&&console.log("z%d: %d clusters in %dms",t,r.numItems,Date.now()-n)}e&&console.timeEnd("total time")}getClusters(t,e){return this.getClustersInternal(t,e).map((t=>h(t)))}getClustersInternal(t,e){let n=((t[0]+180)%360+360)%360-180;const o=Math.max(-90,Math.min(90,t[1]));let s=180===t[2]?180:((t[2]+180)%360+360)%360-180;const i=Math.max(-90,Math.min(90,t[3]));if(t[2]-t[0]>=360)n=-180,s=180;else if(n>s){const t=this.getClustersInternal([n,o,180,i],e),r=this.getClustersInternal([-180,o,s,i],e);return t.concat(r)}const r=this.trees[this.limitZoom(e)],a=r.range(l(n),c(i),l(s),c(o)),u=r.flatData,h=[];for(const t of a){const e=this.stride*t;h.push(u[e+B]>1?R(u,e,this.clusterProps):this.points[u[e+G]])}return h}getChildren(t){const e=this.getOriginId(t),n=this.getOriginZoom(t),o=new Error("No cluster with the specified id: "+t),s=this.trees[n];if(!s)throw o;const i=s.flatData;if(e*this.stride>=i.length)throw o;const r=this.options.radius/(this.options.extent*Math.pow(2,n-1)),a=i[e*this.stride],u=i[e*this.stride+1],l=s.within(a,u,r),c=[];for(const e of l){const n=e*this.stride;i[n+4]===t&&c.push(i[n+B]>1?V(i,n,this.clusterProps):h(this.points[i[n+G]]))}if(0===c.length)throw o;return c}getLeaves(t,e,n){e=e||10,n=n||0;const o=[];return this.appendLeaves(o,t,e,n,0),o}getTile(t,e,n){const o=this.trees[this.limitZoom(t)];if(!o)return null;const s=Math.pow(2,t),{extent:i,radius:r}=this.options,a=r/i,u=(n-a)/s,l=(n+1+a)/s,c={transformed:!0,features:[],source:null,x:e,y:n,z:t};return this.addTileFeatures(o.range((e-a)/s,u,(e+1+a)/s,l),o.flatData,e,n,s,c),0===e&&this.addTileFeatures(o.range(1-a/s,u,1,l),o.flatData,s,n,s,c),e===s-1&&this.addTileFeatures(o.range(0,u,a/s,l),o.flatData,-1,n,s,c),c}getClusterExpansionZoom(t){return this.getOriginZoom(t)}appendLeaves(t,e,n,o,s){const i=this.getChildren(e);for(const e of i){const i=e.properties;if(i?.cluster?s+i.point_count<=o?s+=i.point_count:s=this.appendLeaves(t,i.cluster_id,n,o,s):s<o?s++:t.push(e),t.length===n)break}return s}createTree(t){const e=new F(t.length/this.stride|0,this.options.nodeSize,Float32Array);for(let n=0;n<t.length;n+=this.stride)e.add(t[n],t[n+1]);return e.finish(),e.flatData=t,e.data=null,e}addTileFeatures(t,e,n,o,s,i){for(const r of t){const t=r*this.stride,a=e[t+B]>1;let u,l,c;if(a)u=K(e,t,this.clusterProps),l=e[t],c=e[t+1];else{const n=this.points[e[t+G]];u=n.tags,[l,c]=n.geometry}const h={type:1,geometry:[[Math.round(this.options.extent*(l*s-n)),Math.round(this.options.extent*(c*s-o))]],tags:u};let d;d=a||this.options.generateId?e[t+G]:this.points[e[t+G]].id,void 0!==d&&(h.id=d),i.features.push(h)}}limitZoom(t){return Math.max(this.options.minZoom,Math.min(Math.floor(+t),this.options.maxZoom+1))}cluster(t,e){const{radius:n,extent:o,reduce:s,minPoints:i}=this.options,r=n/(o*Math.pow(2,e)),a=t.flatData,u=[],l=this.stride;for(let n=0;n<a.length;n+=l){if(a[n+2]<=e)continue;a[n+2]=e;const o=a[n],c=a[n+1],h=t.within(a[n],a[n+1],r),d=a[n+B];let p=d;for(const t of h){const n=t*l;a[n+2]>e&&(p+=a[n+B])}if(p>d&&p>=i){let t,i=o*d,r=c*d,f=-1;const g=(n/l<<5)+(e+1)+this.points.length;for(const o of h){const u=o*l;if(a[u+2]<=e)continue;a[u+2]=e;const c=a[u+B];i+=a[u]*c,r+=a[u+1]*c,a[u+4]=g,s&&(t||(t=this.map(a,n,!0),f=this.clusterProps.length,this.clusterProps.push(t)),s(t,this.map(a,u)))}a[n+4]=g,u.push(i/p,r/p,1/0,g,-1,p),s&&u.push(f)}else{for(let t=0;t<l;t++)u.push(a[n+t]);if(p>1)for(const t of h){const n=t*l;if(!(a[n+2]<=e)){a[n+2]=e;for(let t=0;t<l;t++)u.push(a[n+t])}}}}return u}getOriginId(t){return t-this.points.length>>5}getOriginZoom(t){return(t-this.points.length)%32}map(t,e,n){if(t[e+B]>1){const o=this.clusterProps[t[e+J]];return n?Object.assign({},o):o}const o=this.points[t[e+G]].tags,s=this.options.map(o);return n&&s===o?Object.assign({},s):s}}function R(t,e,n){return{id:t[e+G],type:"Point",tags:K(t,e,n),geometry:[t[e],t[e+1]]}}function V(t,e,n){return{type:"Feature",id:t[e+G],properties:K(t,e,n),geometry:{type:"Point",coordinates:[g(t[e]),m(t[e+1])]}}}function K(t,e,n){const o=t[e+B],s=o>=1e4?`${Math.round(o/1e3)}k`:o>=1e3?Math.round(o/100)/10+"k":o,i=t[e+J],r=-1===i?{}:Object.assign({},n[i]);return Object.assign(r,{cluster:!0,cluster_id:t[e+G],point_count:o,point_count_abbreviated:s})}const H="geojsonvt_clip_start",Q="geojsonvt_clip_end";function W(t,e,n,o,s){const i=e===s.maxZoom?0:s.tolerance/((1<<e)*s.extent),r={transformed:!1,features:[],source:null,x:n,y:o,z:e,minX:2,minY:1,maxX:-1,maxY:0,numPoints:0,numSimplified:0,numFeatures:t.length};for(const e of t)tt(r,e,i,s);return r}function tt(t,e,n,o){switch(t.minX=Math.min(t.minX,e.minX),t.minY=Math.min(t.minY,e.minY),t.maxX=Math.max(t.maxX,e.maxX),t.maxY=Math.max(t.maxY,e.maxY),e.type){case"Point":case"MultiPoint":return void function(t,e){const n=[];for(let o=0;o<e.geometry.length;o+=3)n.push(e.geometry[o],e.geometry[o+1]),t.numPoints++,t.numSimplified++;if(!n.length)return;const o={type:1,tags:e.tags||null,geometry:n};null!==e.id&&(o.id=e.id);t.features.push(o)}(t,e);case"LineString":return void function(t,e,n,o){const s=[];if(et(s,e.geometry,t,n,!1,!1),!s.length)return;let i=e.tags||null;if(o.lineMetrics){i={};for(const t in e.tags)i[t]=e.tags[t];i[H]=e.geometry.start/e.geometry.size,i[Q]=e.geometry.end/e.geometry.size}const r={type:2,tags:i,geometry:s};null!==e.id&&(r.id=e.id);t.features.push(r)}(t,e,n,o);case"MultiLineString":case"Polygon":return void function(t,e,n){const o=[];for(let s=0;s<e.geometry.length;s++)et(o,e.geometry[s],t,n,"Polygon"===e.type,0===s);if(!o.length)return;const s={type:"Polygon"===e.type?3:2,tags:e.tags||null,geometry:o};null!==e.id&&(s.id=e.id);t.features.push(s)}(t,e,n);case"MultiPolygon":return void function(t,e,n){const o=[];for(let s=0;s<e.geometry.length;s++){const i=e.geometry[s];for(let e=0;e<i.length;e++)et(o,i[e],t,n,!0,0===e)}if(!o.length)return;const s={type:3,tags:e.tags||null,geometry:o};null!==e.id&&(s.id=e.id);t.features.push(s)}(t,e,n)}}function et(t,e,n,o,s,i){const r=o*o;if(o>0&&e.size<(s?r:o))return void(n.numPoints+=e.length/3);const a=[];for(let t=0;t<e.length;t+=3)(0===o||e[t+2]>r)&&(n.numSimplified++,a.push(e[t],e[t+1])),n.numPoints++;s&&function(t,e){let n=0;for(let e=0,o=t.length,s=o-2;e<o;s=e,e+=2)n+=(t[e]-t[s])*(t[e+1]+t[s+1]);if(n>0!==e)return;for(let e=0,n=t.length;e<n/2;e+=2){const o=t[e],s=t[e+1];t[e]=t[n-2-e],t[e+1]=t[n-1-e],t[n-2-e]=o,t[n-1-e]=s}}(a,i),t.push(a)}function nt(t,e){if(t.transformed)return t;const n=1<<t.z,o=t.x,s=t.y;for(const i of t.features)1===i.type?ot(i,e,n,o,s):st(i,e,n,o,s);return t.transformed=!0,t}function ot(t,e,n,o,s){const i=t,r=t.geometry,a=[];for(let t=0;t<r.length;t+=2)a.push(it(r[t],r[t+1],e,n,o,s));return i.geometry=a,i}function st(t,e,n,o,s){const i=t,r=t.geometry,a=[];for(const t of r){const i=[];for(let r=0;r<t.length;r+=2)i.push(it(t[r],t[r+1],e,n,o,s));a.push(i)}return i.geometry=a,i}function it(t,e,n,o,s,i){return[Math.round(n*(t*o-s)),Math.round(n*(e*o-i))]}class rt{options;tileCoords;tiles;stats={};total=0;constructor(t){this.options=t,this.tiles={},this.tileCoords=[],this.stats={},this.total=0}initialize(t){this.splitTile(t,0,0,0),this.options.debug&&(t.length&&console.log("features: %d, points: %d",this.tiles[0].numFeatures,this.tiles[0].numPoints),console.timeEnd("generate tiles"),console.log("tiles generated:",this.total,JSON.stringify(this.stats)))}updateIndex(t,e,n){n.debug>1&&(console.log("invalidating tiles"),console.time("invalidating")),this.invalidateTiles(e),n.debug>1&&console.timeEnd("invalidating");const[o,s,i]=[0,0,0],r=W(t,o,s,i,n);r.source=t;const a=at(o,s,i);if(this.tiles[a]=r,this.tileCoords.push({z:o,x:s,y:i,id:a}),n.debug){const t=`z${o}`;this.stats[t]=(this.stats[t]||0)+1,this.total++}}getClusterExpansionZoom(t){return null}getChildren(t){return null}getLeaves(t,e,n){return null}getTile(t,e,n){const{extent:o,debug:s}=this.options,i=1<<t,r=at(t,e=e+i&i-1,n);if(this.tiles[r])return nt(this.tiles[r],o);s>1&&console.log("drilling down to z%d-%d-%d",t,e,n);let a,u=t,l=e,c=n;for(;!a&&u>0;)u--,l>>=1,c>>=1,a=this.tiles[at(u,l,c)];return a?.source?(s>1&&(console.log("found parent tile z%d-%d-%d",u,l,c),console.time("drilling down")),this.splitTile(a.source,u,l,c,t,e,n),s>1&&console.timeEnd("drilling down"),this.tiles[r]?nt(this.tiles[r],o):null):null}splitTile(t,e,n,o,s,i,r){const a=[t,e,n,o],u=this.options,l=u.debug;for(;a.length;){o=a.pop(),n=a.pop(),e=a.pop(),t=a.pop();const c=1<<e,h=at(e,n,o);let d=this.tiles[h];if(!d&&(l>1&&console.time("creation"),d=this.tiles[h]=W(t,e,n,o,u),this.tileCoords.push({z:e,x:n,y:o,id:h}),l)){l>1&&(console.log("tile z%d-%d-%d (features: %d, points: %d, simplified: %d)",e,n,o,d.numFeatures,d.numPoints,d.numSimplified),console.timeEnd("creation"));const t=`z${e}`;this.stats[t]=(this.stats[t]||0)+1,this.total++}if(d.source=t,null==s){if(e===u.indexMaxZoom||d.numPoints<=u.indexMaxPoints)continue}else{if(e===u.maxZoom||e===s)continue;if(null!=s){const t=s-e;if(n!==i>>t||o!==r>>t)continue}}if(d.source=null,!t.length)continue;l>1&&console.time("clipping");const p=.5*u.buffer/u.extent,f=.5-p,g=.5+p,m=1+p;let M=null,w=null,P=null,I=null;const v=x(t,c,n-p,n+g,y.X,d.minX,d.maxX,u),b=x(t,c,n+f,n+m,y.X,d.minX,d.maxX,u);v&&(M=x(v,c,o-p,o+g,y.Y,d.minY,d.maxY,u),w=x(v,c,o+f,o+m,y.Y,d.minY,d.maxY,u)),b&&(P=x(b,c,o-p,o+g,y.Y,d.minY,d.maxY,u),I=x(b,c,o+f,o+m,y.Y,d.minY,d.maxY,u)),l>1&&console.timeEnd("clipping"),a.push(M||[],e+1,2*n,2*o),a.push(w||[],e+1,2*n,2*o+1),a.push(P||[],e+1,2*n+1,2*o),a.push(I||[],e+1,2*n+1,2*o+1)}}invalidateTiles(t){if(!t.length)return;const e=this.options,{debug:n}=e;let o=1/0,s=-1/0,i=1/0,r=-1/0;for(const e of t)o=Math.min(o,e.minX),s=Math.max(s,e.maxX),i=Math.min(i,e.minY),r=Math.max(r,e.maxY);const a=e.buffer/e.extent,u=new Set;for(const e in this.tiles){const l=this.tiles[e],c=1<<l.z,h=(l.x-a)/c,d=(l.x+1+a)/c,p=(l.y-a)/c,f=(l.y+1+a)/c;if(s<h||o>=d||r<p||i>=f)continue;let g=!1;for(const e of t)if(e.maxX>=h&&e.minX<d&&e.maxY>=p&&e.minY<f){g=!0;break}if(g){if(n){n>1&&console.log("invalidate tile z%d-%d-%d (features: %d, points: %d, simplified: %d)",l.z,l.x,l.y,l.numFeatures,l.numPoints,l.numSimplified);const t=`z${l.z}`;this.stats[t]=(this.stats[t]||0)-1,this.total--}delete this.tiles[e],u.add(e)}}u.size&&(this.tileCoords=this.tileCoords.filter((t=>!u.has(t.id))))}}function at(t,e,n){return 32*((1<<t)*n+e)+t}const ut={maxZoom:14,indexMaxZoom:5,indexMaxPoints:1e5,tolerance:3,extent:4096,buffer:64,lineMetrics:!1,promoteId:null,generateId:!1,updateable:!1,cluster:!1,clusterOptions:$,debug:0};t.GEOJSONVT_CLIP_END=Q,t.GEOJSONVT_CLIP_START=H,t.GeoJSONVT=class{get tiles(){return this.tileIndex?.tiles??{}}get stats(){return this.tileIndex.stats}get total(){return this.tileIndex.total}options;source;tileIndex;constructor(t,e){const n=(e=this.options=Object.assign({},ut,e)).debug;if(n&&console.time("preprocess data"),e.maxZoom<0||e.maxZoom>24)throw new Error("maxZoom should be in the 0-24 range");if(e.promoteId&&e.generateId)throw new Error("promoteId and generateId cannot be used together.");let o=i(t,e);n&&(console.timeEnd("preprocess data"),console.log("index: maxZoom: %d, maxPoints: %d",e.indexMaxZoom,e.indexMaxPoints),console.time("generate tiles")),o=X(o,e),e.updateable&&(this.source=o),this.initializeIndex(o,e)}initializeIndex(t,e){this.tileIndex=e.cluster?new q(e.clusterOptions):new rt(e),t.length&&this.tileIndex.initialize(t)}getTile(t,e,n){return e=+e,n=+n,(t=+t)<0||t>24?null:this.tileIndex.getTile(t,e,n)}updateData(t,e){const n=this.options;if(!n.updateable)throw new Error("to update tile geojson `updateable` option must be set to true");let{affected:o,source:s}=L(this.source,t,n);e&&({affected:o,source:s}=this.filterUpdate(s,o,e)),o.length&&(this.source=s,this.tileIndex.updateIndex(s,o,n))}filterUpdate(t,e,n){const o=new Set;for(const s of t)null!=s.id&&(n(h(s))||(e.push(s),o.add(s.id)));return{affected:e,source:t=t.filter((t=>!o.has(t.id)))}}getData(){if(!this.options.updateable)throw new Error("to retrieve data the `updateable` option must be set to true");return{type:"FeatureCollection",features:this.source.map((t=>h(t)))}}updateClusterOptions(t,e){const n=this.options.cluster;this.options.cluster=t,this.options.clusterOptions=e,n!=t?this.initializeIndex(this.source,this.options):this.tileIndex.updateIndex(this.source,[],this.options)}getClusterExpansionZoom(t){return this.tileIndex.getClusterExpansionZoom(t)}getClusterChildren(t){return this.tileIndex.getChildren(t)}getClusterLeaves(t,e,n){return this.tileIndex.getLeaves(t,e,n)}},t.Supercluster=q,t.geoJSONToTile=function(t,e,n,o,s={}){s={...ut,...s};const{wrap:r=!1,clip:a=!1}=s;let u=i(t,s);if(r&&(u=X(u,s)),a||s.lineMetrics){const t=1<<e,i=s.buffer/s.extent,r=x(u,t,n-i,n+1+i,y.X,-1,2,s);u=x(r||[],t,o-i,o+1+i,y.Y,-1,2,s)}return nt(W(u??[],e,n,o,s),s.extent)}}));
@@ -676,89 +676,92 @@ function shiftCoords(points, offset) {
676
676
  function applySourceDiff(source, dataDiff, options) {
677
677
  // convert diff to sets/maps for o(1) lookups
678
678
  const diff = diffToHashed(dataDiff);
679
- // collection for features that will be affected by this update
679
+ // collection for features that will be affected by this update and used to invalidate tiles
680
680
  let affected = [];
681
- // full removal - clear everything before applying diff
682
681
  if (diff.removeAll) {
683
682
  affected = source;
684
683
  source = [];
685
684
  }
686
- // remove/add features and collect affected ones
687
685
  if (diff.remove.size || diff.add.size) {
688
686
  const removeFeatures = [];
689
- // collect source features to be removed
687
+ // Collect features to remove (explicit removals + replacements via add)
690
688
  for (const feature of source) {
691
- const { id } = feature;
692
- // explicit feature removal
693
- if (diff.remove.has(id)) {
694
- removeFeatures.push(feature);
695
- // feature with duplicate id being added
696
- }
697
- else if (diff.add.has(id)) {
689
+ if (diff.remove.has(feature.id) || diff.add.has(feature.id)) {
698
690
  removeFeatures.push(feature);
699
691
  }
700
692
  }
701
- // collect affected and remove from source
702
693
  if (removeFeatures.length) {
703
694
  affected.push(...removeFeatures);
704
695
  const removeIds = new Set(removeFeatures.map(f => f.id));
705
696
  source = source.filter(f => !removeIds.has(f.id));
706
697
  }
707
- // convert and add new features
708
698
  if (diff.add.size) {
709
- // projects and adds simplification info
710
699
  let addFeatures = convertToInternal({ type: 'FeatureCollection', features: Array.from(diff.add.values()) }, options);
711
- // wraps features (ie extreme west and extreme east)
712
700
  addFeatures = wrap(addFeatures, options);
713
701
  affected.push(...addFeatures);
714
702
  source.push(...addFeatures);
715
703
  }
716
704
  }
717
705
  if (diff.update.size) {
706
+ // Features can be duplicated across the antimeridian (wrap) in a single tile, so must update all instances with the same id
718
707
  for (const [id, update] of diff.update) {
719
- const featureIndex = source.findIndex(f => f.id === id);
720
- if (featureIndex === -1)
708
+ const oldFeatures = [];
709
+ const keepFeatures = [];
710
+ for (const feature of source) {
711
+ if (feature.id === id) {
712
+ oldFeatures.push(feature);
713
+ }
714
+ else {
715
+ keepFeatures.push(feature);
716
+ }
717
+ }
718
+ if (!oldFeatures.length)
721
719
  continue;
722
- const feature = source[featureIndex];
723
- // get updated geojsonvt simplified feature
724
- const updatedFeature = getUpdatedFeature(feature, update, options);
725
- if (!updatedFeature)
720
+ const updatedFeatures = getUpdatedFeatures(oldFeatures, update, options);
721
+ if (!updatedFeatures.length)
726
722
  continue;
727
- // track both features for invalidation
728
- affected.push(feature, updatedFeature);
729
- // replace old feature with updated feature
730
- source[featureIndex] = updatedFeature;
723
+ affected.push(...oldFeatures, ...updatedFeatures);
724
+ keepFeatures.push(...updatedFeatures);
725
+ source = keepFeatures;
731
726
  }
732
727
  }
733
728
  return { affected, source };
734
729
  }
735
- // return an updated geojsonvt simplified feature
736
- function getUpdatedFeature(vtFeature, update, options) {
730
+ /**
731
+ * Gets updated simplified feature(s) based on a diff update object.
732
+ * @param vtFeatures - the original features
733
+ * @param update - the update object to apply
734
+ * @param options - the options to use for the wrap method
735
+ * @returns Updated features. If geometry is updated, returns new feature(s) converted from geojson and wrapped. If only properties are updated, returns feature(s) with tags updated.
736
+ */
737
+ function getUpdatedFeatures(vtFeatures, update, options) {
737
738
  const changeGeometry = !!update.newGeometry;
738
739
  const changeProps = update.removeAllProperties ||
739
740
  update.removeProperties?.length > 0 ||
740
741
  update.addOrUpdateProperties?.length > 0;
741
- // if geometry changed, need to create new geojson feature and convert to simplified format
742
+ // if geometry changed, need to create a new geojson feature and convert to internal format
742
743
  if (changeGeometry) {
744
+ const vtFeature = vtFeatures[0];
743
745
  const geojsonFeature = {
744
746
  type: 'Feature',
745
747
  id: vtFeature.id,
746
748
  geometry: update.newGeometry,
747
749
  properties: changeProps ? applyPropertyUpdates(vtFeature.tags, update) : vtFeature.tags
748
750
  };
749
- // projects and adds simplification info
750
751
  let features = convertToInternal({ type: 'FeatureCollection', features: [geojsonFeature] }, options);
751
- // wraps features (ie extreme west and extreme east)
752
752
  features = wrap(features, options);
753
- return features[0];
753
+ return features;
754
754
  }
755
- // only properties changed - update tags directly
756
755
  if (changeProps) {
757
- const feature = { ...vtFeature };
758
- feature.tags = applyPropertyUpdates(feature.tags, update);
759
- return feature;
756
+ const updated = [];
757
+ for (const vtFeature of vtFeatures) {
758
+ const feature = { ...vtFeature };
759
+ feature.tags = applyPropertyUpdates(feature.tags, update);
760
+ updated.push(feature);
761
+ }
762
+ return updated;
760
763
  }
761
- return null;
764
+ return [];
762
765
  }
763
766
  /**
764
767
  * helper to apply property updates from a diff update object to a properties object
@@ -1003,6 +1006,9 @@ class ClusterTileIndex {
1003
1006
  */
1004
1007
  getTile(z, x, y) {
1005
1008
  const tree = this.trees[this.limitZoom(z)];
1009
+ if (!tree) {
1010
+ return null;
1011
+ }
1006
1012
  const z2 = Math.pow(2, z);
1007
1013
  const { extent, radius } = this.options;
1008
1014
  const p = radius / extent;