@maplibre/geojson-vt 6.0.2 → 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.
- package/dist/difference.d.ts +11 -4
- package/dist/difference.d.ts.map +1 -1
- package/dist/geojson-vt-dev.js +39 -36
- package/dist/geojson-vt.js +1 -1
- package/dist/geojson-vt.mjs +39 -36
- package/dist/geojson-vt.mjs.map +1 -1
- package/package.json +1 -1
- package/src/difference.ts +51 -46
package/dist/difference.d.ts
CHANGED
|
@@ -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
|
*/
|
package/dist/difference.d.ts.map
CHANGED
|
@@ -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
|
|
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"}
|
package/dist/geojson-vt-dev.js
CHANGED
|
@@ -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
|
-
//
|
|
691
|
+
// Collect features to remove (explicit removals + replacements via add)
|
|
694
692
|
for (const feature of source) {
|
|
695
|
-
|
|
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
|
|
724
|
-
|
|
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
|
|
727
|
-
|
|
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
|
-
|
|
732
|
-
|
|
733
|
-
|
|
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
|
-
|
|
740
|
-
|
|
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
|
|
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
|
|
757
|
+
return features;
|
|
758
758
|
}
|
|
759
|
-
// only properties changed - update tags directly
|
|
760
759
|
if (changeProps) {
|
|
761
|
-
const
|
|
762
|
-
|
|
763
|
-
|
|
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
|
|
768
|
+
return [];
|
|
766
769
|
}
|
|
767
770
|
/**
|
|
768
771
|
* helper to apply property updates from a diff update object to a properties object
|
package/dist/geojson-vt.js
CHANGED
|
@@ -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)];if(!o)return null;const 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)}}));
|
package/dist/geojson-vt.mjs
CHANGED
|
@@ -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
|
-
//
|
|
687
|
+
// Collect features to remove (explicit removals + replacements via add)
|
|
690
688
|
for (const feature of source) {
|
|
691
|
-
|
|
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
|
|
720
|
-
|
|
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
|
|
723
|
-
|
|
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
|
-
|
|
728
|
-
|
|
729
|
-
|
|
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
|
-
|
|
736
|
-
|
|
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
|
|
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
|
|
753
|
+
return features;
|
|
754
754
|
}
|
|
755
|
-
// only properties changed - update tags directly
|
|
756
755
|
if (changeProps) {
|
|
757
|
-
const
|
|
758
|
-
|
|
759
|
-
|
|
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
|
|
764
|
+
return [];
|
|
762
765
|
}
|
|
763
766
|
/**
|
|
764
767
|
* helper to apply property updates from a diff update object to a properties object
|