@loaders.gl/mvt 4.3.0-alpha.1 → 4.3.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dist.dev.js +568 -175
- package/dist/dist.min.js +1 -1
- package/dist/index.cjs +226 -163
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/parse-mvt.d.ts +1 -1
- package/dist/lib/parse-mvt.js +2 -30
- package/dist/lib/parse-tilejson.d.ts +4 -4
- package/dist/lib/parse-tilejson.d.ts.map +1 -1
- package/dist/lib/utils/geometry-utils.d.ts +38 -1
- package/dist/lib/utils/geometry-utils.d.ts.map +1 -1
- package/dist/lib/utils/geometry-utils.js +65 -6
- package/dist/lib/vector-tile/vector-tile-feature.d.ts +28 -9
- package/dist/lib/vector-tile/vector-tile-feature.d.ts.map +1 -1
- package/dist/lib/vector-tile/vector-tile-feature.js +47 -50
- package/dist/lib/{geojsonvt → vector-tiler}/clip.d.ts +3 -3
- package/dist/lib/vector-tiler/clip.d.ts.map +1 -0
- package/dist/lib/vector-tiler/convert.d.ts +18 -0
- package/dist/lib/vector-tiler/convert.d.ts.map +1 -0
- package/dist/lib/{geojsonvt → vector-tiler}/convert.js +8 -1
- package/dist/lib/vector-tiler/feature.d.ts +3 -0
- package/dist/lib/vector-tiler/feature.d.ts.map +1 -0
- package/dist/lib/vector-tiler/simplify.d.ts.map +1 -0
- package/dist/lib/{geojsonvt → vector-tiler}/tile.d.ts +4 -4
- package/dist/lib/vector-tiler/tile.d.ts.map +1 -0
- package/dist/lib/vector-tiler/transform.d.ts +7 -0
- package/dist/lib/vector-tiler/transform.d.ts.map +1 -0
- package/dist/lib/{geojsonvt → vector-tiler}/wrap.d.ts +2 -2
- package/dist/lib/vector-tiler/wrap.d.ts.map +1 -0
- package/dist/mvt-loader.d.ts +1 -1
- package/dist/mvt-loader.js +1 -1
- package/dist/mvt-source.d.ts +4 -4
- package/dist/mvt-source.d.ts.map +1 -1
- package/dist/mvt-source.js +4 -4
- package/dist/mvt-worker.js +101 -56
- package/dist/table-tile-source.d.ts +118 -0
- package/dist/table-tile-source.d.ts.map +1 -0
- package/dist/{geojson-tile-source.js → table-tile-source.js} +154 -103
- package/dist/tilejson-loader.js +1 -1
- package/package.json +7 -6
- package/src/index.ts +3 -3
- package/src/lib/parse-mvt.ts +4 -33
- package/src/lib/parse-tilejson.ts +5 -5
- package/src/lib/utils/geometry-utils.ts +66 -1
- package/src/lib/vector-tile/vector-tile-feature.ts +65 -56
- package/src/lib/{geojsonvt → vector-tiler}/clip.ts +4 -4
- package/src/lib/{geojsonvt → vector-tiler}/convert.ts +18 -8
- package/src/lib/{geojsonvt → vector-tiler}/feature.ts +3 -3
- package/src/lib/{geojsonvt → vector-tiler}/tile.ts +8 -8
- package/src/lib/{geojsonvt → vector-tiler}/transform.ts +2 -2
- package/src/lib/{geojsonvt → vector-tiler}/wrap.ts +5 -5
- package/src/mvt-source.ts +6 -7
- package/src/table-tile-source.ts +508 -0
- package/dist/geojson-tile-source.d.ts +0 -79
- package/dist/geojson-tile-source.d.ts.map +0 -1
- package/dist/lib/geojsonvt/clip.d.ts.map +0 -1
- package/dist/lib/geojsonvt/convert.d.ts +0 -10
- package/dist/lib/geojsonvt/convert.d.ts.map +0 -1
- package/dist/lib/geojsonvt/feature.d.ts +0 -3
- package/dist/lib/geojsonvt/feature.d.ts.map +0 -1
- package/dist/lib/geojsonvt/simplify.d.ts.map +0 -1
- package/dist/lib/geojsonvt/tile.d.ts.map +0 -1
- package/dist/lib/geojsonvt/transform.d.ts +0 -7
- package/dist/lib/geojsonvt/transform.d.ts.map +0 -1
- package/dist/lib/geojsonvt/wrap.d.ts.map +0 -1
- package/src/geojson-tile-source.ts +0 -422
- /package/dist/lib/{geojsonvt → vector-tiler}/clip.js +0 -0
- /package/dist/lib/{geojsonvt → vector-tiler}/feature.js +0 -0
- /package/dist/lib/{geojsonvt → vector-tiler}/simplify.d.ts +0 -0
- /package/dist/lib/{geojsonvt → vector-tiler}/simplify.js +0 -0
- /package/dist/lib/{geojsonvt → vector-tiler}/tile.js +0 -0
- /package/dist/lib/{geojsonvt → vector-tiler}/transform.js +0 -0
- /package/dist/lib/{geojsonvt → vector-tiler}/wrap.js +0 -0
- /package/src/lib/{geojsonvt → vector-tiler}/LICENSE +0 -0
- /package/src/lib/{geojsonvt → vector-tiler}/simplify.ts +0 -0
|
@@ -2,16 +2,37 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT AND ISC
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
// Based on https://github.com/mapbox/geojson-vt under compatible ISC license
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
import { log } from '@loaders.gl/loader-utils';
|
|
6
|
+
import { deduceTableSchema } from '@loaders.gl/schema';
|
|
7
|
+
import { Stats, Stat } from '@probe.gl/stats';
|
|
8
|
+
import { convert } from "./lib/vector-tiler/convert.js"; // GeoJSON conversion and preprocessing
|
|
9
|
+
import { clip } from "./lib/vector-tiler/clip.js"; // stripe clipping algorithm
|
|
10
|
+
import { wrap } from "./lib/vector-tiler/wrap.js"; // date line processing
|
|
11
|
+
import { transformTile } from "./lib/vector-tiler/transform.js"; // coordinate transformation
|
|
12
|
+
import { createTile } from "./lib/vector-tiler/tile.js"; // final simplified tile generation
|
|
13
|
+
import { projectToLngLat } from "./lib/utils/geometry-utils.js";
|
|
14
|
+
import { convertToLocalCoordinates } from "./lib/utils/geometry-utils.js";
|
|
15
|
+
/**
|
|
16
|
+
* Dynamically vector tiles a table (the table needs a geometry column)
|
|
17
|
+
* - Tiles are generated when requested.
|
|
18
|
+
* - Each tile contains a tables of clipped features.
|
|
19
|
+
*
|
|
20
|
+
* @note - Currently only accepts `GeoJSONTable` tables
|
|
21
|
+
* @note - Currently only outputs `GeoJSONTable`
|
|
22
|
+
* @note - (can be initialized with a promise that resolves to GeoJSONTable).
|
|
23
|
+
*
|
|
24
|
+
* @todo - metadata should scan all rows to determine schema
|
|
25
|
+
* @todo - metadata scan all rows to determine tilestats (field values[] etc).
|
|
26
|
+
* @todo - handle binary input tables
|
|
27
|
+
* @todo - generate binary output tables
|
|
28
|
+
* @todo - how does TileSourceLayer specify coordinates / decided which layer to render with
|
|
29
|
+
*/
|
|
30
|
+
export class TableTileSource {
|
|
31
|
+
static defaultProps = {
|
|
32
|
+
coordinates: 'wgs84', // coordinates in tile coordinates or lng/lat
|
|
12
33
|
maxZoom: 14, // max zoom to preserve detail on
|
|
13
34
|
indexMaxZoom: 5, // max zoom in the tile index
|
|
14
|
-
|
|
35
|
+
maxPointsPerTile: 100000, // max number of points per tile in the tile index
|
|
15
36
|
tolerance: 3, // simplification tolerance (higher means simpler)
|
|
16
37
|
extent: 4096, // tile extent
|
|
17
38
|
buffer: 64, // tile buffer on each side
|
|
@@ -21,58 +42,49 @@ export class GeoJSONTileSource {
|
|
|
21
42
|
generateId: false, // whether to generate feature ids. Cannot be used with promoteId
|
|
22
43
|
debug: 0 // logging level (0, 1 or 2)
|
|
23
44
|
};
|
|
45
|
+
/** Global stats for all TableTileSources */
|
|
46
|
+
static stats = new Stats({
|
|
47
|
+
id: 'table-tile-source-all',
|
|
48
|
+
stats: [new Stat('count', 'tiles'), new Stat('count', 'features')]
|
|
49
|
+
});
|
|
50
|
+
/** Stats for this TableTileSource */
|
|
51
|
+
stats = new Stats({
|
|
52
|
+
id: 'table-tile-source',
|
|
53
|
+
stats: [new Stat('tiles', 'count'), new Stat('features', 'count')]
|
|
54
|
+
});
|
|
55
|
+
/** MIME type of the tiles emitted by this tile source */
|
|
24
56
|
mimeType = 'application/vnd.mapbox-vector-tile';
|
|
25
|
-
|
|
26
|
-
|
|
57
|
+
localCoordinates = true;
|
|
58
|
+
/** The props that this tile source was created with */
|
|
59
|
+
props;
|
|
60
|
+
/* Schema of the data */
|
|
61
|
+
schema = null;
|
|
62
|
+
/** Map of generated tiles, indexed by stringified tile coordinates */
|
|
27
63
|
tiles = {};
|
|
64
|
+
/** Array of tile coordinates */
|
|
28
65
|
tileCoords = [];
|
|
29
|
-
|
|
30
|
-
total = 0;
|
|
31
|
-
/** Sync methods can be called: the input data promise has been resolved and initial top-level tiling is done */
|
|
66
|
+
/** Input data has loaded, initial top-level tiling is done, sync methods can now be called */
|
|
32
67
|
ready;
|
|
33
|
-
|
|
34
|
-
|
|
68
|
+
/** Metadata for the tile source (generated TileJSON/tilestats */
|
|
69
|
+
metadata;
|
|
70
|
+
constructor(table, props) {
|
|
71
|
+
this.props = { ...TableTileSource.defaultProps, ...props };
|
|
35
72
|
this.getTileData = this.getTileData.bind(this);
|
|
36
|
-
this.ready = this.initializeTilesAsync(
|
|
73
|
+
this.ready = this.initializeTilesAsync(table);
|
|
74
|
+
this.metadata = this.getMetadata();
|
|
37
75
|
}
|
|
38
|
-
async initializeTilesAsync(
|
|
39
|
-
const
|
|
40
|
-
this.
|
|
41
|
-
|
|
42
|
-
initializeTilesSync(data) {
|
|
43
|
-
const options = this.options;
|
|
44
|
-
const debug = options.debug;
|
|
45
|
-
if (debug)
|
|
46
|
-
console.time('preprocess data');
|
|
47
|
-
if (this.options.maxZoom < 0 || this.options.maxZoom > 24) {
|
|
48
|
-
throw new Error('maxZoom should be in the 0-24 range');
|
|
49
|
-
}
|
|
50
|
-
if (options.promoteId && this.options.generateId) {
|
|
51
|
-
throw new Error('promoteId and generateId cannot be used together.');
|
|
52
|
-
}
|
|
53
|
-
// projects and adds simplification info
|
|
54
|
-
let features = convert(data, options);
|
|
55
|
-
if (debug) {
|
|
56
|
-
console.timeEnd('preprocess data');
|
|
57
|
-
console.log('index: maxZoom: %d, maxPoints: %d', options.indexMaxZoom, options.indexMaxPoints);
|
|
58
|
-
console.time('generate tiles');
|
|
59
|
-
}
|
|
60
|
-
// wraps features (ie extreme west and extreme east)
|
|
61
|
-
features = wrap(features, this.options);
|
|
62
|
-
// start slicing from the top tile down
|
|
63
|
-
if (features.length) {
|
|
64
|
-
this.splitTile(features, 0, 0, 0);
|
|
65
|
-
}
|
|
66
|
-
if (debug) {
|
|
67
|
-
if (features.length) {
|
|
68
|
-
console.log('features: %d, points: %d', this.tiles[0].numFeatures, this.tiles[0].numPoints);
|
|
69
|
-
}
|
|
70
|
-
console.timeEnd('generate tiles');
|
|
71
|
-
console.log('tiles generated:', this.total, JSON.stringify(this.stats));
|
|
72
|
-
}
|
|
76
|
+
async initializeTilesAsync(tablePromise) {
|
|
77
|
+
const table = await tablePromise;
|
|
78
|
+
this.schema = deduceTableSchema(table);
|
|
79
|
+
this.createRootTiles(table);
|
|
73
80
|
}
|
|
74
81
|
async getMetadata() {
|
|
75
|
-
|
|
82
|
+
await this.ready;
|
|
83
|
+
return { schema: this.schema, minZoom: 0, maxZoom: this.props.maxZoom };
|
|
84
|
+
}
|
|
85
|
+
async getSchema() {
|
|
86
|
+
await this.ready;
|
|
87
|
+
return this.schema;
|
|
76
88
|
}
|
|
77
89
|
/**
|
|
78
90
|
* Get a tile at the specified index
|
|
@@ -82,6 +94,7 @@ export class GeoJSONTileSource {
|
|
|
82
94
|
async getVectorTile(tileIndex) {
|
|
83
95
|
await this.ready;
|
|
84
96
|
const table = this.getTileSync(tileIndex);
|
|
97
|
+
log.info(2, 'getVectorTile', tileIndex, table)();
|
|
85
98
|
return table;
|
|
86
99
|
}
|
|
87
100
|
async getTile(tileIndex) {
|
|
@@ -90,7 +103,8 @@ export class GeoJSONTileSource {
|
|
|
90
103
|
}
|
|
91
104
|
async getTileData(tileParams) {
|
|
92
105
|
const { x, y, z } = tileParams.index;
|
|
93
|
-
|
|
106
|
+
const tile = await this.getVectorTile({ x, y, z });
|
|
107
|
+
return tile?.features || [];
|
|
94
108
|
}
|
|
95
109
|
// Implementation
|
|
96
110
|
/**
|
|
@@ -102,7 +116,41 @@ export class GeoJSONTileSource {
|
|
|
102
116
|
if (!rawTile) {
|
|
103
117
|
return null;
|
|
104
118
|
}
|
|
105
|
-
return convertToGeoJSONTable(rawTile,
|
|
119
|
+
return convertToGeoJSONTable(rawTile, {
|
|
120
|
+
coordinates: this.props.coordinates,
|
|
121
|
+
tileIndex,
|
|
122
|
+
extent: this.props.extent
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Create the initial tiles
|
|
127
|
+
* @note the tiles stores all the features together with additional data
|
|
128
|
+
*/
|
|
129
|
+
createRootTiles(table) {
|
|
130
|
+
if (this.props.maxZoom < 0 || this.props.maxZoom > 24) {
|
|
131
|
+
throw new Error('maxZoom should be in the 0-24 range');
|
|
132
|
+
}
|
|
133
|
+
if (this.props.promoteId && this.props.generateId) {
|
|
134
|
+
throw new Error('promoteId and generateId cannot be used together.');
|
|
135
|
+
}
|
|
136
|
+
log.log(1, 'TableTileSource creating root tiles', this.props)();
|
|
137
|
+
// projects and adds simplification info
|
|
138
|
+
log.time(1, 'preprocess table')();
|
|
139
|
+
let features = convert(table, this.props);
|
|
140
|
+
log.timeEnd(1, 'preprocess table')();
|
|
141
|
+
// wraps features (ie extreme west and extreme east)
|
|
142
|
+
log.time(1, 'generate tiles')();
|
|
143
|
+
features = wrap(features, this.props);
|
|
144
|
+
// start slicing from the top tile down
|
|
145
|
+
if (features.length === 0) {
|
|
146
|
+
log.log(1, 'TableTileSource: no features generated')();
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
this.splitTile(features, 0, 0, 0);
|
|
150
|
+
const rootTile = this.tiles[0];
|
|
151
|
+
log.log(1, `root tile features: ${rootTile.numFeatures}, points: ${rootTile.numPoints}`)();
|
|
152
|
+
log.timeEnd(1, 'generate tiles')();
|
|
153
|
+
log.log(1, `TableTileSource: tiles generated: ${this.stats.get('total').count}`, this.stats)();
|
|
106
154
|
}
|
|
107
155
|
/**
|
|
108
156
|
* Return geojsonvt-style "half formed" vector tile
|
|
@@ -115,7 +163,7 @@ export class GeoJSONTileSource {
|
|
|
115
163
|
// z = +z;
|
|
116
164
|
// x = +x;
|
|
117
165
|
// y = +y;
|
|
118
|
-
const { extent
|
|
166
|
+
const { extent } = this.props;
|
|
119
167
|
if (z < 0 || z > 24) {
|
|
120
168
|
return null;
|
|
121
169
|
}
|
|
@@ -125,8 +173,7 @@ export class GeoJSONTileSource {
|
|
|
125
173
|
if (this.tiles[id]) {
|
|
126
174
|
return transformTile(this.tiles[id], extent);
|
|
127
175
|
}
|
|
128
|
-
|
|
129
|
-
console.log('drilling down to z%d-%d-%d', z, x, y);
|
|
176
|
+
log.log(log, 'drilling down to z%d-%d-%d', z, x, y)();
|
|
130
177
|
let z0 = z;
|
|
131
178
|
let x0 = x;
|
|
132
179
|
let y0 = y;
|
|
@@ -141,14 +188,10 @@ export class GeoJSONTileSource {
|
|
|
141
188
|
return null;
|
|
142
189
|
}
|
|
143
190
|
// if we found a parent tile containing the original geometry, we can drill down from it
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
console.time('drilling down');
|
|
147
|
-
}
|
|
191
|
+
log.log(1, 'found parent tile z%d-%d-%d', z0, x0, y0)();
|
|
192
|
+
log.time(1, 'drilling down')();
|
|
148
193
|
this.splitTile(parent.source, z0, x0, y0, z, x, y);
|
|
149
|
-
|
|
150
|
-
console.timeEnd('drilling down');
|
|
151
|
-
}
|
|
194
|
+
log.timeEnd(1, 'drilling down')();
|
|
152
195
|
return this.tiles[id] ? transformTile(this.tiles[id], extent) : null;
|
|
153
196
|
}
|
|
154
197
|
/**
|
|
@@ -157,13 +200,11 @@ export class GeoJSONTileSource {
|
|
|
157
200
|
* @param cz, cx, and cy are the coordinates of the target tile
|
|
158
201
|
*
|
|
159
202
|
* If no target tile is specified, splitting stops when we reach the maximum
|
|
160
|
-
* zoom or the number of points is low as specified in the
|
|
203
|
+
* zoom or the number of points is low as specified in the props.
|
|
161
204
|
*/
|
|
162
205
|
// eslint-disable-next-line max-params, max-statements, complexity
|
|
163
206
|
splitTile(features, z, x, y, cz, cx, cy) {
|
|
164
207
|
const stack = [features, z, x, y];
|
|
165
|
-
const options = this.options;
|
|
166
|
-
const debug = options.debug;
|
|
167
208
|
// avoid recursion by using a processing queue
|
|
168
209
|
while (stack.length) {
|
|
169
210
|
y = stack.pop();
|
|
@@ -174,31 +215,33 @@ export class GeoJSONTileSource {
|
|
|
174
215
|
const id = toID(z, x, y);
|
|
175
216
|
let tile = this.tiles[id];
|
|
176
217
|
if (!tile) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
tile = this.tiles[id] = createTile(features, z, x, y, options);
|
|
218
|
+
log.time(2, 'tile creation')();
|
|
219
|
+
tile = this.tiles[id] = createTile(features, z, x, y, this.props);
|
|
181
220
|
this.tileCoords.push({ z, x, y });
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
221
|
+
const key = `z${z}`;
|
|
222
|
+
let stat = this.stats.get(key, 'count');
|
|
223
|
+
stat.incrementCount();
|
|
224
|
+
stat = this.stats.get('total');
|
|
225
|
+
stat.incrementCount();
|
|
226
|
+
stat = TableTileSource.stats.get(key, 'count');
|
|
227
|
+
stat.incrementCount();
|
|
228
|
+
stat = TableTileSource.stats.get('total');
|
|
229
|
+
stat.incrementCount();
|
|
230
|
+
log.log(2, 'tile z%d-%d-%d (features: %d, points: %d, simplified: %d)', z, x, y, tile.numFeatures, tile.numPoints, tile.numSimplified)();
|
|
231
|
+
log.timeEnd(2, 'tile creation')();
|
|
191
232
|
}
|
|
192
233
|
// save reference to original geometry in tile so that we can drill down later if we stop now
|
|
193
234
|
tile.source = features;
|
|
235
|
+
/** eslint-disable no-continue */
|
|
194
236
|
// if it's the first-pass tiling
|
|
195
237
|
if (cz === undefined) {
|
|
196
238
|
// stop tiling if we reached max zoom, or if the tile is too simple
|
|
197
|
-
if (z ===
|
|
239
|
+
if (z === this.props.indexMaxZoom || tile.numPoints <= this.props.maxPointsPerTile) {
|
|
198
240
|
continue;
|
|
241
|
+
}
|
|
199
242
|
// if a drilldown to a specific tile
|
|
200
243
|
}
|
|
201
|
-
else if (z ===
|
|
244
|
+
else if (z === this.props.maxZoom || z === cz) {
|
|
202
245
|
// stop tiling if we reached base zoom or our target tile zoom
|
|
203
246
|
continue;
|
|
204
247
|
}
|
|
@@ -206,17 +249,17 @@ export class GeoJSONTileSource {
|
|
|
206
249
|
// stop tiling if it's not an ancestor of the target tile
|
|
207
250
|
const zoomSteps = cz - z;
|
|
208
251
|
// @ts-expect-error TODO fix the types of cx cy
|
|
209
|
-
if (x !== cx >> zoomSteps || y !== cy >> zoomSteps)
|
|
252
|
+
if (x !== cx >> zoomSteps || y !== cy >> zoomSteps) {
|
|
210
253
|
continue;
|
|
254
|
+
}
|
|
211
255
|
}
|
|
212
256
|
// if we slice further down, no need to keep source geometry
|
|
213
257
|
tile.source = null;
|
|
214
258
|
if (features.length === 0)
|
|
215
259
|
continue;
|
|
216
|
-
|
|
217
|
-
console.time('clipping');
|
|
260
|
+
log.time(2, 'clipping tile')();
|
|
218
261
|
// values we'll use for clipping
|
|
219
|
-
const k1 = (0.5 *
|
|
262
|
+
const k1 = (0.5 * this.props.buffer) / this.props.extent;
|
|
220
263
|
const k2 = 0.5 - k1;
|
|
221
264
|
const k3 = 0.5 + k1;
|
|
222
265
|
const k4 = 1 + k1;
|
|
@@ -224,22 +267,21 @@ export class GeoJSONTileSource {
|
|
|
224
267
|
let bl = null;
|
|
225
268
|
let tr = null;
|
|
226
269
|
let br = null;
|
|
227
|
-
let left = clip(features, z2, x - k1, x + k3, 0, tile.minX, tile.maxX,
|
|
228
|
-
let right = clip(features, z2, x + k2, x + k4, 0, tile.minX, tile.maxX,
|
|
270
|
+
let left = clip(features, z2, x - k1, x + k3, 0, tile.minX, tile.maxX, this.props);
|
|
271
|
+
let right = clip(features, z2, x + k2, x + k4, 0, tile.minX, tile.maxX, this.props);
|
|
229
272
|
// @ts-expect-error - unclear why this is needed?
|
|
230
273
|
features = null;
|
|
231
274
|
if (left) {
|
|
232
|
-
tl = clip(left, z2, y - k1, y + k3, 1, tile.minY, tile.maxY,
|
|
233
|
-
bl = clip(left, z2, y + k2, y + k4, 1, tile.minY, tile.maxY,
|
|
275
|
+
tl = clip(left, z2, y - k1, y + k3, 1, tile.minY, tile.maxY, this.props);
|
|
276
|
+
bl = clip(left, z2, y + k2, y + k4, 1, tile.minY, tile.maxY, this.props);
|
|
234
277
|
left = null;
|
|
235
278
|
}
|
|
236
279
|
if (right) {
|
|
237
|
-
tr = clip(right, z2, y - k1, y + k3, 1, tile.minY, tile.maxY,
|
|
238
|
-
br = clip(right, z2, y + k2, y + k4, 1, tile.minY, tile.maxY,
|
|
280
|
+
tr = clip(right, z2, y - k1, y + k3, 1, tile.minY, tile.maxY, this.props);
|
|
281
|
+
br = clip(right, z2, y + k2, y + k4, 1, tile.minY, tile.maxY, this.props);
|
|
239
282
|
right = null;
|
|
240
283
|
}
|
|
241
|
-
|
|
242
|
-
console.timeEnd('clipping');
|
|
284
|
+
log.timeEnd(2, 'clipping tile')();
|
|
243
285
|
stack.push(tl || [], z + 1, x * 2, y * 2);
|
|
244
286
|
stack.push(bl || [], z + 1, x * 2, y * 2 + 1);
|
|
245
287
|
stack.push(tr || [], z + 1, x * 2 + 1, y * 2);
|
|
@@ -250,7 +292,8 @@ export class GeoJSONTileSource {
|
|
|
250
292
|
function toID(z, x, y) {
|
|
251
293
|
return ((1 << z) * y + x) * 32 + z;
|
|
252
294
|
}
|
|
253
|
-
|
|
295
|
+
// eslint-disable-next-line max-statements, complexity
|
|
296
|
+
function convertToGeoJSONTable(vtTile, props) {
|
|
254
297
|
const features = [];
|
|
255
298
|
for (const rawFeature of vtTile.features) {
|
|
256
299
|
if (!rawFeature || !rawFeature.geometry) {
|
|
@@ -293,17 +336,31 @@ function convertToGeoJSONTable(vtTile, extent) {
|
|
|
293
336
|
default:
|
|
294
337
|
continue;
|
|
295
338
|
}
|
|
296
|
-
|
|
339
|
+
switch (props.coordinates) {
|
|
340
|
+
case 'EPSG:4326':
|
|
341
|
+
case 'wgs84':
|
|
342
|
+
projectToLngLat(coordinates, props.tileIndex, props.extent);
|
|
343
|
+
break;
|
|
344
|
+
case 'local':
|
|
345
|
+
convertToLocalCoordinates(coordinates, props.extent);
|
|
346
|
+
break;
|
|
347
|
+
default:
|
|
348
|
+
throw new Error(`Unsupported CRS ${props.coordinates}`);
|
|
349
|
+
}
|
|
297
350
|
const feature = {
|
|
298
351
|
type: 'Feature',
|
|
299
352
|
geometry: {
|
|
300
353
|
type,
|
|
301
354
|
coordinates
|
|
302
355
|
},
|
|
303
|
-
properties: rawFeature.tags || {}
|
|
356
|
+
properties: rawFeature.tags || {},
|
|
357
|
+
id: rawFeature.id
|
|
304
358
|
};
|
|
305
359
|
features.push(feature);
|
|
306
360
|
}
|
|
361
|
+
if (features.length === 0) {
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
307
364
|
const table = {
|
|
308
365
|
shape: 'geojson-table',
|
|
309
366
|
type: 'FeatureCollection',
|
|
@@ -311,9 +368,3 @@ function convertToGeoJSONTable(vtTile, extent) {
|
|
|
311
368
|
};
|
|
312
369
|
return table;
|
|
313
370
|
}
|
|
314
|
-
function toLngLat(coords, extent) {
|
|
315
|
-
if (Array.isArray(coords[0])) {
|
|
316
|
-
return coords.map((c) => toLngLat(c, extent));
|
|
317
|
-
}
|
|
318
|
-
return [coords[0] / extent, coords[1] / extent];
|
|
319
|
-
}
|
package/dist/tilejson-loader.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { parseTileJSON } from "./lib/parse-tilejson.js";
|
|
5
5
|
// __VERSION__ is injected by babel-plugin-version-inline
|
|
6
6
|
// @ts-ignore TS2304: Cannot find name '__VERSION__'.
|
|
7
|
-
const VERSION = typeof "4.
|
|
7
|
+
const VERSION = typeof "4.3.0-alpha.1" !== 'undefined' ? "4.3.0-alpha.1" : 'latest';
|
|
8
8
|
/**
|
|
9
9
|
* Loader for TileJSON metadata
|
|
10
10
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loaders.gl/mvt",
|
|
3
3
|
"description": "Loader for Mapbox Vector Tiles",
|
|
4
|
-
"version": "4.3.0-alpha.
|
|
4
|
+
"version": "4.3.0-alpha.2",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"publishConfig": {
|
|
@@ -41,11 +41,12 @@
|
|
|
41
41
|
"build-worker": "esbuild src/workers/mvt-worker.ts --bundle --outfile=dist/mvt-worker.js --define:__VERSION__=\\\"$npm_package_version\\\""
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@loaders.gl/gis": "4.3.0-alpha.
|
|
45
|
-
"@loaders.gl/images": "4.3.0-alpha.
|
|
46
|
-
"@loaders.gl/loader-utils": "4.3.0-alpha.
|
|
47
|
-
"@loaders.gl/schema": "4.3.0-alpha.
|
|
44
|
+
"@loaders.gl/gis": "4.3.0-alpha.2",
|
|
45
|
+
"@loaders.gl/images": "4.3.0-alpha.2",
|
|
46
|
+
"@loaders.gl/loader-utils": "4.3.0-alpha.2",
|
|
47
|
+
"@loaders.gl/schema": "4.3.0-alpha.2",
|
|
48
48
|
"@math.gl/polygon": "^4.0.0",
|
|
49
|
+
"@probe.gl/stats": "^4.0.0",
|
|
49
50
|
"pbf": "^3.2.1"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
@@ -54,5 +55,5 @@
|
|
|
54
55
|
"peerDependencies": {
|
|
55
56
|
"@loaders.gl/core": "^4.0.0"
|
|
56
57
|
},
|
|
57
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "77a3cb538ab7a1fbf74245f25590210451689f5c"
|
|
58
59
|
}
|
package/src/index.ts
CHANGED
|
@@ -11,7 +11,7 @@ export {TileJSONLoader} from './tilejson-loader';
|
|
|
11
11
|
|
|
12
12
|
export {MVTSource} from './mvt-source';
|
|
13
13
|
|
|
14
|
-
//
|
|
14
|
+
// TableTileSource
|
|
15
15
|
|
|
16
|
-
export type {
|
|
17
|
-
export {
|
|
16
|
+
export type {TableTileSourceProps} from './table-tile-source';
|
|
17
|
+
export {TableTileSource} from './table-tile-source';
|
package/src/lib/parse-mvt.ts
CHANGED
|
@@ -155,9 +155,9 @@ function getDecodedFeature(
|
|
|
155
155
|
options: MVTOptions,
|
|
156
156
|
layerName: string
|
|
157
157
|
): Feature {
|
|
158
|
-
const decodedFeature = feature.
|
|
159
|
-
|
|
160
|
-
options.
|
|
158
|
+
const decodedFeature = feature.toGeoJSONFeature(
|
|
159
|
+
options.coordinates || 'local',
|
|
160
|
+
options.tileIndex
|
|
161
161
|
);
|
|
162
162
|
|
|
163
163
|
// Add layer name to GeoJSON properties
|
|
@@ -179,10 +179,7 @@ function getDecodedFeatureBinary(
|
|
|
179
179
|
options: MVTOptions,
|
|
180
180
|
layerName: string
|
|
181
181
|
): FlatFeature {
|
|
182
|
-
const decodedFeature = feature.
|
|
183
|
-
// @ts-expect-error
|
|
184
|
-
options.coordinates === 'wgs84' ? options.tileIndex : transformToLocalCoordinatesBinary
|
|
185
|
-
);
|
|
182
|
+
const decodedFeature = feature.toBinaryFeature(options.coordinates || 'local', options.tileIndex);
|
|
186
183
|
|
|
187
184
|
// Add layer name to GeoJSON properties
|
|
188
185
|
if (options.layerProperty && decodedFeature.properties) {
|
|
@@ -191,29 +188,3 @@ function getDecodedFeatureBinary(
|
|
|
191
188
|
|
|
192
189
|
return decodedFeature;
|
|
193
190
|
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* @param line
|
|
197
|
-
* @param feature
|
|
198
|
-
*/
|
|
199
|
-
function transformToLocalCoordinates(line: number[], feature: {extent: any}): void {
|
|
200
|
-
// This function transforms local coordinates in a
|
|
201
|
-
// [0 - bufferSize, this.extent + bufferSize] range to a
|
|
202
|
-
// [0 - (bufferSize / this.extent), 1 + (bufferSize / this.extent)] range.
|
|
203
|
-
// The resulting extent would be 1.
|
|
204
|
-
const {extent} = feature;
|
|
205
|
-
for (let i = 0; i < line.length; i++) {
|
|
206
|
-
const p = line[i];
|
|
207
|
-
p[0] /= extent;
|
|
208
|
-
p[1] /= extent;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
function transformToLocalCoordinatesBinary(data: number[], feature: {extent: any}) {
|
|
213
|
-
// For the binary code path, the feature data is just
|
|
214
|
-
// one big flat array, so we just divide each value
|
|
215
|
-
const {extent} = feature;
|
|
216
|
-
for (let i = 0, il = data.length; i < il; ++i) {
|
|
217
|
-
data[i] /= extent;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
@@ -16,11 +16,6 @@ export type TileJSON = {
|
|
|
16
16
|
tileFormat?: string;
|
|
17
17
|
tilesetType?: string;
|
|
18
18
|
|
|
19
|
-
/** Generating application. Tippecanoe adds this. */
|
|
20
|
-
generator?: string;
|
|
21
|
-
/** Generating application options. Tippecanoe adds this. */
|
|
22
|
-
generatorOptions?: string;
|
|
23
|
-
|
|
24
19
|
/** Tile indexing scheme */
|
|
25
20
|
scheme?: 'xyz' | 'tms';
|
|
26
21
|
/** Sharded URLs */
|
|
@@ -38,6 +33,11 @@ export type TileJSON = {
|
|
|
38
33
|
// Combination of tilestats (if present) and tilejson layer information
|
|
39
34
|
layers?: TileJSONLayer[];
|
|
40
35
|
|
|
36
|
+
/** Generating application. Tippecanoe adds this. */
|
|
37
|
+
generator?: string;
|
|
38
|
+
/** Generating application options. Tippecanoe adds this. */
|
|
39
|
+
generatorOptions?: string;
|
|
40
|
+
|
|
41
41
|
/** Any nested JSON metadata */
|
|
42
42
|
metaJson?: any | null;
|
|
43
43
|
};
|
|
@@ -20,16 +20,80 @@ export function signedArea(ring: number[][]) {
|
|
|
20
20
|
return sum;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* This function projects local coordinates in a
|
|
25
|
+
* [0 - bufferSize, this.extent + bufferSize] range to a
|
|
26
|
+
* [0 - (bufferSize / this.extent), 1 + (bufferSize / this.extent)] range.
|
|
27
|
+
* The resulting extent would be 1.
|
|
28
|
+
* @param line
|
|
29
|
+
* @param feature
|
|
30
|
+
*/
|
|
31
|
+
export function convertToLocalCoordinates(
|
|
32
|
+
coordinates: number[] | number[][] | number[][][] | number[][][][],
|
|
33
|
+
extent: number
|
|
34
|
+
): void {
|
|
35
|
+
if (Array.isArray(coordinates[0])) {
|
|
36
|
+
for (const subcoords of coordinates) {
|
|
37
|
+
convertToLocalCoordinates(subcoords as number[] | number[][] | number[][][], extent);
|
|
38
|
+
}
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Just a point
|
|
43
|
+
const p = coordinates as number[];
|
|
44
|
+
p[0] /= extent;
|
|
45
|
+
p[1] /= extent;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* For the binary code path, the feature data is just
|
|
50
|
+
* one big flat array, so we just divide each value
|
|
51
|
+
* @param data
|
|
52
|
+
* @param feature
|
|
53
|
+
*/
|
|
54
|
+
export function convertToLocalCoordinatesFlat(data: number[], extent: number): void {
|
|
55
|
+
for (let i = 0, il = data.length; i < il; ++i) {
|
|
56
|
+
data[i] /= extent;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
23
60
|
/**
|
|
24
61
|
* Projects local tile coordinates to lngLat in place.
|
|
25
62
|
* @param points
|
|
26
63
|
* @param tileIndex
|
|
27
64
|
*/
|
|
65
|
+
export function projectToLngLat(
|
|
66
|
+
line: number[] | number[][] | number[][][],
|
|
67
|
+
tileIndex: {x: number; y: number; z: number},
|
|
68
|
+
extent: number
|
|
69
|
+
): void {
|
|
70
|
+
if (typeof line[0][0] !== 'number') {
|
|
71
|
+
for (const point of line) {
|
|
72
|
+
// @ts-expect-error
|
|
73
|
+
projectToLngLat(point, tileIndex, extent);
|
|
74
|
+
}
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const size = extent * Math.pow(2, tileIndex.z);
|
|
78
|
+
const x0 = extent * tileIndex.x;
|
|
79
|
+
const y0 = extent * tileIndex.y;
|
|
80
|
+
for (let j = 0; j < line.length; j++) {
|
|
81
|
+
const p = line[j];
|
|
82
|
+
p[0] = ((p[0] + x0) * 360) / size - 180;
|
|
83
|
+
const y2 = 180 - ((p[1] + y0) * 360) / size;
|
|
84
|
+
p[1] = (360 / Math.PI) * Math.atan(Math.exp((y2 * Math.PI) / 180)) - 90;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Projects local tile coordinates to lngLat in place.
|
|
90
|
+
* @param points
|
|
91
|
+
* @param tileIndex
|
|
28
92
|
export function projectTileCoordinatesToLngLat(
|
|
29
93
|
points: number[][],
|
|
30
94
|
tileIndex: {x: number; y: number; z: number},
|
|
31
95
|
extent: number
|
|
32
|
-
) {
|
|
96
|
+
): void {
|
|
33
97
|
const {x, y, z} = tileIndex;
|
|
34
98
|
const size = extent * Math.pow(2, z);
|
|
35
99
|
const x0 = extent * x;
|
|
@@ -41,6 +105,7 @@ export function projectTileCoordinatesToLngLat(
|
|
|
41
105
|
p[1] = (360 / Math.PI) * Math.atan(Math.exp((y2 * Math.PI) / 180)) - 90;
|
|
42
106
|
}
|
|
43
107
|
}
|
|
108
|
+
*/
|
|
44
109
|
|
|
45
110
|
/**
|
|
46
111
|
*
|