@loaders.gl/mvt 4.3.2 → 4.4.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.
Files changed (51) hide show
  1. package/dist/dist.dev.js +151 -93
  2. package/dist/dist.min.js +1 -1
  3. package/dist/index.cjs +74 -78
  4. package/dist/index.cjs.map +4 -4
  5. package/dist/index.d.ts +2 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +0 -1
  8. package/dist/lib/parse-mvt.d.ts.map +1 -1
  9. package/dist/lib/pojo-parser/mvt-constants.d.ts +116 -0
  10. package/dist/lib/pojo-parser/mvt-constants.d.ts.map +1 -0
  11. package/dist/lib/pojo-parser/mvt-constants.js +126 -0
  12. package/dist/lib/pojo-parser/mvt-types.d.ts +17 -0
  13. package/dist/lib/pojo-parser/mvt-types.d.ts.map +1 -0
  14. package/dist/lib/pojo-parser/mvt-types.js +4 -0
  15. package/dist/lib/pojo-parser/parse-geometry-from-pbf.d.ts +77 -0
  16. package/dist/lib/pojo-parser/parse-geometry-from-pbf.d.ts.map +1 -0
  17. package/dist/lib/pojo-parser/parse-geometry-from-pbf.js +234 -0
  18. package/dist/lib/pojo-parser/parse-mvt-from-pbf.d.ts +25 -0
  19. package/dist/lib/pojo-parser/parse-mvt-from-pbf.d.ts.map +1 -0
  20. package/dist/lib/pojo-parser/parse-mvt-from-pbf.js +262 -0
  21. package/dist/lib/vector-tile/vector-tile-feature.d.ts +2 -1
  22. package/dist/lib/vector-tile/vector-tile-feature.d.ts.map +1 -1
  23. package/dist/lib/vector-tile/vector-tile-layer.d.ts +1 -1
  24. package/dist/lib/vector-tile/vector-tile-layer.d.ts.map +1 -1
  25. package/dist/mvt-format.d.ts +12 -0
  26. package/dist/mvt-format.d.ts.map +1 -0
  27. package/dist/mvt-format.js +20 -0
  28. package/dist/mvt-loader.d.ts +12 -12
  29. package/dist/mvt-loader.d.ts.map +1 -1
  30. package/dist/mvt-loader.js +3 -13
  31. package/dist/mvt-source.d.ts +22 -24
  32. package/dist/mvt-source.d.ts.map +1 -1
  33. package/dist/mvt-source.js +14 -23
  34. package/dist/mvt-worker.js +20 -15
  35. package/dist/table-tile-source.d.ts +38 -38
  36. package/dist/table-tile-source.d.ts.map +1 -1
  37. package/dist/table-tile-source.js +54 -53
  38. package/dist/tilejson-loader.js +1 -1
  39. package/package.json +7 -7
  40. package/src/index.ts +2 -2
  41. package/src/lib/parse-mvt.ts +2 -8
  42. package/src/lib/pojo-parser/mvt-constants.ts +135 -0
  43. package/src/lib/pojo-parser/mvt-types.ts +22 -0
  44. package/src/lib/pojo-parser/parse-geometry-from-pbf.ts +285 -0
  45. package/src/lib/pojo-parser/parse-mvt-from-pbf.ts +310 -0
  46. package/src/lib/vector-tile/vector-tile-feature.ts +2 -6
  47. package/src/lib/vector-tile/vector-tile-layer.ts +1 -1
  48. package/src/mvt-format.ts +23 -0
  49. package/src/mvt-loader.ts +2 -13
  50. package/src/mvt-source.ts +33 -38
  51. package/src/table-tile-source.ts +116 -96
@@ -0,0 +1,310 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright vis.gl contributors
4
+
5
+ // This code is inspired by https://github.com/mapbox/vector-tile-js under BSD 3-clause license.
6
+
7
+ import Protobuf from 'pbf';
8
+ import {Schema} from '@loaders.gl/schema';
9
+ import type {MVTTile, MVTLayer} from './mvt-types';
10
+ import * as MVT from './mvt-constants';
11
+ import {readBoundingBoxFromPBF, loadFlatGeometryFromPBF} from './parse-geometry-from-pbf';
12
+
13
+ export type MVTLayerData = {
14
+ /** Layer being built */
15
+ layer: MVTLayer;
16
+ currentFeature: number;
17
+ /** list of all keys in layer: Temporary, used when building up the layer */
18
+ keys: string[];
19
+ /** single list of all values in all columns - Temporary values used when building up the layer */
20
+ values: (string | number | boolean | null)[];
21
+ types: number[];
22
+ columnTypes: number[];
23
+ columnNullable: boolean[];
24
+ /** list of all feature start positions in the PBF - Temporary values used when building up the layer */
25
+ featurePositions: number[];
26
+ /** list of all geometry start positions in the PBF - Temporary values used when building up the layer */
27
+ geometryPositions: number[];
28
+ };
29
+
30
+ const DEFAULT_LAYER = {
31
+ version: 1,
32
+ name: '',
33
+ extent: 4096,
34
+ length: 0,
35
+ schema: {fields: [], metadata: {}},
36
+ columns: {},
37
+ idColumn: [],
38
+ geometryTypeColumn: [],
39
+ geometryColumn: [],
40
+ boundingBoxColumn: []
41
+ } as const satisfies MVTLayer;
42
+
43
+ const DEFAULT_LAYER_DATA = {
44
+ currentFeature: 0,
45
+ keys: [],
46
+ values: [],
47
+ types: [],
48
+ columnTypes: [],
49
+ columnNullable: [],
50
+ featurePositions: [],
51
+ geometryPositions: []
52
+ };
53
+
54
+ /** Parse an MVT tile from an ArrayBuffer */
55
+ export function parseMVT(arrayBuffer: ArrayBuffer | Uint8Array): MVTTile {
56
+ const pbf = new Protobuf(arrayBuffer);
57
+ return parseMVTTile(pbf);
58
+ }
59
+
60
+ /** Parse an MVT tile from a PBF buffer */
61
+ export function parseMVTTile(pbf: Protobuf, end?: number): MVTTile {
62
+ const tile = {layers: {}} satisfies MVTTile;
63
+ try {
64
+ pbf.readFields(readTileFieldFromPBF, tile, end);
65
+ } catch (error) {
66
+ // eslint-disable-next-line no-console
67
+ console.warn(error);
68
+ }
69
+ return tile;
70
+ }
71
+
72
+ /**
73
+ * Protobuf read callback for a top-level tile object's PBF tags
74
+ * @param tag
75
+ * @param layers
76
+ * @param pbf
77
+ */
78
+ function readTileFieldFromPBF(tag: number, tile?: MVTTile, pbf?: Protobuf): void {
79
+ if (!pbf || !tile) {
80
+ return;
81
+ }
82
+
83
+ switch (tag as MVT.TileInfo) {
84
+ case MVT.TileInfo.layers:
85
+ // get the byte length and end of the layer
86
+ const byteLength = pbf.readVarint();
87
+ const end = byteLength + pbf.pos;
88
+
89
+ const layer = parseLayer(pbf, end);
90
+ tile.layers[layer.name] = layer;
91
+ break;
92
+ default:
93
+ // ignore? log?
94
+ }
95
+ }
96
+
97
+ /** Parse an MVT layer from BPF at current position */
98
+ export function parseLayer(pbf: Protobuf, end: number): MVTLayer {
99
+ const layerData: MVTLayerData = {layer: {...DEFAULT_LAYER}, ...DEFAULT_LAYER_DATA};
100
+ pbf.readFields(readLayerFieldFromPBF, layerData, end);
101
+
102
+ // Read features
103
+ for (let featureIndex = 0; featureIndex < layerData.featurePositions.length; featureIndex++) {
104
+ // Determine start and end of feature in PBF
105
+ const featurePosition = layerData.featurePositions[featureIndex];
106
+
107
+ pbf.pos = featurePosition;
108
+ const byteLength = pbf.readVarint();
109
+ const end = byteLength + pbf.pos;
110
+
111
+ layerData.currentFeature = featureIndex;
112
+ pbf.readFields(readFeatureFieldFromPBF, layerData, end);
113
+ readBoundingBoxesFromPDF(pbf, layerData);
114
+ readGeometriesFromPBF(pbf, layerData);
115
+ }
116
+
117
+ // Post processing
118
+ const {layer} = layerData;
119
+ layer.length = layerData.featurePositions.length;
120
+ layer.schema = makeMVTSchema(layerData);
121
+ return layer;
122
+ }
123
+
124
+ /**
125
+ *
126
+ * @param tag
127
+ * @param layer
128
+ * @param pbf
129
+ */
130
+ function readLayerFieldFromPBF(tag: number, layerData?: MVTLayerData, pbf?: Protobuf): void {
131
+ if (!layerData || !pbf) {
132
+ return;
133
+ }
134
+
135
+ switch (tag as MVT.LayerInfo) {
136
+ case MVT.LayerInfo.version:
137
+ layerData.layer.version = pbf.readVarint();
138
+ break;
139
+ case MVT.LayerInfo.name:
140
+ layerData.layer.name = pbf.readString();
141
+ break;
142
+ case MVT.LayerInfo.extent:
143
+ layerData.layer.extent = pbf.readVarint();
144
+ break;
145
+ case MVT.LayerInfo.features:
146
+ layerData.featurePositions.push(pbf.pos);
147
+ break;
148
+ case MVT.LayerInfo.keys:
149
+ layerData.keys.push(pbf.readString());
150
+ break;
151
+ case MVT.LayerInfo.values:
152
+ const [value, type] = parseValues(pbf);
153
+ layerData.values.push(value);
154
+ layerData.types.push(type);
155
+ break;
156
+ default:
157
+ // ignore? Log?
158
+ }
159
+ }
160
+
161
+ /**
162
+ * @param pbf
163
+ * @returns value
164
+ */
165
+ function parseValues(pbf: Protobuf): [string | number | boolean | null, MVT.PropertyType] {
166
+ const end = pbf.readVarint() + pbf.pos;
167
+
168
+ let value: string | number | boolean | null = null;
169
+ // not a valid property type so we use it to detect multiple values
170
+ let type = -1 as MVT.PropertyType;
171
+
172
+ // TODO - can we have multiple values?
173
+ while (pbf.pos < end) {
174
+ if (type !== (-1 as MVT.PropertyType)) {
175
+ throw new Error('MVT: Multiple values not supported');
176
+ }
177
+ type = pbf.readVarint() >> 3;
178
+ value = readValueFromPBF(pbf, type);
179
+ }
180
+ return [value, type];
181
+ }
182
+
183
+ /** Read a type tagged value from the protobuf at current position */
184
+ function readValueFromPBF(pbf: Protobuf, type: MVT.PropertyType): string | number | boolean | null {
185
+ switch (type) {
186
+ case MVT.PropertyType.string_value:
187
+ return pbf.readString();
188
+ case MVT.PropertyType.float_value:
189
+ return pbf.readFloat();
190
+ case MVT.PropertyType.double_value:
191
+ return pbf.readDouble();
192
+ case MVT.PropertyType.int_value:
193
+ return pbf.readVarint64();
194
+ case MVT.PropertyType.uint_value:
195
+ return pbf.readVarint();
196
+ case MVT.PropertyType.sint_value:
197
+ return pbf.readSVarint();
198
+ case MVT.PropertyType.bool_value:
199
+ return pbf.readBoolean();
200
+ default:
201
+ return null;
202
+ }
203
+ }
204
+
205
+ /**
206
+ *
207
+ * @param tag
208
+ * @param feature
209
+ * @param pbf
210
+ */
211
+ function readFeatureFieldFromPBF(tag: number, layerData?: MVTLayerData, pbf?: Protobuf): void {
212
+ if (!pbf || !layerData) {
213
+ return;
214
+ }
215
+ switch (tag as MVT.FeatureInfo) {
216
+ case MVT.FeatureInfo.id:
217
+ const id = pbf.readVarint();
218
+ layerData.layer.idColumn[layerData.currentFeature] = id;
219
+ break;
220
+ case MVT.FeatureInfo.tags:
221
+ parseColumnValues(pbf, layerData);
222
+ break;
223
+ case MVT.FeatureInfo.type:
224
+ const type = pbf.readVarint();
225
+ layerData.layer.geometryTypeColumn[layerData.currentFeature] = type;
226
+ break;
227
+ case MVT.FeatureInfo.geometry:
228
+ layerData.geometryPositions[layerData.currentFeature] = pbf.pos;
229
+ break;
230
+ default:
231
+ // ignore? log?
232
+ }
233
+ }
234
+
235
+ /**
236
+ *
237
+ * @param pbf
238
+ * @param feature
239
+ */
240
+ function parseColumnValues(pbf: Protobuf, layerData: MVTLayerData): void {
241
+ const end = pbf.readVarint() + pbf.pos;
242
+
243
+ while (pbf.pos < end) {
244
+ const keyIndex = pbf.readVarint();
245
+ const valueIndex = pbf.readVarint();
246
+ const columnName = layerData.keys[keyIndex];
247
+ const value = layerData.values[valueIndex];
248
+ layerData.columnTypes[columnName] = layerData.types[valueIndex];
249
+ layerData.columnNullable[columnName] ||= value === null;
250
+
251
+ layerData.layer.columns[columnName] ||= [];
252
+ layerData.layer.columns[columnName].push(value);
253
+ }
254
+ }
255
+
256
+ // Geometry readers
257
+
258
+ function readBoundingBoxesFromPDF(pbf: Protobuf, layerData: MVTLayerData): void {
259
+ for (let row = 0; row < layerData.geometryPositions.length; row++) {
260
+ pbf.pos = layerData.geometryPositions[row];
261
+ const boundingBox = readBoundingBoxFromPBF(pbf);
262
+ layerData.layer.boundingBoxColumn[row] = boundingBox;
263
+ }
264
+ }
265
+
266
+ function readGeometriesFromPBF(pbf: Protobuf, layerData: MVTLayerData): void {
267
+ for (let row = 0; row < layerData.geometryPositions.length; row++) {
268
+ pbf.pos = layerData.geometryPositions[row];
269
+ const flatGeometry = loadFlatGeometryFromPBF(pbf);
270
+ layerData.layer.geometryColumn[row] = flatGeometry;
271
+ }
272
+ }
273
+
274
+ // Schema Builder
275
+
276
+ function makeMVTSchema(layerData: MVTLayerData): Schema {
277
+ const {keys, columnTypes, columnNullable} = layerData;
278
+ const fields: Schema['fields'] = [];
279
+ for (let i = 0; i < keys.length; i++) {
280
+ const key = keys[i];
281
+ const nullable = columnNullable[key];
282
+ switch (columnTypes[key] as MVT.PropertyType) {
283
+ case MVT.PropertyType.string_value:
284
+ fields.push({name: keys[i], type: 'utf8', nullable});
285
+ break;
286
+ case MVT.PropertyType.float_value:
287
+ fields.push({name: keys[i], type: 'float32', nullable});
288
+ break;
289
+ case MVT.PropertyType.double_value:
290
+ fields.push({name: keys[i], type: 'float64', nullable});
291
+ break;
292
+ case MVT.PropertyType.int_value:
293
+ fields.push({name: keys[i], type: 'int32', nullable});
294
+ break;
295
+ case MVT.PropertyType.uint_value:
296
+ fields.push({name: keys[i], type: 'uint32', nullable});
297
+ break;
298
+ case MVT.PropertyType.sint_value:
299
+ fields.push({name: keys[i], type: 'int32', nullable});
300
+ break;
301
+ case MVT.PropertyType.bool_value:
302
+ fields.push({name: keys[i], type: 'bool', nullable});
303
+ break;
304
+ default:
305
+ // ignore?
306
+ }
307
+ }
308
+
309
+ return {fields, metadata: {}};
310
+ }
@@ -4,12 +4,8 @@
4
4
 
5
5
  // This code is forked from https://github.com/mapbox/vector-tile-js under BSD 3-clause license.
6
6
 
7
- import type {
8
- Feature,
9
- FlatFeature,
10
- FlatIndexedGeometry,
11
- GeojsonGeometryInfo
12
- } from '@loaders.gl/schema';
7
+ import type {Feature, FlatFeature, FlatIndexedGeometry} from '@loaders.gl/schema';
8
+ import type {GeojsonGeometryInfo} from '@loaders.gl/gis';
13
9
  import Protobuf from 'pbf';
14
10
  import {
15
11
  classifyRings,
@@ -7,7 +7,7 @@
7
7
 
8
8
  import Protobuf from 'pbf';
9
9
  import {VectorTileFeature} from './vector-tile-feature';
10
- import {GeojsonGeometryInfo} from '@loaders.gl/schema';
10
+ import {GeojsonGeometryInfo} from '@loaders.gl/gis';
11
11
 
12
12
  export class VectorTileLayer {
13
13
  version: number;
@@ -0,0 +1,23 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright vis.gl contributors
4
+
5
+ import type {Format} from '@loaders.gl/loader-utils';
6
+
7
+ /**
8
+ * Worker loader for the Mapbox Vector Tile format
9
+ */
10
+ export const MVTFormat = {
11
+ name: 'Mapbox Vector Tile',
12
+ id: 'mvt',
13
+ module: 'mvt',
14
+ // Note: ArcGIS uses '.pbf' extension and 'application/octet-stream'
15
+ extensions: ['mvt', 'pbf'],
16
+ mimeTypes: [
17
+ // https://www.iana.org/assignments/media-types/application/vnd.mapbox-vector-tile
18
+ 'application/vnd.mapbox-vector-tile',
19
+ 'application/x-protobuf'
20
+ // 'application/octet-stream'
21
+ ],
22
+ category: 'geometry'
23
+ } as const satisfies Format;
package/src/mvt-loader.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  import type {Loader, LoaderWithParser, LoaderOptions} from '@loaders.gl/loader-utils';
6
6
  // import type {MVTOptions} from './lib/types';
7
7
  import {parseMVT} from './lib/parse-mvt';
8
+ import {MVTFormat} from './mvt-format';
8
9
 
9
10
  // __VERSION__ is injected by babel-plugin-version-inline
10
11
  // @ts-ignore TS2304: Cannot find name '__VERSION__'.
@@ -37,23 +38,11 @@ export type MVTLoaderOptions = LoaderOptions & {
37
38
  * Worker loader for the Mapbox Vector Tile format
38
39
  */
39
40
  export const MVTWorkerLoader = {
41
+ ...MVTFormat,
40
42
  dataType: null as any,
41
43
  batchType: null as never,
42
-
43
- name: 'Mapbox Vector Tile',
44
- id: 'mvt',
45
- module: 'mvt',
46
44
  version: VERSION,
47
- // Note: ArcGIS uses '.pbf' extension and 'application/octet-stream'
48
- extensions: ['mvt', 'pbf'],
49
- mimeTypes: [
50
- // https://www.iana.org/assignments/media-types/application/vnd.mapbox-vector-tile
51
- 'application/vnd.mapbox-vector-tile',
52
- 'application/x-protobuf'
53
- // 'application/octet-stream'
54
- ],
55
45
  worker: true,
56
- category: 'geometry',
57
46
  options: {
58
47
  mvt: {
59
48
  shape: 'geojson',
package/src/mvt-source.ts CHANGED
@@ -5,13 +5,13 @@
5
5
  import type {
6
6
  Source,
7
7
  ImageType,
8
- DataSourceProps,
8
+ DataSourceOptions,
9
9
  ImageTileSource,
10
10
  VectorTileSource,
11
11
  GetTileParameters,
12
12
  GetTileDataParameters
13
13
  } from '@loaders.gl/loader-utils';
14
- import {DataSource, resolvePath} from '@loaders.gl/loader-utils';
14
+ import {DataSource} from '@loaders.gl/loader-utils';
15
15
  import {ImageLoader, ImageLoaderOptions, getBinaryImageMetadata} from '@loaders.gl/images';
16
16
  import {
17
17
  MVTLoader,
@@ -20,32 +20,10 @@ import {
20
20
  TileJSON,
21
21
  TileJSONLoaderOptions
22
22
  } from '@loaders.gl/mvt';
23
-
24
- /** Creates an MVTTileSource */
25
- export const MVTSource = {
26
- name: 'MVT',
27
- id: 'mvt',
28
- module: 'mvt',
29
- version: '0.0.0',
30
- extensions: ['mvt'],
31
- mimeTypes: ['application/octet-stream'],
32
- options: {
33
- mvt: {
34
- // TODO - add options here
35
- }
36
- },
37
- type: 'mvt',
38
- fromUrl: true,
39
- fromBlob: false,
40
-
41
- testURL: (url: string): boolean => true,
42
- createDataSource(url: string, props: MVTTileSourceProps): MVTTileSource {
43
- return new MVTTileSource(url, props);
44
- }
45
- } as const satisfies Source<MVTTileSource, MVTTileSourceProps>;
23
+ import {MVTFormat} from './mvt-format';
46
24
 
47
25
  /** Properties for a Mapbox Vector Tile Source */
48
- export type MVTTileSourceProps = DataSourceProps & {
26
+ export type MVTSourceOptions = DataSourceOptions & {
49
27
  mvt?: {
50
28
  // TODO - add options here
51
29
  /** if not supplied, loads tilejson.json, If null does not load metadata */
@@ -59,6 +37,26 @@ export type MVTTileSourceProps = DataSourceProps & {
59
37
  };
60
38
  };
61
39
 
40
+ /** Creates an MVTTileSource */
41
+ export const MVTSource = {
42
+ ...MVTFormat,
43
+ version: '0.0.0',
44
+ type: 'mvt',
45
+ fromUrl: true,
46
+ fromBlob: false,
47
+
48
+ defaultOptions: {
49
+ mvt: {
50
+ // TODO - add options here
51
+ }
52
+ },
53
+
54
+ testURL: (url: string): boolean => true,
55
+ createDataSource(url: string, options: MVTSourceOptions): MVTTileSource {
56
+ return new MVTTileSource(url, options);
57
+ }
58
+ } as const satisfies Source<MVTTileSource>;
59
+
62
60
  /**
63
61
  * MVT data source for Mapbox Vector Tiles v1.
64
62
  */
@@ -66,23 +64,20 @@ export type MVTTileSourceProps = DataSourceProps & {
66
64
  * A PMTiles data source
67
65
  * @note Can be either a raster or vector tile source depending on the contents of the PMTiles file.
68
66
  */
69
- export class MVTTileSource extends DataSource implements ImageTileSource, VectorTileSource {
70
- readonly props: MVTTileSourceProps;
71
- readonly url: string;
67
+ export class MVTTileSource
68
+ extends DataSource<string, MVTSourceOptions>
69
+ implements ImageTileSource, VectorTileSource
70
+ {
72
71
  readonly metadataUrl: string | null = null;
73
- data: string;
74
72
  schema: 'tms' | 'xyz' | 'template' = 'tms';
75
73
  metadata: Promise<TileJSON | null>;
76
74
  extension: string;
77
75
  mimeType: string | null = null;
78
76
 
79
- constructor(url: string, props: MVTTileSourceProps) {
80
- super(props);
81
- this.props = props;
82
- this.url = resolvePath(url);
83
- this.metadataUrl = props.mvt?.metadataUrl || `${this.url}/tilejson.json`;
84
- this.extension = props.mvt?.extension || '.png';
85
- this.data = this.url;
77
+ constructor(url: string, options: MVTSourceOptions) {
78
+ super(url, options, MVTSource.defaultOptions);
79
+ this.metadataUrl = options.mvt?.metadataUrl || `${this.url}/tilejson.json`;
80
+ this.extension = options.mvt?.extension || '.png';
86
81
 
87
82
  this.getTileData = this.getTileData.bind(this);
88
83
  this.metadata = this.getMetadata();
@@ -117,7 +112,7 @@ export class MVTTileSource extends DataSource implements ImageTileSource, Vector
117
112
  const metadata = TileJSONLoader.parseTextSync?.(tileJSON) || null;
118
113
 
119
114
  // TODO add metadata attributions
120
- // metadata.attributions = [...this.props.attributions, ...(metadata.attributions || [])];
115
+ // metadata.attributions = [...this.options.attributions, ...(metadata.attributions || [])];
121
116
  // if (metadata?.mimeType) {
122
117
  // this.mimeType = metadata?.tileMIMEType;
123
118
  // }