@maplibre/geojson-vt 5.0.2 → 5.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -30,7 +30,7 @@ dynamically loading a 100Mb US zip codes GeoJSON with 5.4 million points:
30
30
 
31
31
  ![](https://cloud.githubusercontent.com/assets/25395/5360312/86028d8e-7f91-11e4-811f-87f24acb09ca.gif)
32
32
 
33
- There's a convenient [debug page](http://maplibre.github.io/geojson-vt/debug/) to test out **geojson-vt** on different data.
33
+ There's a convenient [debug page](http://maplibre.org/geojson-vt/debug/) to test out **geojson-vt** on different data.
34
34
  Just drag any GeoJSON on the page, watching the console.
35
35
 
36
36
  ![](https://cloud.githubusercontent.com/assets/25395/5363235/41955c6e-7fa8-11e4-9575-a66ef54cb6d9.gif)
@@ -107,20 +107,20 @@ To use `updateData`, the index must be created with the `updateable: true` optio
107
107
 
108
108
  ### Install
109
109
 
110
- Install using NPM (`npm install geojson-vt`), then:
110
+ Install using NPM (`npm install @maplibre/geojson-vt`), then:
111
111
 
112
112
  ```js
113
113
  // import as a ES module
114
- import geojsonvt from 'geojson-vt';
114
+ import geojsonvt from '@maplibre/geojson-vt';
115
115
 
116
116
  // import from a CDN in the browser:
117
- import geojsonvt from 'https://esm.run/geojson-vt';
117
+ import geojsonvt from 'https://esm.run/@maplibre/geojson-vt';
118
118
  ```
119
119
 
120
120
  Or use a browser build directly:
121
121
 
122
122
  ```html
123
- <script src="https://unpkg.com/geojson-vt/geojson-vt.js"></script>
123
+ <script src="https://unpkg.com/@maplibre/geojson-vt/geojson-vt.js"></script>
124
124
  ```
125
125
 
126
126
  ### Getting Involved
package/dist/clip.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import type { GeoJSONVTInternalFeature, GeoJSONVTOptions } from './definitions';
2
+ export declare function clip(features: GeoJSONVTInternalFeature[], scale: number, k1: number, k2: number, axis: number, minAll: number, maxAll: number, options: GeoJSONVTOptions): GeoJSONVTInternalFeature[] | null;
3
+ //# sourceMappingURL=clip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clip.d.ts","sourceRoot":"","sources":["../src/clip.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,wBAAwB,EAAE,gBAAgB,EAAqB,MAAM,eAAe,CAAC;AAYnG,wBAAgB,IAAI,CAAC,QAAQ,EAAE,wBAAwB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,wBAAwB,EAAE,GAAG,IAAI,CAqG5M"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=clip.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clip.test.d.ts","sourceRoot":"","sources":["../src/clip.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ import type { GeoJSONVTInternalFeature, GeoJSONVTOptions } from './definitions';
2
+ /**
3
+ * converts GeoJSON feature into an intermediate projected JSON vector format with simplification data
4
+ * @param data
5
+ * @param options
6
+ * @returns
7
+ */
8
+ export declare function convert(data: GeoJSON.GeoJSON, options: GeoJSONVTOptions): GeoJSONVTInternalFeature[];
9
+ //# sourceMappingURL=convert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,wBAAwB,EAAE,gBAAgB,EAAqB,MAAM,eAAe,CAAC;AAEnG;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,wBAAwB,EAAE,CAiBpG"}
@@ -0,0 +1,85 @@
1
+ export type GeoJSONVTOptions = {
2
+ /**
3
+ * Max zoom to preserve detail on
4
+ * @default 14
5
+ */
6
+ maxZoom?: number;
7
+ /**
8
+ * Max zoom in the tile index
9
+ * @default 5
10
+ */
11
+ indexMaxZoom?: number;
12
+ /**
13
+ * Max number of points per tile in the tile index
14
+ * @default 100000
15
+ */
16
+ indexMaxPoints?: number;
17
+ /**
18
+ * Simplification tolerance (higher means simpler)
19
+ * @default 3
20
+ */
21
+ tolerance?: number;
22
+ /**
23
+ * Tile extent
24
+ * @default 4096
25
+ */
26
+ extent?: number;
27
+ /**
28
+ * Tile buffer on each side
29
+ * @default 64
30
+ */
31
+ buffer?: number;
32
+ /**
33
+ * Whether to calculate line metrics
34
+ * @default false
35
+ */
36
+ lineMetrics?: boolean;
37
+ /**
38
+ * Name of a feature property to be promoted to feature.id
39
+ */
40
+ promoteId?: string | null;
41
+ /**
42
+ * Whether to generate feature ids. Cannot be used with promoteId
43
+ * @default false
44
+ */
45
+ generateId?: boolean;
46
+ /**
47
+ * Whether geojson can be updated (with caveat of a stored simplified copy)
48
+ * @default false
49
+ */
50
+ updateable?: boolean;
51
+ /**
52
+ * Logging level (0, 1 or 2)
53
+ * @default 0
54
+ */
55
+ debug?: number;
56
+ };
57
+ export type StartEndSizeArray = number[] & {
58
+ start?: number;
59
+ end?: number;
60
+ size?: number;
61
+ };
62
+ export type PartialGeoJSONVTFeature = {
63
+ id?: number | string | undefined;
64
+ tags: GeoJSON.GeoJsonProperties;
65
+ minX: number;
66
+ minY: number;
67
+ maxX: number;
68
+ maxY: number;
69
+ };
70
+ export type GeometryTypeMap = {
71
+ Point: number[];
72
+ MultiPoint: number[];
73
+ LineString: StartEndSizeArray;
74
+ MultiLineString: StartEndSizeArray[];
75
+ Polygon: StartEndSizeArray[];
76
+ MultiPolygon: StartEndSizeArray[][];
77
+ };
78
+ export type GeometryType = "Point" | "MultiPoint" | "LineString" | "MultiLineString" | "Polygon" | "MultiPolygon";
79
+ export type GeoJSONVTInternalFeature = {
80
+ [K in GeometryType]: PartialGeoJSONVTFeature & {
81
+ type: K;
82
+ geometry: GeometryTypeMap[K];
83
+ };
84
+ }[GeometryType];
85
+ //# sourceMappingURL=definitions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../src/definitions.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAGF,MAAM,MAAM,iBAAiB,GAAG,MAAM,EAAE,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3F,MAAM,MAAM,uBAAuB,GAAG;IAClC,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACjC,IAAI,EAAE,OAAO,CAAC,iBAAiB,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAChB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,eAAe,EAAE,iBAAiB,EAAE,CAAC;IACrC,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,YAAY,EAAE,iBAAiB,EAAE,EAAE,CAAC;CACvC,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,YAAY,GAAG,YAAY,GAAG,iBAAiB,GAAG,SAAS,GAAG,cAAc,CAAC;AAElH,MAAM,MAAM,wBAAwB,GAAG;KAClC,CAAC,IAAI,YAAY,GAAG,uBAAuB,GAAG;QAC3C,IAAI,EAAE,CAAC,CAAC;QACR,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;KAChC;CACJ,CAAC,YAAY,CAAC,CAAC"}
@@ -0,0 +1,67 @@
1
+ import type { GeoJSONVTInternalFeature, GeoJSONVTOptions } from './definitions';
2
+ export type GeoJSONVTSourceDiff = {
3
+ /**
4
+ * If true, clear all existing features
5
+ */
6
+ removeAll?: boolean;
7
+ /**
8
+ * Array of feature IDs to remove
9
+ */
10
+ remove?: (string | number)[];
11
+ /**
12
+ * Array of GeoJSON features to add
13
+ */
14
+ add?: GeoJSON.Feature[];
15
+ /**
16
+ * Array of per-feature updates
17
+ */
18
+ update?: GeoJSONVTFeatureDiff[];
19
+ };
20
+ export type GeoJSONVTFeatureDiff = {
21
+ /**
22
+ * ID of the feature being updated
23
+ */
24
+ id: string | number;
25
+ /**
26
+ * Optional new geometry
27
+ */
28
+ newGeometry?: GeoJSON.Geometry;
29
+ /**
30
+ * Remove all properties if true
31
+ */
32
+ removeAllProperties?: boolean;
33
+ /**
34
+ * Specific properties to delete
35
+ */
36
+ removeProperties?: string[];
37
+ /**
38
+ * Properties to add or update
39
+ */
40
+ addOrUpdateProperties?: {
41
+ key: string;
42
+ value: unknown;
43
+ }[];
44
+ };
45
+ type HashedGeoJSONVTSourceDiff = {
46
+ removeAll?: boolean | undefined;
47
+ remove: Set<string | number>;
48
+ add: Map<string | number | undefined, GeoJSON.Feature>;
49
+ update: Map<string | number, GeoJSONVTFeatureDiff>;
50
+ };
51
+ /**
52
+ * Applies a GeoJSON Source Diff to an existing set of simplified features
53
+ * @param source
54
+ * @param dataDiff
55
+ * @param options
56
+ * @returns
57
+ */
58
+ export declare function applySourceDiff(source: GeoJSONVTInternalFeature[], dataDiff: GeoJSONVTSourceDiff, options: GeoJSONVTOptions): {
59
+ affected: GeoJSONVTInternalFeature[];
60
+ source: GeoJSONVTInternalFeature[];
61
+ };
62
+ /**
63
+ * Convert a GeoJSON Source Diff to an idempotent hashed representation using Sets and Maps
64
+ */
65
+ export declare function diffToHashed(diff: GeoJSONVTSourceDiff): HashedGeoJSONVTSourceDiff;
66
+ export {};
67
+ //# sourceMappingURL=difference.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=difference.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"difference.test.d.ts","sourceRoot":"","sources":["../src/difference.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,12 @@
1
+ import type { GeoJSONVTInternalFeature, GeometryType, GeometryTypeMap } from "./definitions";
2
+ export type SupportedGeometries = GeoJSON.Point | GeoJSON.MultiPoint | GeoJSON.LineString | GeoJSON.MultiLineString | GeoJSON.Polygon | GeoJSON.MultiPolygon;
3
+ /**
4
+ *
5
+ * @param id - the feature's ID
6
+ * @param type - the feature's type
7
+ * @param geom - the feature's geometry
8
+ * @param tags - the feature's properties
9
+ * @returns the created feature
10
+ */
11
+ export declare function createFeature<T extends GeometryType>(id: number | string | undefined, type: T, geom: GeometryTypeMap[T], tags: GeoJSON.GeoJsonProperties): GeoJSONVTInternalFeature;
12
+ //# sourceMappingURL=feature.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature.d.ts","sourceRoot":"","sources":["../src/feature.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAE7F,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC,eAAe,GAAG,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC;AAE7J;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,YAAY,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,iBAAiB,GAAG,wBAAwB,CA0CnL"}
@@ -559,22 +559,23 @@ function transformTile(tile, extent) {
559
559
  const tx = tile.x;
560
560
  const ty = tile.y;
561
561
  for (const feature of tile.features) {
562
- const geom = feature.geometry;
563
- const type = feature.type;
564
- feature.geometry = [];
565
- if (type === 1) {
566
- for (let j = 0; j < geom.length; j += 2) {
567
- feature.geometry.push(transformPoint(geom[j], geom[j + 1], extent, z2, tx, ty));
562
+ if (feature.type === 1) {
563
+ const pointGeometry = [];
564
+ for (let j = 0; j < feature.geometry.length; j += 2) {
565
+ pointGeometry.push(transformPoint(feature.geometry[j], feature.geometry[j + 1], extent, z2, tx, ty));
568
566
  }
567
+ feature.geometry = pointGeometry;
569
568
  continue;
570
569
  }
571
- for (const singleGeom of geom) {
570
+ const geometry = [];
571
+ for (const singleGeom of feature.geometry) {
572
572
  const ring = [];
573
573
  for (let k = 0; k < singleGeom.length; k += 2) {
574
574
  ring.push(transformPoint(singleGeom[k], singleGeom[k + 1], extent, z2, tx, ty));
575
575
  }
576
- feature.geometry.push(ring);
576
+ geometry.push(ring);
577
577
  }
578
+ feature.geometry = geometry;
578
579
  }
579
580
  tile.transformed = true;
580
581
  return tile;
@@ -618,55 +619,83 @@ function createTile(features, z, tx, ty, options) {
618
619
  return tile;
619
620
  }
620
621
  function addFeature(tile, feature, tolerance, options) {
621
- const simplified = [];
622
622
  tile.minX = Math.min(tile.minX, feature.minX);
623
623
  tile.minY = Math.min(tile.minY, feature.minY);
624
624
  tile.maxX = Math.max(tile.maxX, feature.maxX);
625
625
  tile.maxY = Math.max(tile.maxY, feature.maxY);
626
+ let tags = feature.tags || null;
627
+ let tileFeature;
626
628
  switch (feature.type) {
627
629
  case 'Point':
628
- case 'MultiPoint':
630
+ case 'MultiPoint': {
631
+ const geometry = [];
629
632
  for (let i = 0; i < feature.geometry.length; i += 3) {
630
- simplified.push(feature.geometry[i], feature.geometry[i + 1]);
633
+ geometry.push(feature.geometry[i], feature.geometry[i + 1]);
631
634
  tile.numPoints++;
632
635
  tile.numSimplified++;
633
636
  }
637
+ if (!geometry.length)
638
+ return;
639
+ tileFeature = {
640
+ type: 1,
641
+ tags: tags,
642
+ geometry: geometry
643
+ };
634
644
  break;
635
- case 'LineString':
636
- addLine(simplified, feature.geometry, tile, tolerance, false, false);
645
+ }
646
+ case 'LineString': {
647
+ const geometry = [];
648
+ addLine(geometry, feature.geometry, tile, tolerance, false, false);
649
+ if (!geometry.length)
650
+ return;
651
+ if (options.lineMetrics) {
652
+ tags = {};
653
+ for (const key in feature.tags)
654
+ tags[key] = feature.tags[key];
655
+ // HM TODO: replace with geojsonvt
656
+ tags['mapbox_clip_start'] = feature.geometry.start / feature.geometry.size;
657
+ tags['mapbox_clip_end'] = feature.geometry.end / feature.geometry.size;
658
+ }
659
+ tileFeature = {
660
+ type: 2,
661
+ tags: tags,
662
+ geometry: geometry
663
+ };
637
664
  break;
665
+ }
638
666
  case 'MultiLineString':
639
- case 'Polygon':
667
+ case 'Polygon': {
668
+ const geometry = [];
640
669
  for (let i = 0; i < feature.geometry.length; i++) {
641
- addLine(simplified, feature.geometry[i], tile, tolerance, feature.type === 'Polygon', i === 0);
670
+ addLine(geometry, feature.geometry[i], tile, tolerance, feature.type === 'Polygon', i === 0);
642
671
  }
672
+ if (!geometry.length)
673
+ return;
674
+ tileFeature = {
675
+ type: feature.type === 'Polygon' ? 3 : 2,
676
+ tags: tags,
677
+ geometry: geometry
678
+ };
643
679
  break;
644
- case 'MultiPolygon':
680
+ }
681
+ case 'MultiPolygon': {
682
+ const geometry = [];
645
683
  for (let k = 0; k < feature.geometry.length; k++) {
646
684
  const polygon = feature.geometry[k];
647
685
  for (let i = 0; i < polygon.length; i++) {
648
- addLine(simplified, polygon[i], tile, tolerance, true, i === 0);
686
+ addLine(geometry, polygon[i], tile, tolerance, true, i === 0);
649
687
  }
650
688
  }
689
+ if (!geometry.length)
690
+ return;
691
+ tileFeature = {
692
+ type: 3,
693
+ tags: tags,
694
+ geometry: geometry
695
+ };
651
696
  break;
697
+ }
652
698
  }
653
- if (!simplified.length)
654
- return;
655
- let tags = feature.tags || null;
656
- if (feature.type === 'LineString' && options.lineMetrics) {
657
- tags = {};
658
- for (const key in feature.tags)
659
- tags[key] = feature.tags[key];
660
- // HM TODO: replace with geojsonvt
661
- tags['mapbox_clip_start'] = feature.geometry.start / feature.geometry.size;
662
- tags['mapbox_clip_end'] = feature.geometry.end / feature.geometry.size;
663
- }
664
- const tileFeature = {
665
- geometry: simplified,
666
- type: feature.type === 'Polygon' || feature.type === 'MultiPolygon' ? 3 :
667
- (feature.type === 'LineString' || feature.type === 'MultiLineString' ? 2 : 1),
668
- tags
669
- };
670
699
  if (feature.id !== null) {
671
700
  tileFeature.id = feature.id;
672
701
  }
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).geojsonvt=e()}(this,(function(){"use strict";function t(n,o,i,s){let r=s;const l=o+(i-o>>1);let a,c=i-o;const u=n[o],f=n[o+1],m=n[i],d=n[i+1];for(let t=o+3;t<i;t+=3){const o=e(n[t],n[t+1],u,f,m,d);if(o>r)a=t,r=o;else if(o===r){const e=Math.abs(t-l);e<c&&(a=t,c=e)}}r>s&&(a-o>3&&t(n,o,a,s),n[a+2]=r,i-a>3&&t(n,a,i,s))}function e(t,e,n,o,i,s){let r=i-n,l=s-o;if(0!==r||0!==l){const a=((t-n)*r+(e-o)*l)/(r*r+l*l);a>1?(n=i,o=s):a>0&&(n+=r*a,o+=l*a)}return r=t-n,l=e-o,r*r+l*l}function n(t,e,n,i){const s={type:e,geom:n},r={id:null==t?null:t,type:s.type,geometry:s.geom,tags:i,minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};switch(s.type){case"Point":case"MultiPoint":case"LineString":o(r,s.geom);break;case"Polygon":o(r,s.geom[0]);break;case"MultiLineString":for(const t of s.geom)o(r,t);break;case"MultiPolygon":for(const t of s.geom)o(r,t[0])}return r}function o(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++)s(n,t.features[o],e,o);break;case"Feature":s(n,t,e);break;default:s(n,{geometry:t,properties:void 0},e)}return n}function s(t,e,o,i){if(!e.geometry)return;if("GeometryCollection"===e.geometry.type){for(const n of e.geometry.geometries)s(t,{id:e.id,geometry:n,properties:e.properties},o,i);return}const c=e.geometry.coordinates;if(!c?.length)return;const u=Math.pow(o.tolerance/((1<<o.maxZoom)*o.extent),2);let f=e.id;switch(o.promoteId?f=e.properties?.[o.promoteId]:o.generateId&&(f=i||0),e.geometry.type){case"Point":{const o=[];return r(e.geometry.coordinates,o),void t.push(n(f,e.geometry.type,o,e.properties))}case"MultiPoint":{const o=[];for(const t of e.geometry.coordinates)r(t,o);return void t.push(n(f,e.geometry.type,o,e.properties))}case"LineString":{const o=[];return l(e.geometry.coordinates,o,u,!1),void t.push(n(f,e.geometry.type,o,e.properties))}case"MultiLineString":{if(o.lineMetrics){for(const o of e.geometry.coordinates){const i=[];l(o,i,u,!1),t.push(n(f,"LineString",i,e.properties))}return}const i=[];return a(e.geometry.coordinates,i,u,!1),void t.push(n(f,e.geometry.type,i,e.properties))}case"Polygon":{const o=[];return a(e.geometry.coordinates,o,u,!0),void t.push(n(f,e.geometry.type,o,e.properties))}case"MultiPolygon":{const o=[];for(const t of e.geometry.coordinates){const e=[];a(t,e,u,!0),o.push(e)}return void t.push(n(f,e.geometry.type,o,e.properties))}default:throw new Error("Input data is not a valid GeoJSON object.")}}function r(t,e){e.push(c(t[0]),u(t[1]),0)}function l(e,n,o,i){let s,r,l=0;for(let t=0;t<e.length;t++){const o=c(e[t][0]),a=u(e[t][1]);n.push(o,a,0),t>0&&(l+=i?(s*a-o*r)/2:Math.sqrt(Math.pow(o-s,2)+Math.pow(a-r,2))),s=o,r=a}const a=n.length-3;n[2]=1,o>0&&t(n,0,a,o),n[a+2]=1,n.size=Math.abs(l),n.start=0,n.end=n.size}function a(t,e,n,o){for(let i=0;i<t.length;i++){const s=[];l(t[i],s,n,o),e.push(s)}}function c(t){return t/360+.5}function u(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 f(t,e,o,i,s,r,l,a){if(i/=e,r>=(o/=e)&&l<i)return t;if(l<o||r>=i)return null;const c=[];for(const e of t){const t=0===s?e.minX:e.minY,r=0===s?e.maxX:e.maxY;if(t>=o&&r<i)c.push(e);else if(!(r<o||t>=i))switch(e.type){case"Point":case"MultiPoint":{const t=[];if(m(e.geometry,t,o,i,s),!t.length)continue;const r=3===t.length?"Point":"MultiPoint";c.push(n(e.id,r,t,e.tags));continue}case"LineString":{const t=[];if(d(e.geometry,t,o,i,s,!1,a.lineMetrics),!t.length)continue;if(a.lineMetrics){for(const o of t)c.push(n(e.id,e.type,o,e.tags));continue}if(t.length>1){c.push(n(e.id,"MultiLineString",t,e.tags));continue}c.push(n(e.id,e.type,t[0],e.tags));continue}case"MultiLineString":{const t=[];if(g(e.geometry,t,o,i,s,!1),!t.length)continue;if(1===t.length){c.push(n(e.id,"LineString",t[0],e.tags));continue}c.push(n(e.id,e.type,t,e.tags));continue}case"Polygon":{const t=[];if(g(e.geometry,t,o,i,s,!0),!t.length)continue;c.push(n(e.id,e.type,t,e.tags));continue}case"MultiPolygon":{const t=[];for(const n of e.geometry){const e=[];g(n,e,o,i,s,!0),e.length&&t.push(e)}if(!t.length)continue;c.push(n(e.id,e.type,t,e.tags));continue}}}return c.length?c:null}function m(t,e,n,o,i){for(let s=0;s<t.length;s+=3){const r=t[s+i];r>=n&&r<=o&&h(e,t[s],t[s+1],t[s+2])}}function d(t,e,n,o,i,s,r){let l=p(t);const a=0===i?y:x;let c,u,f=t.start;for(let m=0;m<t.length-3;m+=3){const d=t[m],g=t[m+1],y=t[m+2],x=t[m+3],M=t[m+4],P=0===i?d:g,b=0===i?x:M;let w=!1;r&&(c=Math.sqrt(Math.pow(d-x,2)+Math.pow(g-M,2))),P<n?b>n&&(u=a(l,d,g,x,M,n),r&&(l.start=f+c*u)):P>o?b<o&&(u=a(l,d,g,x,M,o),r&&(l.start=f+c*u)):h(l,d,g,y),b<n&&P>=n&&(u=a(l,d,g,x,M,n),w=!0),b>o&&P<=o&&(u=a(l,d,g,x,M,o),w=!0),!s&&w&&(r&&(l.end=f+c*u),e.push(l),l=p(t)),r&&(f+=c)}let m=t.length-3;const d=t[m],g=t[m+1],M=t[m+2],P=0===i?d:g;P>=n&&P<=o&&h(l,d,g,M),m=l.length-3,s&&m>=3&&(l[m]!==l[0]||l[m+1]!==l[1])&&h(l,l[0],l[1],l[2]),l.length&&e.push(l)}function p(t){const e=[];return e.size=t.size,e.start=t.start,e.end=t.end,e}function g(t,e,n,o,i,s){for(const r of t)d(r,e,n,o,i,s,!1)}function h(t,e,n,o){t.push(e,n,o)}function y(t,e,n,o,i,s){const r=(s-e)/(o-e);return h(t,s,n+(i-n)*r,1),r}function x(t,e,n,o,i,s){const r=(s-n)/(i-n);return h(t,e+(o-e)*r,s,1),r}function M(t,e){const n=e.buffer/e.extent;let o=t;const i=f(t,1,-1-n,n,0,-1,2,e),s=f(t,1,1-n,2+n,0,-1,2,e);return i||s?(o=f(t,1,-n,1+n,0,-1,2,e)||[],i&&(o=P(i,1).concat(o)),s&&(o=o.concat(P(s,-1))),o):o}function P(t,e){const o=[];for(const i of t)switch(i.type){case"Point":case"MultiPoint":case"LineString":{const t=b(i.geometry,e);o.push(n(i.id,i.type,t,i.tags));continue}case"MultiLineString":case"Polygon":{const t=[];for(const n of i.geometry)t.push(b(n,e));o.push(n(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(b(t,e));t.push(o)}o.push(n(i.id,i.type,t,i.tags));continue}}return o}function b(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 w(t,e){if(t.transformed)return t;const n=1<<t.z,o=t.x,i=t.y;for(const s of t.features){const t=s.geometry,r=s.type;if(s.geometry=[],1!==r)for(const r of t){const t=[];for(let s=0;s<r.length;s+=2)t.push(v(r[s],r[s+1],e,n,o,i));s.geometry.push(t)}else for(let r=0;r<t.length;r+=2)s.geometry.push(v(t[r],t[r+1],e,n,o,i))}return t.transformed=!0,t}function v(t,e,n,o,i,s){return[Math.round(n*(t*o-i)),Math.round(n*(e*o-s))]}function z(t,e,n,o,i){const s=e===i.maxZoom?0:i.tolerance/((1<<e)*i.extent),r={features:[],numPoints:0,numSimplified:0,numFeatures:t.length,source:null,x:n,y:o,z:e,transformed:!1,minX:2,minY:1,maxX:-1,maxY:0};for(const e of t)Y(r,e,s,i);return r}function Y(t,e,n,o){const i=[];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":for(let n=0;n<e.geometry.length;n+=3)i.push(e.geometry[n],e.geometry[n+1]),t.numPoints++,t.numSimplified++;break;case"LineString":S(i,e.geometry,t,n,!1,!1);break;case"MultiLineString":case"Polygon":for(let o=0;o<e.geometry.length;o++)S(i,e.geometry[o],t,n,"Polygon"===e.type,0===o);break;case"MultiPolygon":for(let o=0;o<e.geometry.length;o++){const s=e.geometry[o];for(let e=0;e<s.length;e++)S(i,s[e],t,n,!0,0===e)}}if(!i.length)return;let s=e.tags||null;if("LineString"===e.type&&o.lineMetrics){s={};for(const t in e.tags)s[t]=e.tags[t];s.mapbox_clip_start=e.geometry.start/e.geometry.size,s.mapbox_clip_end=e.geometry.end/e.geometry.size}const r={geometry:i,type:"Polygon"===e.type||"MultiPolygon"===e.type?3:"LineString"===e.type||"MultiLineString"===e.type?2:1,tags:s};null!==e.id&&(r.id=e.id),t.features.push(r)}function S(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 l=[];for(let t=0;t<e.length;t+=3)(0===o||e[t+2]>r)&&(n.numSimplified++,l.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}}(l,s),t.push(l)}function X(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){const{id:t}=n;(o.remove.has(t)||o.add.has(t))&&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=M(e,n),s.push(...e),t.push(...e)}}if(o.update.size)for(const[e,i]of o.update){const o=t.findIndex((t=>t.id===e));if(-1===o)continue;const r=t[o],l=L(r,i,n);l&&(s.push(r,l),t[o]=l)}return{affected:s,source:t}}function L(t,e,n){const o=!!e.newGeometry,s=e.removeAllProperties||e.removeProperties?.length>0||e.addOrUpdateProperties?.length>0;if(o){let o=i({type:"FeatureCollection",features:[{type:"Feature",id:t.id,geometry:e.newGeometry,properties:s?I(t.tags,e):t.tags}]},n);return o=M(o,n),o[0]}if(s){const n={...t};return n.tags=I(n.tags,e),n}return null}function I(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}const Z={maxZoom:14,indexMaxZoom:5,indexMaxPoints:1e5,tolerance:3,extent:4096,buffer:64,lineMetrics:!1,promoteId:null,generateId:!1,updateable:!1,debug:0};class k{options;tiles;tileCoords;stats={};total=0;source;constructor(t,e){const n=(e=this.options=Object.assign({},Z,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);this.tiles={},this.tileCoords=[],n&&(console.timeEnd("preprocess data"),console.log("index: maxZoom: %d, maxPoints: %d",e.indexMaxZoom,e.indexMaxPoints),console.time("generate tiles"),this.stats={},this.total=0),o=M(o,e),o.length&&this.splitTile(o,0,0,0),e.updateable&&(this.source=o),n&&(o.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)))}splitTile(t,e,n,o,i,s,r){const l=[t,e,n,o],a=this.options,c=a.debug;for(;l.length;){o=l.pop(),n=l.pop(),e=l.pop(),t=l.pop();const u=1<<e,m=C(e,n,o);let d=this.tiles[m];if(!d&&(c>1&&console.time("creation"),d=this.tiles[m]=z(t,e,n,o,a),this.tileCoords.push({z:e,x:n,y:o,id:m}),c)){c>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===a.indexMaxZoom||d.numPoints<=a.indexMaxPoints)continue}else{if(e===a.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;c>1&&console.time("clipping");const p=.5*a.buffer/a.extent,g=.5-p,h=.5+p,y=1+p;let x=null,M=null,P=null,b=null;const w=f(t,u,n-p,n+h,0,d.minX,d.maxX,a),v=f(t,u,n+g,n+y,0,d.minX,d.maxX,a);w&&(x=f(w,u,o-p,o+h,1,d.minY,d.maxY,a),M=f(w,u,o+g,o+y,1,d.minY,d.maxY,a)),v&&(P=f(v,u,o-p,o+h,1,d.minY,d.maxY,a),b=f(v,u,o+g,o+y,1,d.minY,d.maxY,a)),c>1&&console.timeEnd("clipping"),l.push(x||[],e+1,2*n,2*o),l.push(M||[],e+1,2*n,2*o+1),l.push(P||[],e+1,2*n+1,2*o),l.push(b||[],e+1,2*n+1,2*o+1)}}getTile(t,e,n){t=+t,e=+e,n=+n;const o=this.options,{extent:i,debug:s}=o;if(t<0||t>24)return null;const r=1<<t,l=C(t,e=e+r&r-1,n);if(this.tiles[l])return w(this.tiles[l],i);s>1&&console.log("drilling down to z%d-%d-%d",t,e,n);let a,c=t,u=e,f=n;for(;!a&&c>0;)c--,u>>=1,f>>=1,a=this.tiles[C(c,u,f)];return a?.source?(s>1&&(console.log("found parent tile z%d-%d-%d",c,u,f),console.time("drilling down")),this.splitTile(a.source,c,u,f,t,e,n),s>1&&console.timeEnd("drilling down"),this.tiles[l]?w(this.tiles[l],i):null):null}invalidateTiles(t){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 l=e.buffer/e.extent,a=new Set;for(const e in this.tiles){const c=this.tiles[e],u=1<<c.z,f=(c.x-l)/u,m=(c.x+1+l)/u,d=(c.y-l)/u,p=(c.y+1+l)/u;if(i<f||o>=m||r<d||s>=p)continue;let g=!1;for(const e of t)if(e.maxX>=f&&e.minX<m&&e.maxY>=d&&e.minY<p){g=!0;break}if(g){if(n){n>1&&console.log("invalidate tile z%d-%d-%d (features: %d, points: %d, simplified: %d)",c.z,c.x,c.y,c.numFeatures,c.numPoints,c.numSimplified);const t=`z${c.z}`;this.stats[t]=(this.stats[t]||0)-1,this.total--}delete this.tiles[e],a.add(e)}}a.size&&(this.tileCoords=this.tileCoords.filter((t=>!a.has(t.id))))}updateData(t){const e=this.options,n=e.debug;if(!e.updateable)throw new Error("to update tile geojson `updateable` option must be set to true");const{affected:o,source:i}=X(this.source,t,e);if(!o.length)return;this.source=i,n>1&&(console.log("invalidating tiles"),console.time("invalidating")),this.invalidateTiles(o),n>1&&console.timeEnd("invalidating");const[s,r,l]=[0,0,0],a=z(this.source,s,r,l,this.options);a.source=this.source;const c=C(s,r,l);if(this.tiles[c]=a,this.tileCoords.push({z:s,x:r,y:l,id:c}),n){const t=`z${s}`;this.stats[t]=(this.stats[t]||0)+1,this.total++}}}function C(t,e,n){return 32*((1<<t)*n+e)+t}return function(t,e){return new k(t,e)}}));
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).geojsonvt=e()}(this,(function(){"use strict";function t(o,n,i,s){let r=s;const l=n+(i-n>>1);let a,c=i-n;const u=o[n],m=o[n+1],f=o[i],d=o[i+1];for(let t=n+3;t<i;t+=3){const n=e(o[t],o[t+1],u,m,f,d);if(n>r)a=t,r=n;else if(n===r){const e=Math.abs(t-l);e<c&&(a=t,c=e)}}r>s&&(a-n>3&&t(o,n,a,s),o[a+2]=r,i-a>3&&t(o,a,i,s))}function e(t,e,o,n,i,s){let r=i-o,l=s-n;if(0!==r||0!==l){const a=((t-o)*r+(e-n)*l)/(r*r+l*l);a>1?(o=i,n=s):a>0&&(o+=r*a,n+=l*a)}return r=t-o,l=e-n,r*r+l*l}function o(t,e,o,i){const s={type:e,geom:o},r={id:null==t?null:t,type:s.type,geometry:s.geom,tags:i,minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};switch(s.type){case"Point":case"MultiPoint":case"LineString":n(r,s.geom);break;case"Polygon":n(r,s.geom[0]);break;case"MultiLineString":for(const t of s.geom)n(r,t);break;case"MultiPolygon":for(const t of s.geom)n(r,t[0])}return r}function n(t,e){for(let o=0;o<e.length;o+=3)t.minX=Math.min(t.minX,e[o]),t.minY=Math.min(t.minY,e[o+1]),t.maxX=Math.max(t.maxX,e[o]),t.maxY=Math.max(t.maxY,e[o+1])}function i(t,e){const o=[];switch(t.type){case"FeatureCollection":for(let n=0;n<t.features.length;n++)s(o,t.features[n],e,n);break;case"Feature":s(o,t,e);break;default:s(o,{geometry:t,properties:void 0},e)}return o}function s(t,e,n,i){if(!e.geometry)return;if("GeometryCollection"===e.geometry.type){for(const o of e.geometry.geometries)s(t,{id:e.id,geometry:o,properties:e.properties},n,i);return}const c=e.geometry.coordinates;if(!c?.length)return;const u=Math.pow(n.tolerance/((1<<n.maxZoom)*n.extent),2);let m=e.id;switch(n.promoteId?m=e.properties?.[n.promoteId]:n.generateId&&(m=i||0),e.geometry.type){case"Point":{const n=[];return r(e.geometry.coordinates,n),void t.push(o(m,e.geometry.type,n,e.properties))}case"MultiPoint":{const n=[];for(const t of e.geometry.coordinates)r(t,n);return void t.push(o(m,e.geometry.type,n,e.properties))}case"LineString":{const n=[];return l(e.geometry.coordinates,n,u,!1),void t.push(o(m,e.geometry.type,n,e.properties))}case"MultiLineString":{if(n.lineMetrics){for(const n of e.geometry.coordinates){const i=[];l(n,i,u,!1),t.push(o(m,"LineString",i,e.properties))}return}const i=[];return a(e.geometry.coordinates,i,u,!1),void t.push(o(m,e.geometry.type,i,e.properties))}case"Polygon":{const n=[];return a(e.geometry.coordinates,n,u,!0),void t.push(o(m,e.geometry.type,n,e.properties))}case"MultiPolygon":{const n=[];for(const t of e.geometry.coordinates){const e=[];a(t,e,u,!0),n.push(e)}return void t.push(o(m,e.geometry.type,n,e.properties))}default:throw new Error("Input data is not a valid GeoJSON object.")}}function r(t,e){e.push(c(t[0]),u(t[1]),0)}function l(e,o,n,i){let s,r,l=0;for(let t=0;t<e.length;t++){const n=c(e[t][0]),a=u(e[t][1]);o.push(n,a,0),t>0&&(l+=i?(s*a-n*r)/2:Math.sqrt(Math.pow(n-s,2)+Math.pow(a-r,2))),s=n,r=a}const a=o.length-3;o[2]=1,n>0&&t(o,0,a,n),o[a+2]=1,o.size=Math.abs(l),o.start=0,o.end=o.size}function a(t,e,o,n){for(let i=0;i<t.length;i++){const s=[];l(t[i],s,o,n),e.push(s)}}function c(t){return t/360+.5}function u(t){const e=Math.sin(t*Math.PI/180),o=.5-.25*Math.log((1+e)/(1-e))/Math.PI;return o<0?0:o>1?1:o}function m(t,e,n,i,s,r,l,a){if(i/=e,r>=(n/=e)&&l<i)return t;if(l<n||r>=i)return null;const c=[];for(const e of t){const t=0===s?e.minX:e.minY,r=0===s?e.maxX:e.maxY;if(t>=n&&r<i)c.push(e);else if(!(r<n||t>=i))switch(e.type){case"Point":case"MultiPoint":{const t=[];if(f(e.geometry,t,n,i,s),!t.length)continue;const r=3===t.length?"Point":"MultiPoint";c.push(o(e.id,r,t,e.tags));continue}case"LineString":{const t=[];if(d(e.geometry,t,n,i,s,!1,a.lineMetrics),!t.length)continue;if(a.lineMetrics){for(const n of t)c.push(o(e.id,e.type,n,e.tags));continue}if(t.length>1){c.push(o(e.id,"MultiLineString",t,e.tags));continue}c.push(o(e.id,e.type,t[0],e.tags));continue}case"MultiLineString":{const t=[];if(g(e.geometry,t,n,i,s,!1),!t.length)continue;if(1===t.length){c.push(o(e.id,"LineString",t[0],e.tags));continue}c.push(o(e.id,e.type,t,e.tags));continue}case"Polygon":{const t=[];if(g(e.geometry,t,n,i,s,!0),!t.length)continue;c.push(o(e.id,e.type,t,e.tags));continue}case"MultiPolygon":{const t=[];for(const o of e.geometry){const e=[];g(o,e,n,i,s,!0),e.length&&t.push(e)}if(!t.length)continue;c.push(o(e.id,e.type,t,e.tags));continue}}}return c.length?c:null}function f(t,e,o,n,i){for(let s=0;s<t.length;s+=3){const r=t[s+i];r>=o&&r<=n&&h(e,t[s],t[s+1],t[s+2])}}function d(t,e,o,n,i,s,r){let l=p(t);const a=0===i?y:x;let c,u,m=t.start;for(let f=0;f<t.length-3;f+=3){const d=t[f],g=t[f+1],y=t[f+2],x=t[f+3],M=t[f+4],P=0===i?d:g,b=0===i?x:M;let w=!1;r&&(c=Math.sqrt(Math.pow(d-x,2)+Math.pow(g-M,2))),P<o?b>o&&(u=a(l,d,g,x,M,o),r&&(l.start=m+c*u)):P>n?b<n&&(u=a(l,d,g,x,M,n),r&&(l.start=m+c*u)):h(l,d,g,y),b<o&&P>=o&&(u=a(l,d,g,x,M,o),w=!0),b>n&&P<=n&&(u=a(l,d,g,x,M,n),w=!0),!s&&w&&(r&&(l.end=m+c*u),e.push(l),l=p(t)),r&&(m+=c)}let f=t.length-3;const d=t[f],g=t[f+1],M=t[f+2],P=0===i?d:g;P>=o&&P<=n&&h(l,d,g,M),f=l.length-3,s&&f>=3&&(l[f]!==l[0]||l[f+1]!==l[1])&&h(l,l[0],l[1],l[2]),l.length&&e.push(l)}function p(t){const e=[];return e.size=t.size,e.start=t.start,e.end=t.end,e}function g(t,e,o,n,i,s){for(const r of t)d(r,e,o,n,i,s,!1)}function h(t,e,o,n){t.push(e,o,n)}function y(t,e,o,n,i,s){const r=(s-e)/(n-e);return h(t,s,o+(i-o)*r,1),r}function x(t,e,o,n,i,s){const r=(s-o)/(i-o);return h(t,e+(n-e)*r,s,1),r}function M(t,e){const o=e.buffer/e.extent;let n=t;const i=m(t,1,-1-o,o,0,-1,2,e),s=m(t,1,1-o,2+o,0,-1,2,e);return i||s?(n=m(t,1,-o,1+o,0,-1,2,e)||[],i&&(n=P(i,1).concat(n)),s&&(n=n.concat(P(s,-1))),n):n}function P(t,e){const n=[];for(const i of t)switch(i.type){case"Point":case"MultiPoint":case"LineString":{const t=b(i.geometry,e);n.push(o(i.id,i.type,t,i.tags));continue}case"MultiLineString":case"Polygon":{const t=[];for(const o of i.geometry)t.push(b(o,e));n.push(o(i.id,i.type,t,i.tags));continue}case"MultiPolygon":{const t=[];for(const o of i.geometry){const n=[];for(const t of o)n.push(b(t,e));t.push(n)}n.push(o(i.id,i.type,t,i.tags));continue}}return n}function b(t,e){const o=[];o.size=t.size,void 0!==t.start&&(o.start=t.start,o.end=t.end);for(let n=0;n<t.length;n+=3)o.push(t[n]+e,t[n+1],t[n+2]);return o}function w(t,e){if(t.transformed)return t;const o=1<<t.z,n=t.x,i=t.y;for(const s of t.features){if(1===s.type){const t=[];for(let r=0;r<s.geometry.length;r+=2)t.push(v(s.geometry[r],s.geometry[r+1],e,o,n,i));s.geometry=t;continue}const t=[];for(const r of s.geometry){const s=[];for(let t=0;t<r.length;t+=2)s.push(v(r[t],r[t+1],e,o,n,i));t.push(s)}s.geometry=t}return t.transformed=!0,t}function v(t,e,o,n,i,s){return[Math.round(o*(t*n-i)),Math.round(o*(e*n-s))]}function z(t,e,o,n,i){const s=e===i.maxZoom?0:i.tolerance/((1<<e)*i.extent),r={features:[],numPoints:0,numSimplified:0,numFeatures:t.length,source:null,x:o,y:n,z:e,transformed:!1,minX:2,minY:1,maxX:-1,maxY:0};for(const e of t)Y(r,e,s,i);return r}function Y(t,e,o,n){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);let i,s=e.tags||null;switch(e.type){case"Point":case"MultiPoint":{const o=[];for(let n=0;n<e.geometry.length;n+=3)o.push(e.geometry[n],e.geometry[n+1]),t.numPoints++,t.numSimplified++;if(!o.length)return;i={type:1,tags:s,geometry:o};break}case"LineString":{const r=[];if(S(r,e.geometry,t,o,!1,!1),!r.length)return;if(n.lineMetrics){s={};for(const t in e.tags)s[t]=e.tags[t];s.mapbox_clip_start=e.geometry.start/e.geometry.size,s.mapbox_clip_end=e.geometry.end/e.geometry.size}i={type:2,tags:s,geometry:r};break}case"MultiLineString":case"Polygon":{const n=[];for(let i=0;i<e.geometry.length;i++)S(n,e.geometry[i],t,o,"Polygon"===e.type,0===i);if(!n.length)return;i={type:"Polygon"===e.type?3:2,tags:s,geometry:n};break}case"MultiPolygon":{const n=[];for(let i=0;i<e.geometry.length;i++){const s=e.geometry[i];for(let e=0;e<s.length;e++)S(n,s[e],t,o,!0,0===e)}if(!n.length)return;i={type:3,tags:s,geometry:n};break}}null!==e.id&&(i.id=e.id),t.features.push(i)}function S(t,e,o,n,i,s){const r=n*n;if(n>0&&e.size<(i?r:n))return void(o.numPoints+=e.length/3);const l=[];for(let t=0;t<e.length;t+=3)(0===n||e[t+2]>r)&&(o.numSimplified++,l.push(e[t],e[t+1])),o.numPoints++;i&&function(t,e){let o=0;for(let e=0,n=t.length,i=n-2;e<n;i=e,e+=2)o+=(t[e]-t[i])*(t[e+1]+t[i+1]);if(o>0!==e)return;for(let e=0,o=t.length;e<o/2;e+=2){const n=t[e],i=t[e+1];t[e]=t[o-2-e],t[e+1]=t[o-1-e],t[o-2-e]=n,t[o-1-e]=i}}(l,s),t.push(l)}function X(t,e,o){const n=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(n.removeAll&&(s=t,t=[]),n.remove.size||n.add.size){const e=[];for(const o of t){const{id:t}=o;(n.remove.has(t)||n.add.has(t))&&e.push(o)}if(e.length){s.push(...e);const o=new Set(e.map((t=>t.id)));t=t.filter((t=>!o.has(t.id)))}if(n.add.size){let e=i({type:"FeatureCollection",features:Array.from(n.add.values())},o);e=M(e,o),s.push(...e),t.push(...e)}}if(n.update.size)for(const[e,i]of n.update){const n=t.findIndex((t=>t.id===e));if(-1===n)continue;const r=t[n],l=I(r,i,o);l&&(s.push(r,l),t[n]=l)}return{affected:s,source:t}}function I(t,e,o){const n=!!e.newGeometry,s=e.removeAllProperties||e.removeProperties?.length>0||e.addOrUpdateProperties?.length>0;if(n){let n=i({type:"FeatureCollection",features:[{type:"Feature",id:t.id,geometry:e.newGeometry,properties:s?L(t.tags,e):t.tags}]},o);return n=M(n,o),n[0]}if(s){const o={...t};return o.tags=L(o.tags,e),o}return null}function L(t,e){if(e.removeAllProperties)return{};const o={...t||{}};if(e.removeProperties)for(const t of e.removeProperties)delete o[t];if(e.addOrUpdateProperties)for(const{key:t,value:n}of e.addOrUpdateProperties)o[t]=n;return o}const k={maxZoom:14,indexMaxZoom:5,indexMaxPoints:1e5,tolerance:3,extent:4096,buffer:64,lineMetrics:!1,promoteId:null,generateId:!1,updateable:!1,debug:0};class Z{options;tiles;tileCoords;stats={};total=0;source;constructor(t,e){const o=(e=this.options=Object.assign({},k,e)).debug;if(o&&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 n=i(t,e);this.tiles={},this.tileCoords=[],o&&(console.timeEnd("preprocess data"),console.log("index: maxZoom: %d, maxPoints: %d",e.indexMaxZoom,e.indexMaxPoints),console.time("generate tiles"),this.stats={},this.total=0),n=M(n,e),n.length&&this.splitTile(n,0,0,0),e.updateable&&(this.source=n),o&&(n.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)))}splitTile(t,e,o,n,i,s,r){const l=[t,e,o,n],a=this.options,c=a.debug;for(;l.length;){n=l.pop(),o=l.pop(),e=l.pop(),t=l.pop();const u=1<<e,f=C(e,o,n);let d=this.tiles[f];if(!d&&(c>1&&console.time("creation"),d=this.tiles[f]=z(t,e,o,n,a),this.tileCoords.push({z:e,x:o,y:n,id:f}),c)){c>1&&(console.log("tile z%d-%d-%d (features: %d, points: %d, simplified: %d)",e,o,n,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===a.indexMaxZoom||d.numPoints<=a.indexMaxPoints)continue}else{if(e===a.maxZoom||e===i)continue;if(null!=i){const t=i-e;if(o!==s>>t||n!==r>>t)continue}}if(d.source=null,!t.length)continue;c>1&&console.time("clipping");const p=.5*a.buffer/a.extent,g=.5-p,h=.5+p,y=1+p;let x=null,M=null,P=null,b=null;const w=m(t,u,o-p,o+h,0,d.minX,d.maxX,a),v=m(t,u,o+g,o+y,0,d.minX,d.maxX,a);w&&(x=m(w,u,n-p,n+h,1,d.minY,d.maxY,a),M=m(w,u,n+g,n+y,1,d.minY,d.maxY,a)),v&&(P=m(v,u,n-p,n+h,1,d.minY,d.maxY,a),b=m(v,u,n+g,n+y,1,d.minY,d.maxY,a)),c>1&&console.timeEnd("clipping"),l.push(x||[],e+1,2*o,2*n),l.push(M||[],e+1,2*o,2*n+1),l.push(P||[],e+1,2*o+1,2*n),l.push(b||[],e+1,2*o+1,2*n+1)}}getTile(t,e,o){t=+t,e=+e,o=+o;const n=this.options,{extent:i,debug:s}=n;if(t<0||t>24)return null;const r=1<<t,l=C(t,e=e+r&r-1,o);if(this.tiles[l])return w(this.tiles[l],i);s>1&&console.log("drilling down to z%d-%d-%d",t,e,o);let a,c=t,u=e,m=o;for(;!a&&c>0;)c--,u>>=1,m>>=1,a=this.tiles[C(c,u,m)];return a?.source?(s>1&&(console.log("found parent tile z%d-%d-%d",c,u,m),console.time("drilling down")),this.splitTile(a.source,c,u,m,t,e,o),s>1&&console.timeEnd("drilling down"),this.tiles[l]?w(this.tiles[l],i):null):null}invalidateTiles(t){const e=this.options,{debug:o}=e;let n=1/0,i=-1/0,s=1/0,r=-1/0;for(const e of t)n=Math.min(n,e.minX),i=Math.max(i,e.maxX),s=Math.min(s,e.minY),r=Math.max(r,e.maxY);const l=e.buffer/e.extent,a=new Set;for(const e in this.tiles){const c=this.tiles[e],u=1<<c.z,m=(c.x-l)/u,f=(c.x+1+l)/u,d=(c.y-l)/u,p=(c.y+1+l)/u;if(i<m||n>=f||r<d||s>=p)continue;let g=!1;for(const e of t)if(e.maxX>=m&&e.minX<f&&e.maxY>=d&&e.minY<p){g=!0;break}if(g){if(o){o>1&&console.log("invalidate tile z%d-%d-%d (features: %d, points: %d, simplified: %d)",c.z,c.x,c.y,c.numFeatures,c.numPoints,c.numSimplified);const t=`z${c.z}`;this.stats[t]=(this.stats[t]||0)-1,this.total--}delete this.tiles[e],a.add(e)}}a.size&&(this.tileCoords=this.tileCoords.filter((t=>!a.has(t.id))))}updateData(t){const e=this.options,o=e.debug;if(!e.updateable)throw new Error("to update tile geojson `updateable` option must be set to true");const{affected:n,source:i}=X(this.source,t,e);if(!n.length)return;this.source=i,o>1&&(console.log("invalidating tiles"),console.time("invalidating")),this.invalidateTiles(n),o>1&&console.timeEnd("invalidating");const[s,r,l]=[0,0,0],a=z(this.source,s,r,l,this.options);a.source=this.source;const c=C(s,r,l);if(this.tiles[c]=a,this.tileCoords.push({z:s,x:r,y:l,id:c}),o){const t=`z${s}`;this.stats[t]=(this.stats[t]||0)+1,this.total++}}}function C(t,e,o){return 32*((1<<t)*o+e)+t}return function(t,e){return new Z(t,e)}}));
@@ -553,22 +553,23 @@ function transformTile(tile, extent) {
553
553
  const tx = tile.x;
554
554
  const ty = tile.y;
555
555
  for (const feature of tile.features) {
556
- const geom = feature.geometry;
557
- const type = feature.type;
558
- feature.geometry = [];
559
- if (type === 1) {
560
- for (let j = 0; j < geom.length; j += 2) {
561
- feature.geometry.push(transformPoint(geom[j], geom[j + 1], extent, z2, tx, ty));
556
+ if (feature.type === 1) {
557
+ const pointGeometry = [];
558
+ for (let j = 0; j < feature.geometry.length; j += 2) {
559
+ pointGeometry.push(transformPoint(feature.geometry[j], feature.geometry[j + 1], extent, z2, tx, ty));
562
560
  }
561
+ feature.geometry = pointGeometry;
563
562
  continue;
564
563
  }
565
- for (const singleGeom of geom) {
564
+ const geometry = [];
565
+ for (const singleGeom of feature.geometry) {
566
566
  const ring = [];
567
567
  for (let k = 0; k < singleGeom.length; k += 2) {
568
568
  ring.push(transformPoint(singleGeom[k], singleGeom[k + 1], extent, z2, tx, ty));
569
569
  }
570
- feature.geometry.push(ring);
570
+ geometry.push(ring);
571
571
  }
572
+ feature.geometry = geometry;
572
573
  }
573
574
  tile.transformed = true;
574
575
  return tile;
@@ -612,55 +613,83 @@ function createTile(features, z, tx, ty, options) {
612
613
  return tile;
613
614
  }
614
615
  function addFeature(tile, feature, tolerance, options) {
615
- const simplified = [];
616
616
  tile.minX = Math.min(tile.minX, feature.minX);
617
617
  tile.minY = Math.min(tile.minY, feature.minY);
618
618
  tile.maxX = Math.max(tile.maxX, feature.maxX);
619
619
  tile.maxY = Math.max(tile.maxY, feature.maxY);
620
+ let tags = feature.tags || null;
621
+ let tileFeature;
620
622
  switch (feature.type) {
621
623
  case 'Point':
622
- case 'MultiPoint':
624
+ case 'MultiPoint': {
625
+ const geometry = [];
623
626
  for (let i = 0; i < feature.geometry.length; i += 3) {
624
- simplified.push(feature.geometry[i], feature.geometry[i + 1]);
627
+ geometry.push(feature.geometry[i], feature.geometry[i + 1]);
625
628
  tile.numPoints++;
626
629
  tile.numSimplified++;
627
630
  }
631
+ if (!geometry.length)
632
+ return;
633
+ tileFeature = {
634
+ type: 1,
635
+ tags: tags,
636
+ geometry: geometry
637
+ };
628
638
  break;
629
- case 'LineString':
630
- addLine(simplified, feature.geometry, tile, tolerance, false, false);
639
+ }
640
+ case 'LineString': {
641
+ const geometry = [];
642
+ addLine(geometry, feature.geometry, tile, tolerance, false, false);
643
+ if (!geometry.length)
644
+ return;
645
+ if (options.lineMetrics) {
646
+ tags = {};
647
+ for (const key in feature.tags)
648
+ tags[key] = feature.tags[key];
649
+ // HM TODO: replace with geojsonvt
650
+ tags['mapbox_clip_start'] = feature.geometry.start / feature.geometry.size;
651
+ tags['mapbox_clip_end'] = feature.geometry.end / feature.geometry.size;
652
+ }
653
+ tileFeature = {
654
+ type: 2,
655
+ tags: tags,
656
+ geometry: geometry
657
+ };
631
658
  break;
659
+ }
632
660
  case 'MultiLineString':
633
- case 'Polygon':
661
+ case 'Polygon': {
662
+ const geometry = [];
634
663
  for (let i = 0; i < feature.geometry.length; i++) {
635
- addLine(simplified, feature.geometry[i], tile, tolerance, feature.type === 'Polygon', i === 0);
664
+ addLine(geometry, feature.geometry[i], tile, tolerance, feature.type === 'Polygon', i === 0);
636
665
  }
666
+ if (!geometry.length)
667
+ return;
668
+ tileFeature = {
669
+ type: feature.type === 'Polygon' ? 3 : 2,
670
+ tags: tags,
671
+ geometry: geometry
672
+ };
637
673
  break;
638
- case 'MultiPolygon':
674
+ }
675
+ case 'MultiPolygon': {
676
+ const geometry = [];
639
677
  for (let k = 0; k < feature.geometry.length; k++) {
640
678
  const polygon = feature.geometry[k];
641
679
  for (let i = 0; i < polygon.length; i++) {
642
- addLine(simplified, polygon[i], tile, tolerance, true, i === 0);
680
+ addLine(geometry, polygon[i], tile, tolerance, true, i === 0);
643
681
  }
644
682
  }
683
+ if (!geometry.length)
684
+ return;
685
+ tileFeature = {
686
+ type: 3,
687
+ tags: tags,
688
+ geometry: geometry
689
+ };
645
690
  break;
691
+ }
646
692
  }
647
- if (!simplified.length)
648
- return;
649
- let tags = feature.tags || null;
650
- if (feature.type === 'LineString' && options.lineMetrics) {
651
- tags = {};
652
- for (const key in feature.tags)
653
- tags[key] = feature.tags[key];
654
- // HM TODO: replace with geojsonvt
655
- tags['mapbox_clip_start'] = feature.geometry.start / feature.geometry.size;
656
- tags['mapbox_clip_end'] = feature.geometry.end / feature.geometry.size;
657
- }
658
- const tileFeature = {
659
- geometry: simplified,
660
- type: feature.type === 'Polygon' || feature.type === 'MultiPolygon' ? 3 :
661
- (feature.type === 'LineString' || feature.type === 'MultiLineString' ? 2 : 1),
662
- tags
663
- };
664
693
  if (feature.id !== null) {
665
694
  tileFeature.id = feature.id;
666
695
  }