@maplibre/geojson-vt 6.2.0 → 6.3.0
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 +7 -2
- package/dist/cluster-tile-index.d.ts +12 -9
- package/dist/cluster-tile-index.d.ts.map +1 -1
- package/dist/convert.d.ts +2 -9
- package/dist/convert.d.ts.map +1 -1
- package/dist/deconvert.d.ts +4 -11
- package/dist/deconvert.d.ts.map +1 -1
- package/dist/definitions.d.ts +38 -10
- package/dist/definitions.d.ts.map +1 -1
- package/dist/difference.d.ts +2 -1
- package/dist/difference.d.ts.map +1 -1
- package/dist/geojson-vt-dev.js +263 -133
- package/dist/geojson-vt.js +1 -1
- package/dist/geojson-vt.mjs +261 -132
- package/dist/geojson-vt.mjs.map +1 -1
- package/dist/geojsonvt.d.ts +8 -4
- package/dist/geojsonvt.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/tile-index.d.ts +4 -3
- package/dist/tile-index.d.ts.map +1 -1
- package/dist/world-coordinate-helper.d.ts +13 -0
- package/dist/world-coordinate-helper.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/cluster-tile-index.test.ts +28 -8
- package/src/cluster-tile-index.ts +53 -27
- package/src/convert.ts +45 -47
- package/src/deconvert.test.ts +4 -4
- package/src/deconvert.ts +15 -31
- package/src/definitions.ts +39 -10
- package/src/difference.ts +48 -19
- package/src/geojson-to-tile.ts +2 -2
- package/src/geojsonvt.test.ts +171 -20
- package/src/geojsonvt.ts +24 -10
- package/src/index.ts +2 -1
- package/src/tile-index.ts +8 -6
- package/src/world-coordinate-helper.ts +63 -0
- package/src/wrap.ts +1 -1
package/dist/geojson-vt.mjs
CHANGED
|
@@ -127,31 +127,88 @@ function calcLineBBox(feature, geom) {
|
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
129
|
//#endregion
|
|
130
|
+
//#region src/world-coordinate-helper.ts
|
|
131
|
+
/**
|
|
132
|
+
* Longitude and latitude, which spherical mercator puts in the world square.
|
|
133
|
+
*/
|
|
134
|
+
var MercatorWorldCoordinateHelper = class {
|
|
135
|
+
projectX(lng) {
|
|
136
|
+
return lng / 360 + .5;
|
|
137
|
+
}
|
|
138
|
+
projectY(lat) {
|
|
139
|
+
const sin = Math.sin(lat * Math.PI / 180);
|
|
140
|
+
const y = .5 - .25 * Math.log((1 + sin) / (1 - sin)) / Math.PI;
|
|
141
|
+
return y < 0 ? 0 : y > 1 ? 1 : y;
|
|
142
|
+
}
|
|
143
|
+
unprojectX(x) {
|
|
144
|
+
return (x - .5) * 360;
|
|
145
|
+
}
|
|
146
|
+
unprojectY(y) {
|
|
147
|
+
const y2 = (180 - y * 360) * Math.PI / 180;
|
|
148
|
+
return 360 * Math.atan(Math.exp(y2)) / Math.PI - 90;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Positions in the unit square already, see `coordinates` in {@link GeoJSONVTOptions}.
|
|
153
|
+
*/
|
|
154
|
+
var IdentityWorldCoordinateHelper = class {
|
|
155
|
+
projectX(x) {
|
|
156
|
+
return x;
|
|
157
|
+
}
|
|
158
|
+
projectY(y) {
|
|
159
|
+
return y;
|
|
160
|
+
}
|
|
161
|
+
unprojectX(x) {
|
|
162
|
+
return x;
|
|
163
|
+
}
|
|
164
|
+
unprojectY(y) {
|
|
165
|
+
return y;
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
const mercatorWorldCoordinateHelper = new MercatorWorldCoordinateHelper();
|
|
169
|
+
const identityWorldCoordinateHelper = new IdentityWorldCoordinateHelper();
|
|
170
|
+
function getWorldCoordinateHelper(coordinates) {
|
|
171
|
+
return coordinates === "unitSquare" ? identityWorldCoordinateHelper : mercatorWorldCoordinateHelper;
|
|
172
|
+
}
|
|
173
|
+
//#endregion
|
|
130
174
|
//#region src/convert.ts
|
|
131
175
|
const MAX_GEOMETRY_COLLECTION_DEPTH = 1024;
|
|
132
176
|
/**
|
|
133
177
|
* converts GeoJSON to internal source features (an intermediate projected JSON vector format with simplification data)
|
|
134
178
|
* @param data
|
|
135
179
|
* @param options
|
|
180
|
+
* @param unlocated - the features without coordinates, by id: a feature with an id that converts to nothing is set in it, and one that converts to something is deleted from it
|
|
136
181
|
* @returns
|
|
137
182
|
*/
|
|
138
|
-
function convertToInternal(data, options) {
|
|
183
|
+
function convertToInternal(data, options, unlocated) {
|
|
139
184
|
const features = [];
|
|
140
185
|
switch (data.type) {
|
|
141
186
|
case "FeatureCollection":
|
|
142
|
-
for (let i = 0; i < data.features.length; i++)
|
|
187
|
+
for (let i = 0; i < data.features.length; i++) convertFeature(features, data.features[i], options, unlocated, i);
|
|
143
188
|
break;
|
|
144
189
|
case "Feature":
|
|
145
|
-
|
|
190
|
+
convertFeature(features, data, options, unlocated);
|
|
146
191
|
break;
|
|
147
|
-
default:
|
|
192
|
+
default: convertFeature(features, {
|
|
148
193
|
type: "Feature",
|
|
149
194
|
geometry: data,
|
|
150
195
|
properties: void 0
|
|
151
|
-
}, options);
|
|
196
|
+
}, options, unlocated);
|
|
152
197
|
}
|
|
153
198
|
return features;
|
|
154
199
|
}
|
|
200
|
+
function convertFeature(features, geojson, options, unlocated, index) {
|
|
201
|
+
const count = features.length;
|
|
202
|
+
featureToInternal(features, geojson, options, index);
|
|
203
|
+
if (!unlocated) return;
|
|
204
|
+
const id = getFeatureId(geojson, options, index);
|
|
205
|
+
if (id == null) return;
|
|
206
|
+
if (features.length > count) unlocated.delete(id);
|
|
207
|
+
else unlocated.set(id, {
|
|
208
|
+
...geojson,
|
|
209
|
+
id
|
|
210
|
+
});
|
|
211
|
+
}
|
|
155
212
|
function featureToInternal(features, geojson, options, index, depth = 0) {
|
|
156
213
|
if (!geojson.geometry) return;
|
|
157
214
|
if (depth > MAX_GEOMETRY_COLLECTION_DEPTH) throw new Error("GeometryCollection nesting exceeds supported depth: 1024");
|
|
@@ -162,25 +219,25 @@ function featureToInternal(features, geojson, options, index, depth = 0) {
|
|
|
162
219
|
if (!geojson.geometry.coordinates?.length) return;
|
|
163
220
|
const id = getFeatureId(geojson, options, index);
|
|
164
221
|
const tolerance = Math.pow(options.tolerance / ((1 << options.maxZoom) * options.extent), 2);
|
|
165
|
-
const
|
|
222
|
+
const worldCoordinateHelper = getWorldCoordinateHelper(options.coordinates);
|
|
166
223
|
switch (geojson.geometry.type) {
|
|
167
224
|
case "Point":
|
|
168
|
-
convertPointFeature(features, id, geojson.geometry,
|
|
225
|
+
convertPointFeature(features, id, geojson.geometry, worldCoordinateHelper, geojson.properties);
|
|
169
226
|
return;
|
|
170
227
|
case "MultiPoint":
|
|
171
|
-
convertMultiPointFeature(features, id, geojson.geometry,
|
|
228
|
+
convertMultiPointFeature(features, id, geojson.geometry, worldCoordinateHelper, geojson.properties);
|
|
172
229
|
return;
|
|
173
230
|
case "LineString":
|
|
174
|
-
convertLineStringFeature(features, id, geojson.geometry, tolerance,
|
|
231
|
+
convertLineStringFeature(features, id, geojson.geometry, tolerance, worldCoordinateHelper, geojson.properties);
|
|
175
232
|
return;
|
|
176
233
|
case "MultiLineString":
|
|
177
|
-
convertMultiLineStringFeature(features, id, geojson.geometry, tolerance,
|
|
234
|
+
convertMultiLineStringFeature(features, id, geojson.geometry, tolerance, worldCoordinateHelper, options, geojson.properties);
|
|
178
235
|
return;
|
|
179
236
|
case "Polygon":
|
|
180
|
-
convertPolygonFeature(features, id, geojson.geometry, tolerance,
|
|
237
|
+
convertPolygonFeature(features, id, geojson.geometry, tolerance, worldCoordinateHelper, geojson.properties);
|
|
181
238
|
return;
|
|
182
239
|
case "MultiPolygon":
|
|
183
|
-
convertMultiPolygonFeature(features, id, geojson.geometry, tolerance,
|
|
240
|
+
convertMultiPolygonFeature(features, id, geojson.geometry, tolerance, worldCoordinateHelper, geojson.properties);
|
|
184
241
|
return;
|
|
185
242
|
default: throw new Error("Input data is not a valid GeoJSON object.");
|
|
186
243
|
}
|
|
@@ -198,55 +255,55 @@ function convertGeometryCollection(features, geojson, geometry, options, index,
|
|
|
198
255
|
properties: geojson.properties
|
|
199
256
|
}, options, index, depth);
|
|
200
257
|
}
|
|
201
|
-
function convertPointFeature(features, id, geom,
|
|
258
|
+
function convertPointFeature(features, id, geom, worldCoordinateHelper, properties) {
|
|
202
259
|
const out = [];
|
|
203
|
-
out.push(projectX(geom.coordinates[0]
|
|
260
|
+
out.push(worldCoordinateHelper.projectX(geom.coordinates[0]), worldCoordinateHelper.projectY(geom.coordinates[1]), 0);
|
|
204
261
|
features.push(createFeature(id, "Point", out, properties));
|
|
205
262
|
}
|
|
206
|
-
function convertMultiPointFeature(features, id, geom,
|
|
263
|
+
function convertMultiPointFeature(features, id, geom, worldCoordinateHelper, properties) {
|
|
207
264
|
const out = [];
|
|
208
|
-
for (const coords of geom.coordinates) out.push(projectX(coords[0]
|
|
265
|
+
for (const coords of geom.coordinates) out.push(worldCoordinateHelper.projectX(coords[0]), worldCoordinateHelper.projectY(coords[1]), 0);
|
|
209
266
|
features.push(createFeature(id, "MultiPoint", out, properties));
|
|
210
267
|
}
|
|
211
|
-
function convertLineStringFeature(features, id, geom, tolerance,
|
|
268
|
+
function convertLineStringFeature(features, id, geom, tolerance, worldCoordinateHelper, properties) {
|
|
212
269
|
const out = { points: [] };
|
|
213
|
-
convertLine(geom.coordinates, out, tolerance, false,
|
|
270
|
+
convertLine(geom.coordinates, out, tolerance, false, worldCoordinateHelper);
|
|
214
271
|
features.push(createFeature(id, "LineString", out, properties));
|
|
215
272
|
}
|
|
216
|
-
function convertMultiLineStringFeature(features, id, geom, tolerance,
|
|
273
|
+
function convertMultiLineStringFeature(features, id, geom, tolerance, worldCoordinateHelper, options, properties) {
|
|
217
274
|
if (options.lineMetrics) for (const line of geom.coordinates) {
|
|
218
275
|
const out = { points: [] };
|
|
219
|
-
convertLine(line, out, tolerance, false,
|
|
276
|
+
convertLine(line, out, tolerance, false, worldCoordinateHelper);
|
|
220
277
|
features.push(createFeature(id, "LineString", out, properties));
|
|
221
278
|
}
|
|
222
279
|
else {
|
|
223
280
|
const out = [];
|
|
224
|
-
convertLines(geom.coordinates, out, tolerance, false,
|
|
281
|
+
convertLines(geom.coordinates, out, tolerance, false, worldCoordinateHelper);
|
|
225
282
|
features.push(createFeature(id, "MultiLineString", out, properties));
|
|
226
283
|
}
|
|
227
284
|
}
|
|
228
|
-
function convertPolygonFeature(features, id, geom, tolerance,
|
|
285
|
+
function convertPolygonFeature(features, id, geom, tolerance, worldCoordinateHelper, properties) {
|
|
229
286
|
const out = [];
|
|
230
|
-
convertLines(geom.coordinates, out, tolerance, true,
|
|
287
|
+
convertLines(geom.coordinates, out, tolerance, true, worldCoordinateHelper);
|
|
231
288
|
features.push(createFeature(id, "Polygon", out, properties));
|
|
232
289
|
}
|
|
233
|
-
function convertMultiPolygonFeature(features, id, geom, tolerance,
|
|
290
|
+
function convertMultiPolygonFeature(features, id, geom, tolerance, worldCoordinateHelper, properties) {
|
|
234
291
|
const out = [];
|
|
235
292
|
for (const polygon of geom.coordinates) {
|
|
236
293
|
const polygonOut = [];
|
|
237
|
-
convertLines(polygon, polygonOut, tolerance, true,
|
|
294
|
+
convertLines(polygon, polygonOut, tolerance, true, worldCoordinateHelper);
|
|
238
295
|
if (!polygonOut.length) continue;
|
|
239
296
|
out.push(polygonOut);
|
|
240
297
|
}
|
|
241
298
|
if (!out.length) return;
|
|
242
299
|
features.push(createFeature(id, "MultiPolygon", out, properties));
|
|
243
300
|
}
|
|
244
|
-
function convertLine(ring, out, tolerance, isPolygon,
|
|
301
|
+
function convertLine(ring, out, tolerance, isPolygon, worldCoordinateHelper) {
|
|
245
302
|
let x0, y0;
|
|
246
303
|
let size = 0;
|
|
247
304
|
for (let j = 0; j < ring.length; j++) {
|
|
248
|
-
const x = projectX(ring[j][0]
|
|
249
|
-
const y = projectY(ring[j][1]
|
|
305
|
+
const x = worldCoordinateHelper.projectX(ring[j][0]);
|
|
306
|
+
const y = worldCoordinateHelper.projectY(ring[j][1]);
|
|
250
307
|
out.points.push(x, y, 0);
|
|
251
308
|
if (j > 0) {
|
|
252
309
|
if (isPolygon) size += (x0 * y - x * y0) / 2;
|
|
@@ -264,47 +321,31 @@ function convertLine(ring, out, tolerance, isPolygon, worldCoordinates) {
|
|
|
264
321
|
out.start = 0;
|
|
265
322
|
out.end = out.size;
|
|
266
323
|
}
|
|
267
|
-
function convertLines(rings, out, tolerance, isPolygon,
|
|
324
|
+
function convertLines(rings, out, tolerance, isPolygon, worldCoordinateHelper) {
|
|
268
325
|
for (let i = 0; i < rings.length; i++) {
|
|
269
326
|
const geom = { points: [] };
|
|
270
|
-
convertLine(rings[i], geom, tolerance, isPolygon,
|
|
327
|
+
convertLine(rings[i], geom, tolerance, isPolygon, worldCoordinateHelper);
|
|
271
328
|
out.push(geom);
|
|
272
329
|
}
|
|
273
330
|
}
|
|
274
|
-
/**
|
|
275
|
-
* Convert longitude to spherical mercator in [0..1] range, or keep a world coordinate as it is
|
|
276
|
-
*/
|
|
277
|
-
function projectX(x, worldCoordinates = false) {
|
|
278
|
-
if (worldCoordinates) return x;
|
|
279
|
-
return x / 360 + .5;
|
|
280
|
-
}
|
|
281
|
-
/**
|
|
282
|
-
* Convert latitude to spherical mercator in [0..1] range, or keep a world coordinate as it is
|
|
283
|
-
*/
|
|
284
|
-
function projectY(y, worldCoordinates = false) {
|
|
285
|
-
if (worldCoordinates) return y;
|
|
286
|
-
const sin = Math.sin(y * Math.PI / 180);
|
|
287
|
-
const y2 = .5 - .25 * Math.log((1 + sin) / (1 - sin)) / Math.PI;
|
|
288
|
-
return y2 < 0 ? 0 : y2 > 1 ? 1 : y2;
|
|
289
|
-
}
|
|
290
331
|
//#endregion
|
|
291
332
|
//#region src/deconvert.ts
|
|
292
333
|
/**
|
|
293
334
|
* Converts internal source features back to GeoJSON format.
|
|
294
335
|
*/
|
|
295
|
-
function convertToGeoJSON(source,
|
|
336
|
+
function convertToGeoJSON(source, worldCoordinateHelper = mercatorWorldCoordinateHelper) {
|
|
296
337
|
return {
|
|
297
338
|
type: "FeatureCollection",
|
|
298
|
-
features: source.map((feature) => featureToGeoJSON(feature,
|
|
339
|
+
features: source.map((feature) => featureToGeoJSON(feature, worldCoordinateHelper))
|
|
299
340
|
};
|
|
300
341
|
}
|
|
301
342
|
/**
|
|
302
343
|
* Converts a single internal feature to GeoJSON format.
|
|
303
344
|
*/
|
|
304
|
-
function featureToGeoJSON(feature,
|
|
345
|
+
function featureToGeoJSON(feature, worldCoordinateHelper = mercatorWorldCoordinateHelper) {
|
|
305
346
|
const geojsonFeature = {
|
|
306
347
|
type: "Feature",
|
|
307
|
-
geometry: geometryToGeoJSON(feature,
|
|
348
|
+
geometry: geometryToGeoJSON(feature, worldCoordinateHelper),
|
|
308
349
|
properties: feature.tags
|
|
309
350
|
};
|
|
310
351
|
if (feature.id != null) geojsonFeature.id = feature.id;
|
|
@@ -313,54 +354,39 @@ function featureToGeoJSON(feature, worldCoordinates = false) {
|
|
|
313
354
|
/**
|
|
314
355
|
* Converts a single internal feature geometry to GeoJSON format.
|
|
315
356
|
*/
|
|
316
|
-
function geometryToGeoJSON(feature,
|
|
357
|
+
function geometryToGeoJSON(feature, worldCoordinateHelper) {
|
|
317
358
|
const { type, geometry } = feature;
|
|
318
359
|
switch (type) {
|
|
319
360
|
case "Point": return {
|
|
320
361
|
type,
|
|
321
|
-
coordinates: unprojectPoint(geometry[0], geometry[1],
|
|
362
|
+
coordinates: unprojectPoint(geometry[0], geometry[1], worldCoordinateHelper)
|
|
322
363
|
};
|
|
323
364
|
case "MultiPoint": return {
|
|
324
365
|
type,
|
|
325
|
-
coordinates: unprojectPoints(geometry,
|
|
366
|
+
coordinates: unprojectPoints(geometry, worldCoordinateHelper)
|
|
326
367
|
};
|
|
327
368
|
case "LineString": return {
|
|
328
369
|
type,
|
|
329
|
-
coordinates: unprojectPoints(geometry.points,
|
|
370
|
+
coordinates: unprojectPoints(geometry.points, worldCoordinateHelper)
|
|
330
371
|
};
|
|
331
372
|
case "MultiLineString":
|
|
332
373
|
case "Polygon": return {
|
|
333
374
|
type,
|
|
334
|
-
coordinates: geometry.map((ring) => unprojectPoints(ring.points,
|
|
375
|
+
coordinates: geometry.map((ring) => unprojectPoints(ring.points, worldCoordinateHelper))
|
|
335
376
|
};
|
|
336
377
|
case "MultiPolygon": return {
|
|
337
378
|
type,
|
|
338
|
-
coordinates: geometry.map((polygon) => polygon.map((ring) => unprojectPoints(ring.points,
|
|
379
|
+
coordinates: geometry.map((polygon) => polygon.map((ring) => unprojectPoints(ring.points, worldCoordinateHelper)))
|
|
339
380
|
};
|
|
340
381
|
}
|
|
341
382
|
}
|
|
342
|
-
function unprojectPoints(coords,
|
|
383
|
+
function unprojectPoints(coords, worldCoordinateHelper = mercatorWorldCoordinateHelper) {
|
|
343
384
|
const result = [];
|
|
344
|
-
for (let i = 0; i < coords.length; i += 3) result.push(unprojectPoint(coords[i], coords[i + 1],
|
|
385
|
+
for (let i = 0; i < coords.length; i += 3) result.push(unprojectPoint(coords[i], coords[i + 1], worldCoordinateHelper));
|
|
345
386
|
return result;
|
|
346
387
|
}
|
|
347
|
-
function unprojectPoint(x, y,
|
|
348
|
-
return [unprojectX(x
|
|
349
|
-
}
|
|
350
|
-
/**
|
|
351
|
-
* Convert spherical mercator in [0..1] range to longitude, or keep a world coordinate as it is
|
|
352
|
-
*/
|
|
353
|
-
function unprojectX(x, worldCoordinates = false) {
|
|
354
|
-
if (worldCoordinates) return x;
|
|
355
|
-
return (x - .5) * 360;
|
|
356
|
-
}
|
|
357
|
-
/**
|
|
358
|
-
* Convert spherical mercator in [0..1] range to latitude, or keep a world coordinate as it is
|
|
359
|
-
*/
|
|
360
|
-
function unprojectY(y, worldCoordinates = false) {
|
|
361
|
-
if (worldCoordinates) return y;
|
|
362
|
-
const y2 = (180 - y * 360) * Math.PI / 180;
|
|
363
|
-
return 360 * Math.atan(Math.exp(y2)) / Math.PI - 90;
|
|
388
|
+
function unprojectPoint(x, y, worldCoordinateHelper) {
|
|
389
|
+
return [worldCoordinateHelper.unprojectX(x), worldCoordinateHelper.unprojectY(y)];
|
|
364
390
|
}
|
|
365
391
|
//#endregion
|
|
366
392
|
//#region src/clip.ts
|
|
@@ -550,7 +576,7 @@ function intersectY(out, ax, ay, bx, by, y) {
|
|
|
550
576
|
//#endregion
|
|
551
577
|
//#region src/wrap.ts
|
|
552
578
|
function wrap(features, options) {
|
|
553
|
-
if (options.
|
|
579
|
+
if (!options.wrap) return features;
|
|
554
580
|
const buffer = options.buffer / options.extent;
|
|
555
581
|
let merged = features;
|
|
556
582
|
const left = clip(features, 1, -1 - buffer, buffer, 0, -1, 2, options);
|
|
@@ -620,16 +646,19 @@ function shiftLineCoords(line, offset) {
|
|
|
620
646
|
* @param source
|
|
621
647
|
* @param dataDiff
|
|
622
648
|
* @param options
|
|
649
|
+
* @param unlocated - the features without coordinates, by id, so that an update can give them some
|
|
623
650
|
* @returns
|
|
624
651
|
*/
|
|
625
|
-
function applySourceDiff(source, dataDiff, options) {
|
|
652
|
+
function applySourceDiff(source, dataDiff, options, unlocated) {
|
|
626
653
|
const diff = diffToHashed(dataDiff, options);
|
|
627
654
|
let affected = [];
|
|
628
655
|
if (diff.removeAll) {
|
|
629
656
|
affected = source;
|
|
630
657
|
source = [];
|
|
658
|
+
unlocated?.clear();
|
|
631
659
|
}
|
|
632
660
|
if (diff.remove.size || diff.add.size) {
|
|
661
|
+
for (const id of diff.remove) unlocated?.delete(id);
|
|
633
662
|
const removeFeatures = [];
|
|
634
663
|
for (const feature of source) if (diff.remove.has(feature.id) || diff.add.has(feature.id)) removeFeatures.push(feature);
|
|
635
664
|
if (removeFeatures.length) {
|
|
@@ -641,7 +670,7 @@ function applySourceDiff(source, dataDiff, options) {
|
|
|
641
670
|
let addFeatures = convertToInternal({
|
|
642
671
|
type: "FeatureCollection",
|
|
643
672
|
features: Array.from(diff.add.values())
|
|
644
|
-
}, options);
|
|
673
|
+
}, options, unlocated);
|
|
645
674
|
addFeatures = wrap(addFeatures, options);
|
|
646
675
|
affected = affected.concat(addFeatures);
|
|
647
676
|
source = source.concat(addFeatures);
|
|
@@ -654,8 +683,14 @@ function applySourceDiff(source, dataDiff, options) {
|
|
|
654
683
|
else keepFeatures.push(feature);
|
|
655
684
|
for (const [id, update] of diff.update) {
|
|
656
685
|
const oldFeatures = oldFeaturesMap.get(id);
|
|
657
|
-
if (!oldFeatures || oldFeatures.length === 0)
|
|
658
|
-
|
|
686
|
+
if (!oldFeatures || oldFeatures.length === 0) {
|
|
687
|
+
if (!unlocated?.has(id)) continue;
|
|
688
|
+
const locatedFeatures = getUpdatedUnlocatedFeatures(id, update, options, unlocated);
|
|
689
|
+
affected = affected.concat(locatedFeatures);
|
|
690
|
+
keepFeatures = keepFeatures.concat(locatedFeatures);
|
|
691
|
+
continue;
|
|
692
|
+
}
|
|
693
|
+
const updatedFeatures = getUpdatedFeatures(oldFeatures, update, options, unlocated);
|
|
659
694
|
affected = affected.concat(oldFeatures, updatedFeatures);
|
|
660
695
|
keepFeatures = keepFeatures.concat(updatedFeatures);
|
|
661
696
|
}
|
|
@@ -671,28 +706,16 @@ function applySourceDiff(source, dataDiff, options) {
|
|
|
671
706
|
* @param vtFeatures - the original features
|
|
672
707
|
* @param update - the update object to apply
|
|
673
708
|
* @param options - the options to use for the wrap method
|
|
709
|
+
* @param unlocated - the features without coordinates, by id, which a new geometry without coordinates adds the feature to
|
|
674
710
|
* @returns Updated features. If geometry is updated, returns new feature(s) converted from geojson and wrapped, with the id the feature already has. If only properties are updated, returns feature(s) with tags updated.
|
|
675
711
|
*/
|
|
676
|
-
function getUpdatedFeatures(vtFeatures, update, options) {
|
|
712
|
+
function getUpdatedFeatures(vtFeatures, update, options, unlocated) {
|
|
677
713
|
const changeGeometry = !!update.newGeometry;
|
|
678
|
-
const changeProps = update
|
|
714
|
+
const changeProps = hasPropertyChanges(update);
|
|
679
715
|
if (changeGeometry) {
|
|
680
716
|
const vtFeature = vtFeatures[0];
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
features: [{
|
|
684
|
-
type: "Feature",
|
|
685
|
-
id: vtFeature.id,
|
|
686
|
-
geometry: update.newGeometry,
|
|
687
|
-
properties: changeProps ? applyPropertyUpdates(vtFeature.tags, update) : vtFeature.tags
|
|
688
|
-
}]
|
|
689
|
-
}, {
|
|
690
|
-
...options,
|
|
691
|
-
promoteId: void 0,
|
|
692
|
-
generateId: false
|
|
693
|
-
});
|
|
694
|
-
features = wrap(features, options);
|
|
695
|
-
return features;
|
|
717
|
+
const properties = changeProps ? applyPropertyUpdates(vtFeature.tags, update) : vtFeature.tags;
|
|
718
|
+
return convertNewGeometry(vtFeature.id, update.newGeometry, properties, options, unlocated);
|
|
696
719
|
}
|
|
697
720
|
if (changeProps) {
|
|
698
721
|
const updated = [];
|
|
@@ -706,6 +729,43 @@ function getUpdatedFeatures(vtFeatures, update, options) {
|
|
|
706
729
|
return vtFeatures;
|
|
707
730
|
}
|
|
708
731
|
/**
|
|
732
|
+
* Gets the features an update gives a feature without coordinates: none, unless its new geometry has some.
|
|
733
|
+
* Its property changes apply either way.
|
|
734
|
+
*/
|
|
735
|
+
function getUpdatedUnlocatedFeatures(id, update, options, unlocated) {
|
|
736
|
+
const feature = unlocated.get(id);
|
|
737
|
+
const properties = hasPropertyChanges(update) ? applyPropertyUpdates(feature.properties, update) : feature.properties;
|
|
738
|
+
if (!update.newGeometry) {
|
|
739
|
+
unlocated.set(id, {
|
|
740
|
+
...feature,
|
|
741
|
+
properties
|
|
742
|
+
});
|
|
743
|
+
return [];
|
|
744
|
+
}
|
|
745
|
+
return convertNewGeometry(id, update.newGeometry, properties, options, unlocated);
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Converts the new geometry of a feature to internal format, keeping the id the feature already has
|
|
749
|
+
*/
|
|
750
|
+
function convertNewGeometry(id, geometry, properties, options, unlocated) {
|
|
751
|
+
return wrap(convertToInternal({
|
|
752
|
+
type: "FeatureCollection",
|
|
753
|
+
features: [{
|
|
754
|
+
type: "Feature",
|
|
755
|
+
id,
|
|
756
|
+
geometry,
|
|
757
|
+
properties
|
|
758
|
+
}]
|
|
759
|
+
}, {
|
|
760
|
+
...options,
|
|
761
|
+
promoteId: void 0,
|
|
762
|
+
generateId: false
|
|
763
|
+
}, unlocated), options);
|
|
764
|
+
}
|
|
765
|
+
function hasPropertyChanges(update) {
|
|
766
|
+
return update.removeAllProperties || update.removeProperties?.length > 0 || update.addOrUpdateProperties?.length > 0;
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
709
769
|
* helper to apply property updates from a diff update object to a properties object
|
|
710
770
|
*/
|
|
711
771
|
function applyPropertyUpdates(tags, update) {
|
|
@@ -1028,7 +1088,9 @@ const defaultClusterOptions = {
|
|
|
1028
1088
|
log: false,
|
|
1029
1089
|
generateId: false,
|
|
1030
1090
|
reduce: null,
|
|
1031
|
-
map: (props) => props
|
|
1091
|
+
map: (props) => props,
|
|
1092
|
+
coordinates: "lngLat",
|
|
1093
|
+
wrap: true
|
|
1032
1094
|
};
|
|
1033
1095
|
/**
|
|
1034
1096
|
* The highest zoom level to cluster on. A cluster id keeps its zoom level in five bits.
|
|
@@ -1068,9 +1130,9 @@ const OFFSET_PROP = 4;
|
|
|
1068
1130
|
* This class allow clustering of geojson points.
|
|
1069
1131
|
*/
|
|
1070
1132
|
var ClusterTileIndex = class {
|
|
1071
|
-
constructor(options
|
|
1133
|
+
constructor(options) {
|
|
1072
1134
|
this.options = createOptions(options);
|
|
1073
|
-
this.
|
|
1135
|
+
this.worldCoordinateHelper = getWorldCoordinateHelper(this.options.coordinates);
|
|
1074
1136
|
this.trees = new Array(this.options.maxZoom + 1);
|
|
1075
1137
|
this.stride = this.options.reduce ? 5 : 4;
|
|
1076
1138
|
this.clusterProps = [];
|
|
@@ -1087,8 +1149,8 @@ var ClusterTileIndex = class {
|
|
|
1087
1149
|
if (!point.geometry) continue;
|
|
1088
1150
|
const positions = point.geometry.type === "MultiPoint" ? point.geometry.coordinates : [point.geometry.coordinates];
|
|
1089
1151
|
for (const [lng, lat] of positions) {
|
|
1090
|
-
const [x, y] = [projectX(lng, this.
|
|
1091
|
-
if (this.
|
|
1152
|
+
const [x, y] = [this.worldCoordinateHelper.projectX(lng), this.worldCoordinateHelper.projectY(lat)];
|
|
1153
|
+
if (!this.options.wrap && !isInWorld([x, y])) continue;
|
|
1092
1154
|
const feature = {
|
|
1093
1155
|
id: point.id,
|
|
1094
1156
|
type: "Point",
|
|
@@ -1110,14 +1172,14 @@ var ClusterTileIndex = class {
|
|
|
1110
1172
|
const points = [];
|
|
1111
1173
|
for (const feature of features) {
|
|
1112
1174
|
if (feature.type === "Point") {
|
|
1113
|
-
if (this.
|
|
1175
|
+
if (!this.options.wrap && !isInWorld(feature.geometry)) continue;
|
|
1114
1176
|
points.push(feature);
|
|
1115
1177
|
continue;
|
|
1116
1178
|
}
|
|
1117
1179
|
if (feature.type !== "MultiPoint") continue;
|
|
1118
1180
|
for (let i = 0; i < feature.geometry.length; i += 3) {
|
|
1119
1181
|
const geometry = [feature.geometry[i], feature.geometry[i + 1]];
|
|
1120
|
-
if (this.
|
|
1182
|
+
if (!this.options.wrap && !isInWorld(geometry)) continue;
|
|
1121
1183
|
points.push({
|
|
1122
1184
|
id: feature.id,
|
|
1123
1185
|
type: "Point",
|
|
@@ -1134,7 +1196,11 @@ var ClusterTileIndex = class {
|
|
|
1134
1196
|
* @param features
|
|
1135
1197
|
*/
|
|
1136
1198
|
updateIndex(features, _affected, options) {
|
|
1137
|
-
this.options = createOptions(
|
|
1199
|
+
this.options = createOptions({
|
|
1200
|
+
...options.clusterOptions,
|
|
1201
|
+
coordinates: this.options.coordinates,
|
|
1202
|
+
wrap: this.options.wrap
|
|
1203
|
+
});
|
|
1138
1204
|
this.initialize(features);
|
|
1139
1205
|
}
|
|
1140
1206
|
/**
|
|
@@ -1182,11 +1248,61 @@ var ClusterTileIndex = class {
|
|
|
1182
1248
|
}
|
|
1183
1249
|
/**
|
|
1184
1250
|
* Returns clusters and/or points within a bounding box at a given zoom level.
|
|
1185
|
-
* @param bbox - Bounding box in `[westLng, southLat, eastLng, northLat]` order, or `[minX, minY, maxX, maxY]` in
|
|
1251
|
+
* @param bbox - Bounding box in `[westLng, southLat, eastLng, northLat]` order, or `[minX, minY, maxX, maxY]` in the unit square with `coordinates: 'unitSquare'`.
|
|
1252
|
+
* In a world that wraps, the box can reach across the antimeridian. In one that doesn't, only its part inside the world counts.
|
|
1186
1253
|
* @param zoom - Zoom level to query.
|
|
1187
1254
|
*/
|
|
1188
1255
|
getClusters(bbox, zoom) {
|
|
1189
|
-
return (this.
|
|
1256
|
+
return (!this.options.wrap ? this.getClustersInWorld(bbox, zoom) : this.options.coordinates === "unitSquare" ? this.getClustersAcrossEdge(bbox, zoom) : this.getClustersInternal(bbox, zoom)).map((f) => featureToGeoJSON(f, this.worldCoordinateHelper));
|
|
1257
|
+
}
|
|
1258
|
+
/**
|
|
1259
|
+
* The clusters and points in the part of a box inside a world that ends at its edges.
|
|
1260
|
+
*/
|
|
1261
|
+
getClustersInWorld(bbox, zoom) {
|
|
1262
|
+
const lngLat = this.options.coordinates !== "unitSquare";
|
|
1263
|
+
const y1 = this.worldCoordinateHelper.projectY(lngLat ? Math.max(-90, Math.min(90, bbox[1])) : bbox[1]);
|
|
1264
|
+
const y2 = this.worldCoordinateHelper.projectY(lngLat ? Math.max(-90, Math.min(90, bbox[3])) : bbox[3]);
|
|
1265
|
+
const minX = Math.max(0, this.worldCoordinateHelper.projectX(bbox[0]));
|
|
1266
|
+
const maxX = Math.min(1, this.worldCoordinateHelper.projectX(bbox[2]));
|
|
1267
|
+
if (minX > maxX) return [];
|
|
1268
|
+
return this.getClustersInRange([
|
|
1269
|
+
minX,
|
|
1270
|
+
Math.min(y1, y2),
|
|
1271
|
+
maxX,
|
|
1272
|
+
Math.max(y1, y2)
|
|
1273
|
+
], zoom);
|
|
1274
|
+
}
|
|
1275
|
+
/**
|
|
1276
|
+
* The clusters and points in a box of a unit square that wraps, where the box can reach across its left or right edge.
|
|
1277
|
+
*/
|
|
1278
|
+
getClustersAcrossEdge([minX, minY, maxX, maxY], zoom) {
|
|
1279
|
+
if (maxX < minX) maxX += 1;
|
|
1280
|
+
if (maxX - minX >= 1) return this.getClustersInRange([
|
|
1281
|
+
0,
|
|
1282
|
+
minY,
|
|
1283
|
+
1,
|
|
1284
|
+
maxY
|
|
1285
|
+
], zoom);
|
|
1286
|
+
const shift = Math.floor(minX);
|
|
1287
|
+
const west = minX - shift;
|
|
1288
|
+
const east = maxX - shift;
|
|
1289
|
+
if (east <= 1) return this.getClustersInRange([
|
|
1290
|
+
west,
|
|
1291
|
+
minY,
|
|
1292
|
+
east,
|
|
1293
|
+
maxY
|
|
1294
|
+
], zoom);
|
|
1295
|
+
return this.getClustersInRange([
|
|
1296
|
+
west,
|
|
1297
|
+
minY,
|
|
1298
|
+
1,
|
|
1299
|
+
maxY
|
|
1300
|
+
], zoom).concat(this.getClustersInRange([
|
|
1301
|
+
0,
|
|
1302
|
+
minY,
|
|
1303
|
+
east - 1,
|
|
1304
|
+
maxY
|
|
1305
|
+
], zoom));
|
|
1190
1306
|
}
|
|
1191
1307
|
getClustersInternal(bbox, zoom) {
|
|
1192
1308
|
let minLng = ((bbox[0] + 180) % 360 + 360) % 360 - 180;
|
|
@@ -1212,10 +1328,10 @@ var ClusterTileIndex = class {
|
|
|
1212
1328
|
return easternHem.concat(westernHem);
|
|
1213
1329
|
}
|
|
1214
1330
|
return this.getClustersInRange([
|
|
1215
|
-
projectX(minLng),
|
|
1216
|
-
projectY(maxLat),
|
|
1217
|
-
projectX(maxLng),
|
|
1218
|
-
projectY(minLat)
|
|
1331
|
+
this.worldCoordinateHelper.projectX(minLng),
|
|
1332
|
+
this.worldCoordinateHelper.projectY(maxLat),
|
|
1333
|
+
this.worldCoordinateHelper.projectX(maxLng),
|
|
1334
|
+
this.worldCoordinateHelper.projectY(minLat)
|
|
1219
1335
|
], zoom);
|
|
1220
1336
|
}
|
|
1221
1337
|
/**
|
|
@@ -1253,7 +1369,7 @@ var ClusterTileIndex = class {
|
|
|
1253
1369
|
const children = [];
|
|
1254
1370
|
for (const id of ids) {
|
|
1255
1371
|
const k = id * this.stride;
|
|
1256
|
-
if (data[k + OFFSET_PARENT] === clusterId) children.push(data[k + OFFSET_NUM] > 1 ? getClusterGeoJSON(coords, id, data, k, this.clusterProps, this.
|
|
1372
|
+
if (data[k + OFFSET_PARENT] === clusterId) children.push(data[k + OFFSET_NUM] > 1 ? getClusterGeoJSON(coords, id, data, k, this.clusterProps, this.worldCoordinateHelper) : featureToGeoJSON(this.points[data[k + OFFSET_ID]], this.worldCoordinateHelper));
|
|
1257
1373
|
}
|
|
1258
1374
|
if (children.length === 0) throw clusterError;
|
|
1259
1375
|
return children;
|
|
@@ -1281,7 +1397,7 @@ var ClusterTileIndex = class {
|
|
|
1281
1397
|
const tree = this.trees[this.limitZoom(z)];
|
|
1282
1398
|
if (!tree) return null;
|
|
1283
1399
|
const z2 = Math.pow(2, z);
|
|
1284
|
-
if (this.
|
|
1400
|
+
if (!this.options.wrap && (x < 0 || x >= z2 || y < 0 || y >= z2)) return null;
|
|
1285
1401
|
const { extent, radius } = this.options;
|
|
1286
1402
|
const p = radius / extent;
|
|
1287
1403
|
const top = encode((y - p) / z2);
|
|
@@ -1295,8 +1411,8 @@ var ClusterTileIndex = class {
|
|
|
1295
1411
|
z
|
|
1296
1412
|
};
|
|
1297
1413
|
this.addTileFeatures(tree.range(encode((x - p) / z2), top, encode((x + 1 + p) / z2), bottom), tree, x, y, z2, tile);
|
|
1298
|
-
if (
|
|
1299
|
-
if (
|
|
1414
|
+
if (this.options.wrap && x === 0) this.addTileFeatures(tree.range(encode(1 - p / z2), top, encode(1), bottom), tree, z2, y, z2, tile);
|
|
1415
|
+
if (this.options.wrap && x === z2 - 1) this.addTileFeatures(tree.range(encode(0), top, encode(p / z2), bottom), tree, -1, y, z2, tile);
|
|
1300
1416
|
return tile;
|
|
1301
1417
|
}
|
|
1302
1418
|
/**
|
|
@@ -1479,14 +1595,14 @@ function getClusterFeature(coords, index, data, i, clusterProps) {
|
|
|
1479
1595
|
geometry: [decode(coords[index * 2]), decode(coords[index * 2 + 1])]
|
|
1480
1596
|
};
|
|
1481
1597
|
}
|
|
1482
|
-
function getClusterGeoJSON(coords, index, data, i, clusterProps,
|
|
1598
|
+
function getClusterGeoJSON(coords, index, data, i, clusterProps, worldCoordinateHelper) {
|
|
1483
1599
|
return {
|
|
1484
1600
|
type: "Feature",
|
|
1485
1601
|
id: data[i + OFFSET_ID],
|
|
1486
1602
|
properties: getClusterProperties(data, i, clusterProps),
|
|
1487
1603
|
geometry: {
|
|
1488
1604
|
type: "Point",
|
|
1489
|
-
coordinates: [unprojectX(decode(coords[index * 2])
|
|
1605
|
+
coordinates: [worldCoordinateHelper.unprojectX(decode(coords[index * 2])), worldCoordinateHelper.unprojectY(decode(coords[index * 2 + 1]))]
|
|
1490
1606
|
}
|
|
1491
1607
|
};
|
|
1492
1608
|
}
|
|
@@ -1766,7 +1882,7 @@ var TileIndex = class {
|
|
|
1766
1882
|
getTile(z, x, y) {
|
|
1767
1883
|
const { extent, debug } = this.options;
|
|
1768
1884
|
const z2 = 1 << z;
|
|
1769
|
-
if (this.options.
|
|
1885
|
+
if (!this.options.wrap && (x < 0 || x >= z2)) return null;
|
|
1770
1886
|
x = x + z2 & z2 - 1;
|
|
1771
1887
|
const id = toID(z, x, y);
|
|
1772
1888
|
if (this.tiles[id]) return transformTile(this.tiles[id], extent);
|
|
@@ -1792,14 +1908,16 @@ var TileIndex = class {
|
|
|
1792
1908
|
return transformTile(this.tiles[id], extent);
|
|
1793
1909
|
}
|
|
1794
1910
|
/**
|
|
1795
|
-
* The features the top tile starts from
|
|
1796
|
-
* and only what lies inside the world square and its buffer
|
|
1797
|
-
*
|
|
1911
|
+
* The features the top tile starts from. A world that wraps keeps them all left and right, where wrapping already
|
|
1912
|
+
* put them inside, and one that doesn't only what lies inside the world square and its buffer. Positions in the
|
|
1913
|
+
* unit square are also cut above and below in a world that wraps, where lng/lat is clamped already. The index keeps
|
|
1914
|
+
* the rest, so an update can still move a feature in from outside.
|
|
1798
1915
|
*/
|
|
1799
1916
|
clipToWorld(features) {
|
|
1800
|
-
|
|
1917
|
+
const { wrap, coordinates } = this.options;
|
|
1918
|
+
if (wrap && coordinates !== "unitSquare") return features;
|
|
1801
1919
|
const buffer = this.options.buffer / this.options.extent;
|
|
1802
|
-
return clip(clip(features, 1, -buffer, 1 + buffer, 0, -Infinity, Infinity, this.options) || [], 1, -buffer, 1 + buffer, 1, -Infinity, Infinity, this.options) || [];
|
|
1920
|
+
return clip(wrap ? features : clip(features, 1, -buffer, 1 + buffer, 0, -Infinity, Infinity, this.options) || [], 1, -buffer, 1 + buffer, 1, -Infinity, Infinity, this.options) || [];
|
|
1803
1921
|
}
|
|
1804
1922
|
/**
|
|
1805
1923
|
* splits features from a parent tile to sub-tiles.
|
|
@@ -1955,7 +2073,8 @@ const defaultOptions = {
|
|
|
1955
2073
|
cluster: false,
|
|
1956
2074
|
clusterOptions: defaultClusterOptions,
|
|
1957
2075
|
debug: 0,
|
|
1958
|
-
|
|
2076
|
+
coordinates: "lngLat",
|
|
2077
|
+
wrap: true
|
|
1959
2078
|
};
|
|
1960
2079
|
/**
|
|
1961
2080
|
* Main class for creating and managing a vector tile index from GeoJSON data.
|
|
@@ -1963,11 +2082,13 @@ const defaultOptions = {
|
|
|
1963
2082
|
var GeoJSONVT = class {
|
|
1964
2083
|
constructor(data, options) {
|
|
1965
2084
|
options = this.options = Object.assign({}, defaultOptions, options);
|
|
2085
|
+
this.worldCoordinateHelper = getWorldCoordinateHelper(options.coordinates);
|
|
1966
2086
|
const debug = options.debug;
|
|
1967
2087
|
if (debug) console.time("preprocess data");
|
|
1968
2088
|
if (options.maxZoom < 0 || options.maxZoom > 24) throw new Error("maxZoom should be in the 0-24 range");
|
|
1969
2089
|
if (options.promoteId && options.generateId) throw new Error("promoteId and generateId cannot be used together.");
|
|
1970
|
-
|
|
2090
|
+
if (options.updateable) this.unlocated = /* @__PURE__ */ new Map();
|
|
2091
|
+
let features = convertToInternal(data, options, this.unlocated);
|
|
1971
2092
|
if (debug) {
|
|
1972
2093
|
console.timeEnd("preprocess data");
|
|
1973
2094
|
console.log("index: maxZoom: %d, maxPoints: %d", options.indexMaxZoom, options.indexMaxPoints);
|
|
@@ -1978,7 +2099,11 @@ var GeoJSONVT = class {
|
|
|
1978
2099
|
this.initializeIndex(features, options);
|
|
1979
2100
|
}
|
|
1980
2101
|
initializeIndex(features, options) {
|
|
1981
|
-
this.tileIndex = options.cluster ? new ClusterTileIndex(
|
|
2102
|
+
this.tileIndex = options.cluster ? new ClusterTileIndex({
|
|
2103
|
+
...options.clusterOptions,
|
|
2104
|
+
coordinates: options.coordinates,
|
|
2105
|
+
wrap: options.wrap
|
|
2106
|
+
}) : new TileIndex(options);
|
|
1982
2107
|
if (!features.length) return;
|
|
1983
2108
|
this.tileIndex.initialize(features);
|
|
1984
2109
|
}
|
|
@@ -2003,24 +2128,27 @@ var GeoJSONVT = class {
|
|
|
2003
2128
|
updateData(diff, filter) {
|
|
2004
2129
|
const options = this.options;
|
|
2005
2130
|
if (!options.updateable) throw new Error("to update tile geojson `updateable` option must be set to true");
|
|
2006
|
-
let { affected, source } = applySourceDiff(this.source, diff, options);
|
|
2131
|
+
let { affected, source } = applySourceDiff(this.source, diff, options, this.unlocated);
|
|
2007
2132
|
if (filter) ({affected, source} = this.filterUpdate(source, affected, filter));
|
|
2008
2133
|
if (!affected.length) return;
|
|
2009
2134
|
this.source = source;
|
|
2010
2135
|
this.tileIndex.updateIndex(source, affected, options);
|
|
2011
2136
|
}
|
|
2012
2137
|
/**
|
|
2013
|
-
* Filter an update using a predicate function
|
|
2138
|
+
* Filter an update using a predicate function, the features an update emptied included, so that one the filter
|
|
2139
|
+
* rejects can't come back with a later update. A feature without a geometry at all isn't passed to the predicate.
|
|
2140
|
+
* Returns the affected and updated source features.
|
|
2014
2141
|
*/
|
|
2015
2142
|
filterUpdate(source, affected, predicate) {
|
|
2016
2143
|
const removeIds = /* @__PURE__ */ new Set();
|
|
2017
2144
|
for (const feature of source) {
|
|
2018
2145
|
if (feature.id == void 0) continue;
|
|
2019
|
-
if (predicate(featureToGeoJSON(feature, this.
|
|
2146
|
+
if (predicate(featureToGeoJSON(feature, this.worldCoordinateHelper))) continue;
|
|
2020
2147
|
affected.push(feature);
|
|
2021
2148
|
removeIds.add(feature.id);
|
|
2022
2149
|
}
|
|
2023
2150
|
source = source.filter((feature) => !removeIds.has(feature.id));
|
|
2151
|
+
for (const [id, feature] of this.unlocated ?? []) if (feature.geometry && !predicate(feature)) this.unlocated.delete(id);
|
|
2024
2152
|
return {
|
|
2025
2153
|
affected,
|
|
2026
2154
|
source
|
|
@@ -2031,12 +2159,12 @@ var GeoJSONVT = class {
|
|
|
2031
2159
|
*/
|
|
2032
2160
|
getData() {
|
|
2033
2161
|
if (!this.options.updateable) throw new Error("to retrieve data the `updateable` option must be set to true");
|
|
2034
|
-
return convertToGeoJSON(this.source, this.
|
|
2162
|
+
return convertToGeoJSON(this.source, this.worldCoordinateHelper);
|
|
2035
2163
|
}
|
|
2036
2164
|
/**
|
|
2037
2165
|
* Update supercluster options and regenerate the index.
|
|
2038
2166
|
* @param cluster - whether to enable clustering
|
|
2039
|
-
* @param clusterOptions - {@link SuperclusterOptions}
|
|
2167
|
+
* @param clusterOptions - {@link SuperclusterOptions} without `coordinates` and `wrap`, which come from the index options
|
|
2040
2168
|
*/
|
|
2041
2169
|
updateClusterOptions(cluster, clusterOptions) {
|
|
2042
2170
|
const wasCluster = this.options.cluster;
|
|
@@ -2112,9 +2240,10 @@ var GeoJSONVT = class {
|
|
|
2112
2240
|
function geoJSONToTile(data, z, x, y, options = {}) {
|
|
2113
2241
|
options = {
|
|
2114
2242
|
...defaultOptions,
|
|
2243
|
+
wrap: false,
|
|
2115
2244
|
...options
|
|
2116
2245
|
};
|
|
2117
|
-
const { wrap: shouldWrap
|
|
2246
|
+
const { wrap: shouldWrap, clip: shouldClip = false } = options;
|
|
2118
2247
|
let features = convertToInternal(data, options);
|
|
2119
2248
|
if (shouldWrap) features = wrap(features, options);
|
|
2120
2249
|
if (shouldClip || options.lineMetrics) {
|