@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-dev.js
CHANGED
|
@@ -134,6 +134,51 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
//#endregion
|
|
138
|
+
//#region src/world-coordinate-helper.ts
|
|
139
|
+
/**
|
|
140
|
+
* Longitude and latitude, which spherical mercator puts in the world square.
|
|
141
|
+
*/
|
|
142
|
+
var MercatorWorldCoordinateHelper = class {
|
|
143
|
+
projectX(lng) {
|
|
144
|
+
return lng / 360 + .5;
|
|
145
|
+
}
|
|
146
|
+
projectY(lat) {
|
|
147
|
+
const sin = Math.sin(lat * Math.PI / 180);
|
|
148
|
+
const y = .5 - .25 * Math.log((1 + sin) / (1 - sin)) / Math.PI;
|
|
149
|
+
return y < 0 ? 0 : y > 1 ? 1 : y;
|
|
150
|
+
}
|
|
151
|
+
unprojectX(x) {
|
|
152
|
+
return (x - .5) * 360;
|
|
153
|
+
}
|
|
154
|
+
unprojectY(y) {
|
|
155
|
+
const y2 = (180 - y * 360) * Math.PI / 180;
|
|
156
|
+
return 360 * Math.atan(Math.exp(y2)) / Math.PI - 90;
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Positions in the unit square already, see `coordinates` in {@link GeoJSONVTOptions}.
|
|
161
|
+
*/
|
|
162
|
+
var IdentityWorldCoordinateHelper = class {
|
|
163
|
+
projectX(x) {
|
|
164
|
+
return x;
|
|
165
|
+
}
|
|
166
|
+
projectY(y) {
|
|
167
|
+
return y;
|
|
168
|
+
}
|
|
169
|
+
unprojectX(x) {
|
|
170
|
+
return x;
|
|
171
|
+
}
|
|
172
|
+
unprojectY(y) {
|
|
173
|
+
return y;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
const mercatorWorldCoordinateHelper = new MercatorWorldCoordinateHelper();
|
|
177
|
+
const identityWorldCoordinateHelper = new IdentityWorldCoordinateHelper();
|
|
178
|
+
function getWorldCoordinateHelper(coordinates) {
|
|
179
|
+
return coordinates === "unitSquare" ? identityWorldCoordinateHelper : mercatorWorldCoordinateHelper;
|
|
180
|
+
}
|
|
181
|
+
|
|
137
182
|
//#endregion
|
|
138
183
|
//#region src/convert.ts
|
|
139
184
|
const MAX_GEOMETRY_COLLECTION_DEPTH = 1024;
|
|
@@ -141,25 +186,38 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
141
186
|
* converts GeoJSON to internal source features (an intermediate projected JSON vector format with simplification data)
|
|
142
187
|
* @param data
|
|
143
188
|
* @param options
|
|
189
|
+
* @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
|
|
144
190
|
* @returns
|
|
145
191
|
*/
|
|
146
|
-
function convertToInternal(data, options) {
|
|
192
|
+
function convertToInternal(data, options, unlocated) {
|
|
147
193
|
const features = [];
|
|
148
194
|
switch (data.type) {
|
|
149
195
|
case "FeatureCollection":
|
|
150
|
-
for (let i = 0; i < data.features.length; i++)
|
|
196
|
+
for (let i = 0; i < data.features.length; i++) convertFeature(features, data.features[i], options, unlocated, i);
|
|
151
197
|
break;
|
|
152
198
|
case "Feature":
|
|
153
|
-
|
|
199
|
+
convertFeature(features, data, options, unlocated);
|
|
154
200
|
break;
|
|
155
|
-
default:
|
|
201
|
+
default: convertFeature(features, {
|
|
156
202
|
type: "Feature",
|
|
157
203
|
geometry: data,
|
|
158
204
|
properties: void 0
|
|
159
|
-
}, options);
|
|
205
|
+
}, options, unlocated);
|
|
160
206
|
}
|
|
161
207
|
return features;
|
|
162
208
|
}
|
|
209
|
+
function convertFeature(features, geojson, options, unlocated, index) {
|
|
210
|
+
const count = features.length;
|
|
211
|
+
featureToInternal(features, geojson, options, index);
|
|
212
|
+
if (!unlocated) return;
|
|
213
|
+
const id = getFeatureId(geojson, options, index);
|
|
214
|
+
if (id == null) return;
|
|
215
|
+
if (features.length > count) unlocated.delete(id);
|
|
216
|
+
else unlocated.set(id, {
|
|
217
|
+
...geojson,
|
|
218
|
+
id
|
|
219
|
+
});
|
|
220
|
+
}
|
|
163
221
|
function featureToInternal(features, geojson, options, index, depth = 0) {
|
|
164
222
|
if (!geojson.geometry) return;
|
|
165
223
|
if (depth > MAX_GEOMETRY_COLLECTION_DEPTH) throw new Error("GeometryCollection nesting exceeds supported depth: 1024");
|
|
@@ -170,25 +228,25 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
170
228
|
if (!geojson.geometry.coordinates?.length) return;
|
|
171
229
|
const id = getFeatureId(geojson, options, index);
|
|
172
230
|
const tolerance = Math.pow(options.tolerance / ((1 << options.maxZoom) * options.extent), 2);
|
|
173
|
-
const
|
|
231
|
+
const worldCoordinateHelper = getWorldCoordinateHelper(options.coordinates);
|
|
174
232
|
switch (geojson.geometry.type) {
|
|
175
233
|
case "Point":
|
|
176
|
-
convertPointFeature(features, id, geojson.geometry,
|
|
234
|
+
convertPointFeature(features, id, geojson.geometry, worldCoordinateHelper, geojson.properties);
|
|
177
235
|
return;
|
|
178
236
|
case "MultiPoint":
|
|
179
|
-
convertMultiPointFeature(features, id, geojson.geometry,
|
|
237
|
+
convertMultiPointFeature(features, id, geojson.geometry, worldCoordinateHelper, geojson.properties);
|
|
180
238
|
return;
|
|
181
239
|
case "LineString":
|
|
182
|
-
convertLineStringFeature(features, id, geojson.geometry, tolerance,
|
|
240
|
+
convertLineStringFeature(features, id, geojson.geometry, tolerance, worldCoordinateHelper, geojson.properties);
|
|
183
241
|
return;
|
|
184
242
|
case "MultiLineString":
|
|
185
|
-
convertMultiLineStringFeature(features, id, geojson.geometry, tolerance,
|
|
243
|
+
convertMultiLineStringFeature(features, id, geojson.geometry, tolerance, worldCoordinateHelper, options, geojson.properties);
|
|
186
244
|
return;
|
|
187
245
|
case "Polygon":
|
|
188
|
-
convertPolygonFeature(features, id, geojson.geometry, tolerance,
|
|
246
|
+
convertPolygonFeature(features, id, geojson.geometry, tolerance, worldCoordinateHelper, geojson.properties);
|
|
189
247
|
return;
|
|
190
248
|
case "MultiPolygon":
|
|
191
|
-
convertMultiPolygonFeature(features, id, geojson.geometry, tolerance,
|
|
249
|
+
convertMultiPolygonFeature(features, id, geojson.geometry, tolerance, worldCoordinateHelper, geojson.properties);
|
|
192
250
|
return;
|
|
193
251
|
default: throw new Error("Input data is not a valid GeoJSON object.");
|
|
194
252
|
}
|
|
@@ -206,55 +264,55 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
206
264
|
properties: geojson.properties
|
|
207
265
|
}, options, index, depth);
|
|
208
266
|
}
|
|
209
|
-
function convertPointFeature(features, id, geom,
|
|
267
|
+
function convertPointFeature(features, id, geom, worldCoordinateHelper, properties) {
|
|
210
268
|
const out = [];
|
|
211
|
-
out.push(projectX(geom.coordinates[0]
|
|
269
|
+
out.push(worldCoordinateHelper.projectX(geom.coordinates[0]), worldCoordinateHelper.projectY(geom.coordinates[1]), 0);
|
|
212
270
|
features.push(createFeature(id, "Point", out, properties));
|
|
213
271
|
}
|
|
214
|
-
function convertMultiPointFeature(features, id, geom,
|
|
272
|
+
function convertMultiPointFeature(features, id, geom, worldCoordinateHelper, properties) {
|
|
215
273
|
const out = [];
|
|
216
|
-
for (const coords of geom.coordinates) out.push(projectX(coords[0]
|
|
274
|
+
for (const coords of geom.coordinates) out.push(worldCoordinateHelper.projectX(coords[0]), worldCoordinateHelper.projectY(coords[1]), 0);
|
|
217
275
|
features.push(createFeature(id, "MultiPoint", out, properties));
|
|
218
276
|
}
|
|
219
|
-
function convertLineStringFeature(features, id, geom, tolerance,
|
|
277
|
+
function convertLineStringFeature(features, id, geom, tolerance, worldCoordinateHelper, properties) {
|
|
220
278
|
const out = { points: [] };
|
|
221
|
-
convertLine(geom.coordinates, out, tolerance, false,
|
|
279
|
+
convertLine(geom.coordinates, out, tolerance, false, worldCoordinateHelper);
|
|
222
280
|
features.push(createFeature(id, "LineString", out, properties));
|
|
223
281
|
}
|
|
224
|
-
function convertMultiLineStringFeature(features, id, geom, tolerance,
|
|
282
|
+
function convertMultiLineStringFeature(features, id, geom, tolerance, worldCoordinateHelper, options, properties) {
|
|
225
283
|
if (options.lineMetrics) for (const line of geom.coordinates) {
|
|
226
284
|
const out = { points: [] };
|
|
227
|
-
convertLine(line, out, tolerance, false,
|
|
285
|
+
convertLine(line, out, tolerance, false, worldCoordinateHelper);
|
|
228
286
|
features.push(createFeature(id, "LineString", out, properties));
|
|
229
287
|
}
|
|
230
288
|
else {
|
|
231
289
|
const out = [];
|
|
232
|
-
convertLines(geom.coordinates, out, tolerance, false,
|
|
290
|
+
convertLines(geom.coordinates, out, tolerance, false, worldCoordinateHelper);
|
|
233
291
|
features.push(createFeature(id, "MultiLineString", out, properties));
|
|
234
292
|
}
|
|
235
293
|
}
|
|
236
|
-
function convertPolygonFeature(features, id, geom, tolerance,
|
|
294
|
+
function convertPolygonFeature(features, id, geom, tolerance, worldCoordinateHelper, properties) {
|
|
237
295
|
const out = [];
|
|
238
|
-
convertLines(geom.coordinates, out, tolerance, true,
|
|
296
|
+
convertLines(geom.coordinates, out, tolerance, true, worldCoordinateHelper);
|
|
239
297
|
features.push(createFeature(id, "Polygon", out, properties));
|
|
240
298
|
}
|
|
241
|
-
function convertMultiPolygonFeature(features, id, geom, tolerance,
|
|
299
|
+
function convertMultiPolygonFeature(features, id, geom, tolerance, worldCoordinateHelper, properties) {
|
|
242
300
|
const out = [];
|
|
243
301
|
for (const polygon of geom.coordinates) {
|
|
244
302
|
const polygonOut = [];
|
|
245
|
-
convertLines(polygon, polygonOut, tolerance, true,
|
|
303
|
+
convertLines(polygon, polygonOut, tolerance, true, worldCoordinateHelper);
|
|
246
304
|
if (!polygonOut.length) continue;
|
|
247
305
|
out.push(polygonOut);
|
|
248
306
|
}
|
|
249
307
|
if (!out.length) return;
|
|
250
308
|
features.push(createFeature(id, "MultiPolygon", out, properties));
|
|
251
309
|
}
|
|
252
|
-
function convertLine(ring, out, tolerance, isPolygon,
|
|
310
|
+
function convertLine(ring, out, tolerance, isPolygon, worldCoordinateHelper) {
|
|
253
311
|
let x0, y0;
|
|
254
312
|
let size = 0;
|
|
255
313
|
for (let j = 0; j < ring.length; j++) {
|
|
256
|
-
const x = projectX(ring[j][0]
|
|
257
|
-
const y = projectY(ring[j][1]
|
|
314
|
+
const x = worldCoordinateHelper.projectX(ring[j][0]);
|
|
315
|
+
const y = worldCoordinateHelper.projectY(ring[j][1]);
|
|
258
316
|
out.points.push(x, y, 0);
|
|
259
317
|
if (j > 0) {
|
|
260
318
|
if (isPolygon) size += (x0 * y - x * y0) / 2;
|
|
@@ -272,48 +330,32 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
272
330
|
out.start = 0;
|
|
273
331
|
out.end = out.size;
|
|
274
332
|
}
|
|
275
|
-
function convertLines(rings, out, tolerance, isPolygon,
|
|
333
|
+
function convertLines(rings, out, tolerance, isPolygon, worldCoordinateHelper) {
|
|
276
334
|
for (let i = 0; i < rings.length; i++) {
|
|
277
335
|
const geom = { points: [] };
|
|
278
|
-
convertLine(rings[i], geom, tolerance, isPolygon,
|
|
336
|
+
convertLine(rings[i], geom, tolerance, isPolygon, worldCoordinateHelper);
|
|
279
337
|
out.push(geom);
|
|
280
338
|
}
|
|
281
339
|
}
|
|
282
|
-
/**
|
|
283
|
-
* Convert longitude to spherical mercator in [0..1] range, or keep a world coordinate as it is
|
|
284
|
-
*/
|
|
285
|
-
function projectX(x, worldCoordinates = false) {
|
|
286
|
-
if (worldCoordinates) return x;
|
|
287
|
-
return x / 360 + .5;
|
|
288
|
-
}
|
|
289
|
-
/**
|
|
290
|
-
* Convert latitude to spherical mercator in [0..1] range, or keep a world coordinate as it is
|
|
291
|
-
*/
|
|
292
|
-
function projectY(y, worldCoordinates = false) {
|
|
293
|
-
if (worldCoordinates) return y;
|
|
294
|
-
const sin = Math.sin(y * Math.PI / 180);
|
|
295
|
-
const y2 = .5 - .25 * Math.log((1 + sin) / (1 - sin)) / Math.PI;
|
|
296
|
-
return y2 < 0 ? 0 : y2 > 1 ? 1 : y2;
|
|
297
|
-
}
|
|
298
340
|
|
|
299
341
|
//#endregion
|
|
300
342
|
//#region src/deconvert.ts
|
|
301
343
|
/**
|
|
302
344
|
* Converts internal source features back to GeoJSON format.
|
|
303
345
|
*/
|
|
304
|
-
function convertToGeoJSON(source,
|
|
346
|
+
function convertToGeoJSON(source, worldCoordinateHelper = mercatorWorldCoordinateHelper) {
|
|
305
347
|
return {
|
|
306
348
|
type: "FeatureCollection",
|
|
307
|
-
features: source.map((feature) => featureToGeoJSON(feature,
|
|
349
|
+
features: source.map((feature) => featureToGeoJSON(feature, worldCoordinateHelper))
|
|
308
350
|
};
|
|
309
351
|
}
|
|
310
352
|
/**
|
|
311
353
|
* Converts a single internal feature to GeoJSON format.
|
|
312
354
|
*/
|
|
313
|
-
function featureToGeoJSON(feature,
|
|
355
|
+
function featureToGeoJSON(feature, worldCoordinateHelper = mercatorWorldCoordinateHelper) {
|
|
314
356
|
const geojsonFeature = {
|
|
315
357
|
type: "Feature",
|
|
316
|
-
geometry: geometryToGeoJSON(feature,
|
|
358
|
+
geometry: geometryToGeoJSON(feature, worldCoordinateHelper),
|
|
317
359
|
properties: feature.tags
|
|
318
360
|
};
|
|
319
361
|
if (feature.id != null) geojsonFeature.id = feature.id;
|
|
@@ -322,54 +364,39 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
322
364
|
/**
|
|
323
365
|
* Converts a single internal feature geometry to GeoJSON format.
|
|
324
366
|
*/
|
|
325
|
-
function geometryToGeoJSON(feature,
|
|
367
|
+
function geometryToGeoJSON(feature, worldCoordinateHelper) {
|
|
326
368
|
const { type, geometry } = feature;
|
|
327
369
|
switch (type) {
|
|
328
370
|
case "Point": return {
|
|
329
371
|
type,
|
|
330
|
-
coordinates: unprojectPoint(geometry[0], geometry[1],
|
|
372
|
+
coordinates: unprojectPoint(geometry[0], geometry[1], worldCoordinateHelper)
|
|
331
373
|
};
|
|
332
374
|
case "MultiPoint": return {
|
|
333
375
|
type,
|
|
334
|
-
coordinates: unprojectPoints(geometry,
|
|
376
|
+
coordinates: unprojectPoints(geometry, worldCoordinateHelper)
|
|
335
377
|
};
|
|
336
378
|
case "LineString": return {
|
|
337
379
|
type,
|
|
338
|
-
coordinates: unprojectPoints(geometry.points,
|
|
380
|
+
coordinates: unprojectPoints(geometry.points, worldCoordinateHelper)
|
|
339
381
|
};
|
|
340
382
|
case "MultiLineString":
|
|
341
383
|
case "Polygon": return {
|
|
342
384
|
type,
|
|
343
|
-
coordinates: geometry.map((ring) => unprojectPoints(ring.points,
|
|
385
|
+
coordinates: geometry.map((ring) => unprojectPoints(ring.points, worldCoordinateHelper))
|
|
344
386
|
};
|
|
345
387
|
case "MultiPolygon": return {
|
|
346
388
|
type,
|
|
347
|
-
coordinates: geometry.map((polygon) => polygon.map((ring) => unprojectPoints(ring.points,
|
|
389
|
+
coordinates: geometry.map((polygon) => polygon.map((ring) => unprojectPoints(ring.points, worldCoordinateHelper)))
|
|
348
390
|
};
|
|
349
391
|
}
|
|
350
392
|
}
|
|
351
|
-
function unprojectPoints(coords,
|
|
393
|
+
function unprojectPoints(coords, worldCoordinateHelper = mercatorWorldCoordinateHelper) {
|
|
352
394
|
const result = [];
|
|
353
|
-
for (let i = 0; i < coords.length; i += 3) result.push(unprojectPoint(coords[i], coords[i + 1],
|
|
395
|
+
for (let i = 0; i < coords.length; i += 3) result.push(unprojectPoint(coords[i], coords[i + 1], worldCoordinateHelper));
|
|
354
396
|
return result;
|
|
355
397
|
}
|
|
356
|
-
function unprojectPoint(x, y,
|
|
357
|
-
return [unprojectX(x
|
|
358
|
-
}
|
|
359
|
-
/**
|
|
360
|
-
* Convert spherical mercator in [0..1] range to longitude, or keep a world coordinate as it is
|
|
361
|
-
*/
|
|
362
|
-
function unprojectX(x, worldCoordinates = false) {
|
|
363
|
-
if (worldCoordinates) return x;
|
|
364
|
-
return (x - .5) * 360;
|
|
365
|
-
}
|
|
366
|
-
/**
|
|
367
|
-
* Convert spherical mercator in [0..1] range to latitude, or keep a world coordinate as it is
|
|
368
|
-
*/
|
|
369
|
-
function unprojectY(y, worldCoordinates = false) {
|
|
370
|
-
if (worldCoordinates) return y;
|
|
371
|
-
const y2 = (180 - y * 360) * Math.PI / 180;
|
|
372
|
-
return 360 * Math.atan(Math.exp(y2)) / Math.PI - 90;
|
|
398
|
+
function unprojectPoint(x, y, worldCoordinateHelper) {
|
|
399
|
+
return [worldCoordinateHelper.unprojectX(x), worldCoordinateHelper.unprojectY(y)];
|
|
373
400
|
}
|
|
374
401
|
|
|
375
402
|
//#endregion
|
|
@@ -561,7 +588,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
561
588
|
//#endregion
|
|
562
589
|
//#region src/wrap.ts
|
|
563
590
|
function wrap(features, options) {
|
|
564
|
-
if (options.
|
|
591
|
+
if (!options.wrap) return features;
|
|
565
592
|
const buffer = options.buffer / options.extent;
|
|
566
593
|
let merged = features;
|
|
567
594
|
const left = clip(features, 1, -1 - buffer, buffer, 0, -1, 2, options);
|
|
@@ -632,16 +659,19 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
632
659
|
* @param source
|
|
633
660
|
* @param dataDiff
|
|
634
661
|
* @param options
|
|
662
|
+
* @param unlocated - the features without coordinates, by id, so that an update can give them some
|
|
635
663
|
* @returns
|
|
636
664
|
*/
|
|
637
|
-
function applySourceDiff(source, dataDiff, options) {
|
|
665
|
+
function applySourceDiff(source, dataDiff, options, unlocated) {
|
|
638
666
|
const diff = diffToHashed(dataDiff, options);
|
|
639
667
|
let affected = [];
|
|
640
668
|
if (diff.removeAll) {
|
|
641
669
|
affected = source;
|
|
642
670
|
source = [];
|
|
671
|
+
unlocated?.clear();
|
|
643
672
|
}
|
|
644
673
|
if (diff.remove.size || diff.add.size) {
|
|
674
|
+
for (const id of diff.remove) unlocated?.delete(id);
|
|
645
675
|
const removeFeatures = [];
|
|
646
676
|
for (const feature of source) if (diff.remove.has(feature.id) || diff.add.has(feature.id)) removeFeatures.push(feature);
|
|
647
677
|
if (removeFeatures.length) {
|
|
@@ -653,7 +683,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
653
683
|
let addFeatures = convertToInternal({
|
|
654
684
|
type: "FeatureCollection",
|
|
655
685
|
features: Array.from(diff.add.values())
|
|
656
|
-
}, options);
|
|
686
|
+
}, options, unlocated);
|
|
657
687
|
addFeatures = wrap(addFeatures, options);
|
|
658
688
|
affected = affected.concat(addFeatures);
|
|
659
689
|
source = source.concat(addFeatures);
|
|
@@ -666,8 +696,14 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
666
696
|
else keepFeatures.push(feature);
|
|
667
697
|
for (const [id, update] of diff.update) {
|
|
668
698
|
const oldFeatures = oldFeaturesMap.get(id);
|
|
669
|
-
if (!oldFeatures || oldFeatures.length === 0)
|
|
670
|
-
|
|
699
|
+
if (!oldFeatures || oldFeatures.length === 0) {
|
|
700
|
+
if (!unlocated?.has(id)) continue;
|
|
701
|
+
const locatedFeatures = getUpdatedUnlocatedFeatures(id, update, options, unlocated);
|
|
702
|
+
affected = affected.concat(locatedFeatures);
|
|
703
|
+
keepFeatures = keepFeatures.concat(locatedFeatures);
|
|
704
|
+
continue;
|
|
705
|
+
}
|
|
706
|
+
const updatedFeatures = getUpdatedFeatures(oldFeatures, update, options, unlocated);
|
|
671
707
|
affected = affected.concat(oldFeatures, updatedFeatures);
|
|
672
708
|
keepFeatures = keepFeatures.concat(updatedFeatures);
|
|
673
709
|
}
|
|
@@ -683,29 +719,16 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
683
719
|
* @param vtFeatures - the original features
|
|
684
720
|
* @param update - the update object to apply
|
|
685
721
|
* @param options - the options to use for the wrap method
|
|
722
|
+
* @param unlocated - the features without coordinates, by id, which a new geometry without coordinates adds the feature to
|
|
686
723
|
* @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.
|
|
687
724
|
*/
|
|
688
|
-
function getUpdatedFeatures(vtFeatures, update, options) {
|
|
725
|
+
function getUpdatedFeatures(vtFeatures, update, options, unlocated) {
|
|
689
726
|
const changeGeometry = !!update.newGeometry;
|
|
690
|
-
const changeProps = update
|
|
727
|
+
const changeProps = hasPropertyChanges(update);
|
|
691
728
|
if (changeGeometry) {
|
|
692
729
|
const vtFeature = vtFeatures[0];
|
|
693
|
-
const
|
|
694
|
-
|
|
695
|
-
id: vtFeature.id,
|
|
696
|
-
geometry: update.newGeometry,
|
|
697
|
-
properties: changeProps ? applyPropertyUpdates(vtFeature.tags, update) : vtFeature.tags
|
|
698
|
-
};
|
|
699
|
-
let features = convertToInternal({
|
|
700
|
-
type: "FeatureCollection",
|
|
701
|
-
features: [geojsonFeature]
|
|
702
|
-
}, {
|
|
703
|
-
...options,
|
|
704
|
-
promoteId: void 0,
|
|
705
|
-
generateId: false
|
|
706
|
-
});
|
|
707
|
-
features = wrap(features, options);
|
|
708
|
-
return features;
|
|
730
|
+
const properties = changeProps ? applyPropertyUpdates(vtFeature.tags, update) : vtFeature.tags;
|
|
731
|
+
return convertNewGeometry(vtFeature.id, update.newGeometry, properties, options, unlocated);
|
|
709
732
|
}
|
|
710
733
|
if (changeProps) {
|
|
711
734
|
const updated = [];
|
|
@@ -719,6 +742,44 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
719
742
|
return vtFeatures;
|
|
720
743
|
}
|
|
721
744
|
/**
|
|
745
|
+
* Gets the features an update gives a feature without coordinates: none, unless its new geometry has some.
|
|
746
|
+
* Its property changes apply either way.
|
|
747
|
+
*/
|
|
748
|
+
function getUpdatedUnlocatedFeatures(id, update, options, unlocated) {
|
|
749
|
+
const feature = unlocated.get(id);
|
|
750
|
+
const properties = hasPropertyChanges(update) ? applyPropertyUpdates(feature.properties, update) : feature.properties;
|
|
751
|
+
if (!update.newGeometry) {
|
|
752
|
+
unlocated.set(id, {
|
|
753
|
+
...feature,
|
|
754
|
+
properties
|
|
755
|
+
});
|
|
756
|
+
return [];
|
|
757
|
+
}
|
|
758
|
+
return convertNewGeometry(id, update.newGeometry, properties, options, unlocated);
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* Converts the new geometry of a feature to internal format, keeping the id the feature already has
|
|
762
|
+
*/
|
|
763
|
+
function convertNewGeometry(id, geometry, properties, options, unlocated) {
|
|
764
|
+
const features = convertToInternal({
|
|
765
|
+
type: "FeatureCollection",
|
|
766
|
+
features: [{
|
|
767
|
+
type: "Feature",
|
|
768
|
+
id,
|
|
769
|
+
geometry,
|
|
770
|
+
properties
|
|
771
|
+
}]
|
|
772
|
+
}, {
|
|
773
|
+
...options,
|
|
774
|
+
promoteId: void 0,
|
|
775
|
+
generateId: false
|
|
776
|
+
}, unlocated);
|
|
777
|
+
return wrap(features, options);
|
|
778
|
+
}
|
|
779
|
+
function hasPropertyChanges(update) {
|
|
780
|
+
return update.removeAllProperties || update.removeProperties?.length > 0 || update.addOrUpdateProperties?.length > 0;
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
722
783
|
* helper to apply property updates from a diff update object to a properties object
|
|
723
784
|
*/
|
|
724
785
|
function applyPropertyUpdates(tags, update) {
|
|
@@ -1043,7 +1104,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
1043
1104
|
log: false,
|
|
1044
1105
|
generateId: false,
|
|
1045
1106
|
reduce: null,
|
|
1046
|
-
map: (props) => props
|
|
1107
|
+
map: (props) => props,
|
|
1108
|
+
coordinates: "lngLat",
|
|
1109
|
+
wrap: true
|
|
1047
1110
|
};
|
|
1048
1111
|
/**
|
|
1049
1112
|
* The highest zoom level to cluster on. A cluster id keeps its zoom level in five bits.
|
|
@@ -1083,9 +1146,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
1083
1146
|
* This class allow clustering of geojson points.
|
|
1084
1147
|
*/
|
|
1085
1148
|
var ClusterTileIndex = class {
|
|
1086
|
-
constructor(options
|
|
1149
|
+
constructor(options) {
|
|
1087
1150
|
this.options = createOptions(options);
|
|
1088
|
-
this.
|
|
1151
|
+
this.worldCoordinateHelper = getWorldCoordinateHelper(this.options.coordinates);
|
|
1089
1152
|
this.trees = new Array(this.options.maxZoom + 1);
|
|
1090
1153
|
this.stride = this.options.reduce ? 5 : 4;
|
|
1091
1154
|
this.clusterProps = [];
|
|
@@ -1102,8 +1165,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
1102
1165
|
if (!point.geometry) continue;
|
|
1103
1166
|
const positions = point.geometry.type === "MultiPoint" ? point.geometry.coordinates : [point.geometry.coordinates];
|
|
1104
1167
|
for (const [lng, lat] of positions) {
|
|
1105
|
-
const [x, y] = [projectX(lng, this.
|
|
1106
|
-
if (this.
|
|
1168
|
+
const [x, y] = [this.worldCoordinateHelper.projectX(lng), this.worldCoordinateHelper.projectY(lat)];
|
|
1169
|
+
if (!this.options.wrap && !isInWorld([x, y])) continue;
|
|
1107
1170
|
const feature = {
|
|
1108
1171
|
id: point.id,
|
|
1109
1172
|
type: "Point",
|
|
@@ -1125,14 +1188,14 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
1125
1188
|
const points = [];
|
|
1126
1189
|
for (const feature of features) {
|
|
1127
1190
|
if (feature.type === "Point") {
|
|
1128
|
-
if (this.
|
|
1191
|
+
if (!this.options.wrap && !isInWorld(feature.geometry)) continue;
|
|
1129
1192
|
points.push(feature);
|
|
1130
1193
|
continue;
|
|
1131
1194
|
}
|
|
1132
1195
|
if (feature.type !== "MultiPoint") continue;
|
|
1133
1196
|
for (let i = 0; i < feature.geometry.length; i += 3) {
|
|
1134
1197
|
const geometry = [feature.geometry[i], feature.geometry[i + 1]];
|
|
1135
|
-
if (this.
|
|
1198
|
+
if (!this.options.wrap && !isInWorld(geometry)) continue;
|
|
1136
1199
|
points.push({
|
|
1137
1200
|
id: feature.id,
|
|
1138
1201
|
type: "Point",
|
|
@@ -1149,7 +1212,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
1149
1212
|
* @param features
|
|
1150
1213
|
*/
|
|
1151
1214
|
updateIndex(features, _affected, options) {
|
|
1152
|
-
this.options = createOptions(
|
|
1215
|
+
this.options = createOptions({
|
|
1216
|
+
...options.clusterOptions,
|
|
1217
|
+
coordinates: this.options.coordinates,
|
|
1218
|
+
wrap: this.options.wrap
|
|
1219
|
+
});
|
|
1153
1220
|
this.initialize(features);
|
|
1154
1221
|
}
|
|
1155
1222
|
/**
|
|
@@ -1197,11 +1264,61 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
1197
1264
|
}
|
|
1198
1265
|
/**
|
|
1199
1266
|
* Returns clusters and/or points within a bounding box at a given zoom level.
|
|
1200
|
-
* @param bbox - Bounding box in `[westLng, southLat, eastLng, northLat]` order, or `[minX, minY, maxX, maxY]` in
|
|
1267
|
+
* @param bbox - Bounding box in `[westLng, southLat, eastLng, northLat]` order, or `[minX, minY, maxX, maxY]` in the unit square with `coordinates: 'unitSquare'`.
|
|
1268
|
+
* In a world that wraps, the box can reach across the antimeridian. In one that doesn't, only its part inside the world counts.
|
|
1201
1269
|
* @param zoom - Zoom level to query.
|
|
1202
1270
|
*/
|
|
1203
1271
|
getClusters(bbox, zoom) {
|
|
1204
|
-
return (this.
|
|
1272
|
+
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));
|
|
1273
|
+
}
|
|
1274
|
+
/**
|
|
1275
|
+
* The clusters and points in the part of a box inside a world that ends at its edges.
|
|
1276
|
+
*/
|
|
1277
|
+
getClustersInWorld(bbox, zoom) {
|
|
1278
|
+
const lngLat = this.options.coordinates !== "unitSquare";
|
|
1279
|
+
const y1 = this.worldCoordinateHelper.projectY(lngLat ? Math.max(-90, Math.min(90, bbox[1])) : bbox[1]);
|
|
1280
|
+
const y2 = this.worldCoordinateHelper.projectY(lngLat ? Math.max(-90, Math.min(90, bbox[3])) : bbox[3]);
|
|
1281
|
+
const minX = Math.max(0, this.worldCoordinateHelper.projectX(bbox[0]));
|
|
1282
|
+
const maxX = Math.min(1, this.worldCoordinateHelper.projectX(bbox[2]));
|
|
1283
|
+
if (minX > maxX) return [];
|
|
1284
|
+
return this.getClustersInRange([
|
|
1285
|
+
minX,
|
|
1286
|
+
Math.min(y1, y2),
|
|
1287
|
+
maxX,
|
|
1288
|
+
Math.max(y1, y2)
|
|
1289
|
+
], zoom);
|
|
1290
|
+
}
|
|
1291
|
+
/**
|
|
1292
|
+
* The clusters and points in a box of a unit square that wraps, where the box can reach across its left or right edge.
|
|
1293
|
+
*/
|
|
1294
|
+
getClustersAcrossEdge([minX, minY, maxX, maxY], zoom) {
|
|
1295
|
+
if (maxX < minX) maxX += 1;
|
|
1296
|
+
if (maxX - minX >= 1) return this.getClustersInRange([
|
|
1297
|
+
0,
|
|
1298
|
+
minY,
|
|
1299
|
+
1,
|
|
1300
|
+
maxY
|
|
1301
|
+
], zoom);
|
|
1302
|
+
const shift = Math.floor(minX);
|
|
1303
|
+
const west = minX - shift;
|
|
1304
|
+
const east = maxX - shift;
|
|
1305
|
+
if (east <= 1) return this.getClustersInRange([
|
|
1306
|
+
west,
|
|
1307
|
+
minY,
|
|
1308
|
+
east,
|
|
1309
|
+
maxY
|
|
1310
|
+
], zoom);
|
|
1311
|
+
return this.getClustersInRange([
|
|
1312
|
+
west,
|
|
1313
|
+
minY,
|
|
1314
|
+
1,
|
|
1315
|
+
maxY
|
|
1316
|
+
], zoom).concat(this.getClustersInRange([
|
|
1317
|
+
0,
|
|
1318
|
+
minY,
|
|
1319
|
+
east - 1,
|
|
1320
|
+
maxY
|
|
1321
|
+
], zoom));
|
|
1205
1322
|
}
|
|
1206
1323
|
getClustersInternal(bbox, zoom) {
|
|
1207
1324
|
let minLng = ((bbox[0] + 180) % 360 + 360) % 360 - 180;
|
|
@@ -1227,10 +1344,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
1227
1344
|
return easternHem.concat(westernHem);
|
|
1228
1345
|
}
|
|
1229
1346
|
return this.getClustersInRange([
|
|
1230
|
-
projectX(minLng),
|
|
1231
|
-
projectY(maxLat),
|
|
1232
|
-
projectX(maxLng),
|
|
1233
|
-
projectY(minLat)
|
|
1347
|
+
this.worldCoordinateHelper.projectX(minLng),
|
|
1348
|
+
this.worldCoordinateHelper.projectY(maxLat),
|
|
1349
|
+
this.worldCoordinateHelper.projectX(maxLng),
|
|
1350
|
+
this.worldCoordinateHelper.projectY(minLat)
|
|
1234
1351
|
], zoom);
|
|
1235
1352
|
}
|
|
1236
1353
|
/**
|
|
@@ -1268,7 +1385,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
1268
1385
|
const children = [];
|
|
1269
1386
|
for (const id of ids) {
|
|
1270
1387
|
const k = id * this.stride;
|
|
1271
|
-
if (data[k + OFFSET_PARENT] === clusterId) children.push(data[k + OFFSET_NUM] > 1 ? getClusterGeoJSON(coords, id, data, k, this.clusterProps, this.
|
|
1388
|
+
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));
|
|
1272
1389
|
}
|
|
1273
1390
|
if (children.length === 0) throw clusterError;
|
|
1274
1391
|
return children;
|
|
@@ -1296,7 +1413,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
1296
1413
|
const tree = this.trees[this.limitZoom(z)];
|
|
1297
1414
|
if (!tree) return null;
|
|
1298
1415
|
const z2 = Math.pow(2, z);
|
|
1299
|
-
if (this.
|
|
1416
|
+
if (!this.options.wrap && (x < 0 || x >= z2 || y < 0 || y >= z2)) return null;
|
|
1300
1417
|
const { extent, radius } = this.options;
|
|
1301
1418
|
const p = radius / extent;
|
|
1302
1419
|
const top = encode((y - p) / z2);
|
|
@@ -1310,8 +1427,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
1310
1427
|
z
|
|
1311
1428
|
};
|
|
1312
1429
|
this.addTileFeatures(tree.range(encode((x - p) / z2), top, encode((x + 1 + p) / z2), bottom), tree, x, y, z2, tile);
|
|
1313
|
-
if (
|
|
1314
|
-
if (
|
|
1430
|
+
if (this.options.wrap && x === 0) this.addTileFeatures(tree.range(encode(1 - p / z2), top, encode(1), bottom), tree, z2, y, z2, tile);
|
|
1431
|
+
if (this.options.wrap && x === z2 - 1) this.addTileFeatures(tree.range(encode(0), top, encode(p / z2), bottom), tree, -1, y, z2, tile);
|
|
1315
1432
|
return tile;
|
|
1316
1433
|
}
|
|
1317
1434
|
/**
|
|
@@ -1494,14 +1611,14 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
1494
1611
|
geometry: [decode(coords[index * 2]), decode(coords[index * 2 + 1])]
|
|
1495
1612
|
};
|
|
1496
1613
|
}
|
|
1497
|
-
function getClusterGeoJSON(coords, index, data, i, clusterProps,
|
|
1614
|
+
function getClusterGeoJSON(coords, index, data, i, clusterProps, worldCoordinateHelper) {
|
|
1498
1615
|
return {
|
|
1499
1616
|
type: "Feature",
|
|
1500
1617
|
id: data[i + OFFSET_ID],
|
|
1501
1618
|
properties: getClusterProperties(data, i, clusterProps),
|
|
1502
1619
|
geometry: {
|
|
1503
1620
|
type: "Point",
|
|
1504
|
-
coordinates: [unprojectX(decode(coords[index * 2])
|
|
1621
|
+
coordinates: [worldCoordinateHelper.unprojectX(decode(coords[index * 2])), worldCoordinateHelper.unprojectY(decode(coords[index * 2 + 1]))]
|
|
1505
1622
|
}
|
|
1506
1623
|
};
|
|
1507
1624
|
}
|
|
@@ -1784,7 +1901,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
1784
1901
|
getTile(z, x, y) {
|
|
1785
1902
|
const { extent, debug } = this.options;
|
|
1786
1903
|
const z2 = 1 << z;
|
|
1787
|
-
if (this.options.
|
|
1904
|
+
if (!this.options.wrap && (x < 0 || x >= z2)) return null;
|
|
1788
1905
|
x = x + z2 & z2 - 1;
|
|
1789
1906
|
const id = toID(z, x, y);
|
|
1790
1907
|
if (this.tiles[id]) return transformTile(this.tiles[id], extent);
|
|
@@ -1810,14 +1927,16 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
1810
1927
|
return transformTile(this.tiles[id], extent);
|
|
1811
1928
|
}
|
|
1812
1929
|
/**
|
|
1813
|
-
* The features the top tile starts from
|
|
1814
|
-
* and only what lies inside the world square and its buffer
|
|
1815
|
-
*
|
|
1930
|
+
* The features the top tile starts from. A world that wraps keeps them all left and right, where wrapping already
|
|
1931
|
+
* put them inside, and one that doesn't only what lies inside the world square and its buffer. Positions in the
|
|
1932
|
+
* unit square are also cut above and below in a world that wraps, where lng/lat is clamped already. The index keeps
|
|
1933
|
+
* the rest, so an update can still move a feature in from outside.
|
|
1816
1934
|
*/
|
|
1817
1935
|
clipToWorld(features) {
|
|
1818
|
-
|
|
1936
|
+
const { wrap, coordinates } = this.options;
|
|
1937
|
+
if (wrap && coordinates !== "unitSquare") return features;
|
|
1819
1938
|
const buffer = this.options.buffer / this.options.extent;
|
|
1820
|
-
const inX = clip(features, 1, -buffer, 1 + buffer, 0, -Infinity, Infinity, this.options) || [];
|
|
1939
|
+
const inX = wrap ? features : clip(features, 1, -buffer, 1 + buffer, 0, -Infinity, Infinity, this.options) || [];
|
|
1821
1940
|
return clip(inX, 1, -buffer, 1 + buffer, 1, -Infinity, Infinity, this.options) || [];
|
|
1822
1941
|
}
|
|
1823
1942
|
/**
|
|
@@ -1975,7 +2094,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
1975
2094
|
cluster: false,
|
|
1976
2095
|
clusterOptions: defaultClusterOptions,
|
|
1977
2096
|
debug: 0,
|
|
1978
|
-
|
|
2097
|
+
coordinates: "lngLat",
|
|
2098
|
+
wrap: true
|
|
1979
2099
|
};
|
|
1980
2100
|
/**
|
|
1981
2101
|
* Main class for creating and managing a vector tile index from GeoJSON data.
|
|
@@ -1983,11 +2103,13 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
1983
2103
|
var GeoJSONVT = class {
|
|
1984
2104
|
constructor(data, options) {
|
|
1985
2105
|
options = this.options = Object.assign({}, defaultOptions, options);
|
|
2106
|
+
this.worldCoordinateHelper = getWorldCoordinateHelper(options.coordinates);
|
|
1986
2107
|
const debug = options.debug;
|
|
1987
2108
|
if (debug) console.time("preprocess data");
|
|
1988
2109
|
if (options.maxZoom < 0 || options.maxZoom > 24) throw new Error("maxZoom should be in the 0-24 range");
|
|
1989
2110
|
if (options.promoteId && options.generateId) throw new Error("promoteId and generateId cannot be used together.");
|
|
1990
|
-
|
|
2111
|
+
if (options.updateable) this.unlocated = /* @__PURE__ */ new Map();
|
|
2112
|
+
let features = convertToInternal(data, options, this.unlocated);
|
|
1991
2113
|
if (debug) {
|
|
1992
2114
|
console.timeEnd("preprocess data");
|
|
1993
2115
|
console.log("index: maxZoom: %d, maxPoints: %d", options.indexMaxZoom, options.indexMaxPoints);
|
|
@@ -1998,7 +2120,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
1998
2120
|
this.initializeIndex(features, options);
|
|
1999
2121
|
}
|
|
2000
2122
|
initializeIndex(features, options) {
|
|
2001
|
-
this.tileIndex = options.cluster ? new ClusterTileIndex(
|
|
2123
|
+
this.tileIndex = options.cluster ? new ClusterTileIndex({
|
|
2124
|
+
...options.clusterOptions,
|
|
2125
|
+
coordinates: options.coordinates,
|
|
2126
|
+
wrap: options.wrap
|
|
2127
|
+
}) : new TileIndex(options);
|
|
2002
2128
|
if (!features.length) return;
|
|
2003
2129
|
this.tileIndex.initialize(features);
|
|
2004
2130
|
}
|
|
@@ -2023,24 +2149,27 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
2023
2149
|
updateData(diff, filter) {
|
|
2024
2150
|
const options = this.options;
|
|
2025
2151
|
if (!options.updateable) throw new Error("to update tile geojson `updateable` option must be set to true");
|
|
2026
|
-
let { affected, source } = applySourceDiff(this.source, diff, options);
|
|
2152
|
+
let { affected, source } = applySourceDiff(this.source, diff, options, this.unlocated);
|
|
2027
2153
|
if (filter) ({affected, source} = this.filterUpdate(source, affected, filter));
|
|
2028
2154
|
if (!affected.length) return;
|
|
2029
2155
|
this.source = source;
|
|
2030
2156
|
this.tileIndex.updateIndex(source, affected, options);
|
|
2031
2157
|
}
|
|
2032
2158
|
/**
|
|
2033
|
-
* Filter an update using a predicate function
|
|
2159
|
+
* Filter an update using a predicate function, the features an update emptied included, so that one the filter
|
|
2160
|
+
* rejects can't come back with a later update. A feature without a geometry at all isn't passed to the predicate.
|
|
2161
|
+
* Returns the affected and updated source features.
|
|
2034
2162
|
*/
|
|
2035
2163
|
filterUpdate(source, affected, predicate) {
|
|
2036
2164
|
const removeIds = /* @__PURE__ */ new Set();
|
|
2037
2165
|
for (const feature of source) {
|
|
2038
2166
|
if (feature.id == void 0) continue;
|
|
2039
|
-
if (predicate(featureToGeoJSON(feature, this.
|
|
2167
|
+
if (predicate(featureToGeoJSON(feature, this.worldCoordinateHelper))) continue;
|
|
2040
2168
|
affected.push(feature);
|
|
2041
2169
|
removeIds.add(feature.id);
|
|
2042
2170
|
}
|
|
2043
2171
|
source = source.filter((feature) => !removeIds.has(feature.id));
|
|
2172
|
+
for (const [id, feature] of this.unlocated ?? []) if (feature.geometry && !predicate(feature)) this.unlocated.delete(id);
|
|
2044
2173
|
return {
|
|
2045
2174
|
affected,
|
|
2046
2175
|
source
|
|
@@ -2051,12 +2180,12 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
2051
2180
|
*/
|
|
2052
2181
|
getData() {
|
|
2053
2182
|
if (!this.options.updateable) throw new Error("to retrieve data the `updateable` option must be set to true");
|
|
2054
|
-
return convertToGeoJSON(this.source, this.
|
|
2183
|
+
return convertToGeoJSON(this.source, this.worldCoordinateHelper);
|
|
2055
2184
|
}
|
|
2056
2185
|
/**
|
|
2057
2186
|
* Update supercluster options and regenerate the index.
|
|
2058
2187
|
* @param cluster - whether to enable clustering
|
|
2059
|
-
* @param clusterOptions - {@link SuperclusterOptions}
|
|
2188
|
+
* @param clusterOptions - {@link SuperclusterOptions} without `coordinates` and `wrap`, which come from the index options
|
|
2060
2189
|
*/
|
|
2061
2190
|
updateClusterOptions(cluster, clusterOptions) {
|
|
2062
2191
|
const wasCluster = this.options.cluster;
|
|
@@ -2133,9 +2262,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
2133
2262
|
function geoJSONToTile(data, z, x, y, options = {}) {
|
|
2134
2263
|
options = {
|
|
2135
2264
|
...defaultOptions,
|
|
2265
|
+
wrap: false,
|
|
2136
2266
|
...options
|
|
2137
2267
|
};
|
|
2138
|
-
const { wrap: shouldWrap
|
|
2268
|
+
const { wrap: shouldWrap, clip: shouldClip = false } = options;
|
|
2139
2269
|
let features = convertToInternal(data, options);
|
|
2140
2270
|
if (shouldWrap) features = wrap(features, options);
|
|
2141
2271
|
if (shouldClip || options.lineMetrics) {
|