UNPKG

@loaders.gl/mvt

Version:

Loader for Mapbox Vector Tiles

1,648 lines (1,626 loc) 77.5 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; // dist/index.js var dist_exports = {}; __export(dist_exports, { MVTLoader: () => MVTLoader, MVTSource: () => MVTSource, MVTWorkerLoader: () => MVTWorkerLoader, MVTWriter: () => MVTWriter, TableTileSource: () => TableTileSource, TileJSONLoader: () => TileJSONLoader }); module.exports = __toCommonJS(dist_exports); // dist/lib/get-schemas-from-tilejson.js function getSchemaFromTileJSONLayer(layer) { const fields = []; if (layer.fields) { for (const field of layer.fields) { fields.push({ name: field.name, type: getDataTypeFromTileJSONField(field), metadata: getMetadataFromTileJSONField(field) }); } } return { metadata: getMetadataFromTileJSONLayer(layer), fields }; } function getMetadataFromTileJSONLayer(layer) { const metadata = {}; for (const [key, value] of Object.entries(layer)) { if (key !== "fields" && value) { metadata[key] = JSON.stringify(value); } } return metadata; } function getDataTypeFromTileJSONField(field) { switch (field.type.toLowerCase()) { case "float32": return "float32"; case "number": case "float64": return "float64"; case "string": case "utf8": return "utf8"; case "boolean": return "bool"; default: return "null"; } } function getMetadataFromTileJSONField(field) { const metadata = {}; for (const [key, value] of Object.entries(field)) { if (key !== "name" && value) { metadata[key] = JSON.stringify(value); } } return metadata; } // dist/lib/parse-tilejson.js var isObject = (x) => x !== null && typeof x === "object"; function parseTileJSON(jsonMetadata, options) { var _a; if (!jsonMetadata || !isObject(jsonMetadata)) { return null; } let tileJSON = { name: jsonMetadata.name || "", description: jsonMetadata.description || "" }; if (typeof jsonMetadata.generator === "string") { tileJSON.generator = jsonMetadata.generator; } if (typeof jsonMetadata.generator_options === "string") { tileJSON.generatorOptions = jsonMetadata.generator_options; } tileJSON.boundingBox = parseBounds(jsonMetadata.bounds) || parseBounds(jsonMetadata.antimeridian_adjusted_bounds); tileJSON.center = parseCenter(jsonMetadata.center); tileJSON.maxZoom = safeParseFloat(jsonMetadata.maxzoom); tileJSON.minZoom = safeParseFloat(jsonMetadata.minzoom); if (typeof (jsonMetadata == null ? void 0 : jsonMetadata.json) === "string") { try { tileJSON.metaJson = JSON.parse(jsonMetadata.json); } catch (error) { console.warn("Failed to parse tilejson.json field", error); } } const tilestats = jsonMetadata.tilestats || ((_a = tileJSON.metaJson) == null ? void 0 : _a.tilestats); const tileStatsLayers = parseTilestatsLayers(tilestats, options); const tileJSONlayers = parseTileJSONLayers(jsonMetadata.vector_layers); const layers = mergeLayers(tileJSONlayers, tileStatsLayers); tileJSON = { ...tileJSON, layers }; if (tileJSON.maxZoom === null && layers.length > 0) { tileJSON.maxZoom = layers[0].maxZoom || null; } if (tileJSON.minZoom === null && layers.length > 0) { tileJSON.minZoom = layers[0].minZoom || null; } return tileJSON; } function parseTileJSONLayers(layers) { if (!Array.isArray(layers)) { return []; } return layers.map((layer) => parseTileJSONLayer(layer)); } function parseTileJSONLayer(layer) { const fields = Object.entries(layer.fields || []).map(([key, datatype]) => ({ name: key, ...attributeTypeToFieldType(String(datatype)) })); const layer2 = { ...layer }; delete layer2.fields; return { name: layer.id || "", ...layer2, fields }; } function parseTilestatsLayers(tilestats, options) { if (isObject(tilestats) && Array.isArray(tilestats.layers)) { return tilestats.layers.map((layer) => parseTilestatsForLayer(layer, options)); } return []; } function parseTilestatsForLayer(layer, options) { const fields = []; const indexedAttributes = {}; const attributes = layer.attributes || []; for (const attribute of attributes) { const name = attribute.attribute; if (typeof name === "string") { if (name.split("|").length > 1) { const fname = name.split("|")[0]; indexedAttributes[fname] = indexedAttributes[fname] || []; indexedAttributes[fname].push(attribute); console.warn("ignoring tilestats indexed field", fname); } else if (!fields[name]) { fields.push(attributeToField(attribute, options)); } else { } } } return { name: layer.layer || "", dominantGeometry: layer.geometry, fields }; } function mergeLayers(layers, tilestatsLayers) { return layers.map((layer) => { const tilestatsLayer = tilestatsLayers.find((tsLayer) => tsLayer.name === layer.name); const fields = (tilestatsLayer == null ? void 0 : tilestatsLayer.fields) || layer.fields || []; const mergedLayer = { ...layer, ...tilestatsLayer, fields }; mergedLayer.schema = getSchemaFromTileJSONLayer(mergedLayer); return mergedLayer; }); } function parseBounds(bounds) { const result = fromArrayOrString(bounds); if (Array.isArray(result) && result.length === 4 && [result[0], result[2]].every(isLng) && [result[1], result[3]].every(isLat)) { return [ [result[0], result[1]], [result[2], result[3]] ]; } return void 0; } function parseCenter(center) { const result = fromArrayOrString(center); if (Array.isArray(result) && result.length === 3 && isLng(result[0]) && isLat(result[1]) && isZoom(result[2])) { return result; } return null; } function safeParseFloat(input) { const result = typeof input === "string" ? parseFloat(input) : typeof input === "number" ? input : null; return result === null || isNaN(result) ? null : result; } function isLat(num) { return Number.isFinite(num) && num <= 90 && num >= -90; } function isLng(num) { return Number.isFinite(num) && num <= 180 && num >= -180; } function isZoom(num) { return Number.isFinite(num) && num >= 0 && num <= 22; } function fromArrayOrString(data) { if (typeof data === "string") { return data.split(",").map(parseFloat); } else if (Array.isArray(data)) { return data; } return null; } var attrTypeMap = { number: { type: "float32" }, numeric: { type: "float32" }, string: { type: "utf8" }, vachar: { type: "utf8" }, float: { type: "float32" }, int: { type: "int32" }, int4: { type: "int32" }, boolean: { type: "boolean" }, bool: { type: "boolean" } }; function attributeToField(attribute = {}, options) { var _a; const fieldTypes = attributeTypeToFieldType(attribute.type); const field = { name: attribute.attribute, // what happens if attribute type is string... // filterProps: getFilterProps(fieldTypes.type, attribute), ...fieldTypes }; if (typeof attribute.min === "number") { field.min = attribute.min; } if (typeof attribute.max === "number") { field.max = attribute.max; } if (typeof attribute.count === "number") { field.uniqueValueCount = attribute.count; } if (attribute.values) { field.values = attribute.values; } if (field.values && typeof options.maxValues === "number") { field.values = (_a = field.values) == null ? void 0 : _a.slice(0, options.maxValues); } return field; } function attributeTypeToFieldType(aType) { const type = aType.toLowerCase(); if (!type || !attrTypeMap[type]) { } return attrTypeMap[type] || { type: "string" }; } // dist/tilejson-loader.js var VERSION = true ? "4.4.2" : "latest"; var TileJSONLoader = { dataType: null, batchType: null, name: "TileJSON", id: "tilejson", module: "pmtiles", version: VERSION, worker: true, extensions: ["json"], mimeTypes: ["application/json"], text: true, options: { tilejson: { maxValues: void 0 } }, parse: async (arrayBuffer, options) => { const jsonString = new TextDecoder().decode(arrayBuffer); const json = JSON.parse(jsonString); const tilejsonOptions = { ...TileJSONLoader.options.tilejson, ...options == null ? void 0 : options.tilejson }; return parseTileJSON(json, tilejsonOptions); }, parseTextSync: (text, options) => { const json = JSON.parse(text); const tilejsonOptions = { ...TileJSONLoader.options.tilejson, ...options == null ? void 0 : options.tilejson }; return parseTileJSON(json, tilejsonOptions); } }; // dist/lib/parse-mvt.js var import_gis = require("@loaders.gl/gis"); var import_loader_utils = require("@loaders.gl/loader-utils"); var import_pbf = __toESM(require("pbf"), 1); // dist/lib/utils/geometry-utils.js var import_polygon = require("@math.gl/polygon"); function signedArea(ring) { let sum = 0; for (let i = 0, j = ring.length - 1, p1, p2; i < ring.length; j = i++) { p1 = ring[i]; p2 = ring[j]; sum += (p2[0] - p1[0]) * (p1[1] + p2[1]); } return sum; } function convertToLocalCoordinates(coordinates, extent) { if (Array.isArray(coordinates[0])) { for (const subcoords of coordinates) { convertToLocalCoordinates(subcoords, extent); } return; } const p = coordinates; p[0] /= extent; p[1] /= extent; } function convertToLocalCoordinatesFlat(data, extent) { for (let i = 0; i < data.length; ++i) { data[i] /= extent; } } function projectToLngLat(line, tileIndex, extent) { if (typeof line[0][0] !== "number") { for (const point of line) { projectToLngLat(point, tileIndex, extent); } return; } const size = extent * Math.pow(2, tileIndex.z); const x0 = extent * tileIndex.x; const y0 = extent * tileIndex.y; for (let j = 0; j < line.length; j++) { const p = line[j]; p[0] = (p[0] + x0) * 360 / size - 180; const y2 = 180 - (p[1] + y0) * 360 / size; p[1] = 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90; } } function projectToLngLatFlat(data, tileIndex, extent) { const { x, y, z } = tileIndex; const size = extent * Math.pow(2, z); const x0 = extent * x; const y0 = extent * y; for (let j = 0, jl = data.length; j < jl; j += 2) { data[j] = (data[j] + x0) * 360 / size - 180; const y2 = 180 - (data[j + 1] + y0) * 360 / size; data[j + 1] = 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90; } } function classifyRings(rings) { const len = rings.length; if (len <= 1) return [rings]; const polygons = []; let polygon; let ccw; for (let i = 0; i < len; i++) { const area = signedArea(rings[i]); if (area === 0) continue; if (ccw === void 0) ccw = area < 0; if (ccw === area < 0) { if (polygon) polygons.push(polygon); polygon = [rings[i]]; } else if (polygon) polygon.push(rings[i]); } if (polygon) polygons.push(polygon); return polygons; } function classifyRingsFlat(geom) { const len = geom.indices.length; const type = "Polygon"; if (len <= 1) { return { type, data: geom.data, areas: [[(0, import_polygon.getPolygonSignedArea)(geom.data)]], indices: [geom.indices] }; } const areas = []; const polygons = []; let ringAreas = []; let polygon = []; let ccw; let offset = 0; for (let endIndex, i = 0, startIndex; i < len; i++) { startIndex = geom.indices[i] - offset; endIndex = geom.indices[i + 1] - offset || geom.data.length; const shape = geom.data.slice(startIndex, endIndex); const area = (0, import_polygon.getPolygonSignedArea)(shape); if (area === 0) { const before = geom.data.slice(0, startIndex); const after = geom.data.slice(endIndex); geom.data = before.concat(after); offset += endIndex - startIndex; continue; } if (ccw === void 0) ccw = area < 0; if (ccw === area < 0) { if (polygon.length) { areas.push(ringAreas); polygons.push(polygon); } polygon = [startIndex]; ringAreas = [area]; } else { ringAreas.push(area); polygon.push(startIndex); } } if (ringAreas) areas.push(ringAreas); if (polygon.length) polygons.push(polygon); return { type, areas, indices: polygons, data: geom.data }; } // dist/lib/vector-tile/vector-tile-feature.js var VectorTileFeature = class { properties; extent; type; id; _pbf; _geometry; _keys; _values; _geometryInfo; // eslint-disable-next-line max-params constructor(pbf, end, extent, keys, values, geometryInfo) { this.properties = {}; this.extent = extent; this.type = 0; this.id = null; this._pbf = pbf; this._geometry = -1; this._keys = keys; this._values = values; this._geometryInfo = geometryInfo; pbf.readFields(readFeature, this, end); } toGeoJSONFeature(coordinates, tileIndex) { const coords = this.loadGeometry(); switch (coordinates) { case "wgs84": return _toGeoJSONFeature(this, coords, (line) => projectToLngLat(line, tileIndex, this.extent)); default: return _toGeoJSONFeature(this, coords, convertToLocalCoordinates); } } /** * * @param options * @returns */ toBinaryFeature(coordinates, tileIndex) { const geom = this.loadFlatGeometry(); switch (coordinates) { case "wgs84": return this._toBinaryCoordinates(geom, (coords) => projectToLngLatFlat(coords, tileIndex, this.extent)); default: return this._toBinaryCoordinates(geom, convertToLocalCoordinatesFlat); } } /** Read a bounding box from the feature */ // eslint-disable-next-line max-statements bbox() { const pbf = this._pbf; pbf.pos = this._geometry; const end = pbf.readVarint() + pbf.pos; let cmd = 1; let length = 0; let x = 0; let y = 0; let x1 = Infinity; let x2 = -Infinity; let y1 = Infinity; let y2 = -Infinity; while (pbf.pos < end) { if (length <= 0) { const cmdLen = pbf.readVarint(); cmd = cmdLen & 7; length = cmdLen >> 3; } length--; if (cmd === 1 || cmd === 2) { x += pbf.readSVarint(); y += pbf.readSVarint(); if (x < x1) x1 = x; if (x > x2) x2 = x; if (y < y1) y1 = y; if (y > y2) y2 = y; } else if (cmd !== 7) { throw new Error(`unknown command ${cmd}`); } } return [x1, y1, x2, y2]; } // BINARY HELPERS /** * * @param transform * @returns result */ _toBinaryCoordinates(geom, transform) { let geometry; transform(geom.data, this.extent); const coordLength = 2; switch (this.type) { case 1: this._geometryInfo.pointFeaturesCount++; this._geometryInfo.pointPositionsCount += geom.indices.length; geometry = { type: "Point", ...geom }; break; case 2: this._geometryInfo.lineFeaturesCount++; this._geometryInfo.linePathsCount += geom.indices.length; this._geometryInfo.linePositionsCount += geom.data.length / coordLength; geometry = { type: "LineString", ...geom }; break; case 3: geometry = classifyRingsFlat(geom); this._geometryInfo.polygonFeaturesCount++; this._geometryInfo.polygonObjectsCount += geometry.indices.length; for (const indices of geometry.indices) { this._geometryInfo.polygonRingsCount += indices.length; } this._geometryInfo.polygonPositionsCount += geometry.data.length / coordLength; break; default: throw new Error(`Invalid geometry type: ${this.type}`); } const result = { type: "Feature", geometry, properties: this.properties }; if (this.id !== null) { result.id = this.id; } return result; } // GEOJSON HELPER // eslint-disable-next-line complexity, max-statements loadGeometry() { const pbf = this._pbf; pbf.pos = this._geometry; const end = pbf.readVarint() + pbf.pos; let cmd = 1; let length = 0; let x = 0; let y = 0; const lines = []; let line; while (pbf.pos < end) { if (length <= 0) { const cmdLen = pbf.readVarint(); cmd = cmdLen & 7; length = cmdLen >> 3; } length--; switch (cmd) { case 1: case 2: x += pbf.readSVarint(); y += pbf.readSVarint(); if (cmd === 1) { if (line) lines.push(line); line = []; } if (line) line.push([x, y]); break; case 7: if (line) { line.push(line[0].slice()); } break; default: throw new Error(`unknown command ${cmd}`); } } if (line) lines.push(line); return lines; } /** * Expands the protobuf data to an intermediate Flat GeoJSON * data format, which maps closely to the binary data buffers. * It is similar to GeoJSON, but rather than storing the coordinates * in multidimensional arrays, we have a 1D `data` with all the * coordinates, and then index into this using the `indices` * parameter, e.g. * * geometry: { * type: 'Point', data: [1,2], indices: [0] * } * geometry: { * type: 'LineString', data: [1,2,3,4,...], indices: [0] * } * geometry: { * type: 'Polygon', data: [1,2,3,4,...], indices: [[0, 2]] * } * Thus the indices member lets us look up the relevant range * from the data array. * The Multi* versions of the above types share the same data * structure, just with multiple elements in the indices array */ // eslint-disable-next-line complexity, max-statements loadFlatGeometry() { const pbf = this._pbf; pbf.pos = this._geometry; const endPos = pbf.readVarint() + pbf.pos; let cmd = 1; let cmdLen; let length = 0; let x = 0; let y = 0; let i = 0; const indices = []; const data = []; while (pbf.pos < endPos) { if (length <= 0) { cmdLen = pbf.readVarint(); cmd = cmdLen & 7; length = cmdLen >> 3; } length--; if (cmd === 1 || cmd === 2) { x += pbf.readSVarint(); y += pbf.readSVarint(); if (cmd === 1) { indices.push(i); } data.push(x, y); i += 2; } else if (cmd === 7) { if (i > 0) { const start = indices[indices.length - 1]; data.push(data[start], data[start + 1]); i += 2; } } else { throw new Error(`unknown command ${cmd}`); } } return { data, indices }; } }; __publicField(VectorTileFeature, "types", ["Unknown", "Point", "LineString", "Polygon"]); function _toGeoJSONFeature(vtFeature, coords, transform) { let type = VectorTileFeature.types[vtFeature.type]; let i; let j; let coordinates; switch (vtFeature.type) { case 1: const points = []; for (i = 0; i < coords.length; i++) { points[i] = coords[i][0]; } coordinates = points; transform(coordinates, vtFeature.extent); break; case 2: coordinates = coords; for (i = 0; i < coordinates.length; i++) { transform(coordinates[i], vtFeature.extent); } break; case 3: coordinates = classifyRings(coords); for (i = 0; i < coordinates.length; i++) { for (j = 0; j < coordinates[i].length; j++) { transform(coordinates[i][j], vtFeature.extent); } } break; default: throw new Error("illegal vector tile type"); } if (coordinates.length === 1) { coordinates = coordinates[0]; } else { type = `Multi${type}`; } const result = { type: "Feature", geometry: { type, coordinates }, properties: vtFeature.properties }; if (vtFeature.id !== null) { result.properties ||= {}; result.properties.id = vtFeature.id; } return result; } function readFeature(tag, feature, pbf) { if (feature && pbf) { if (tag === 1) feature.id = pbf.readVarint(); else if (tag === 2) readTag(pbf, feature); else if (tag === 3) feature.type = pbf.readVarint(); else if (tag === 4) feature._geometry = pbf.pos; } } function readTag(pbf, feature) { const end = pbf.readVarint() + pbf.pos; while (pbf.pos < end) { const key = feature._keys[pbf.readVarint()]; const value = feature._values[pbf.readVarint()]; feature.properties[key] = value; } } // dist/lib/vector-tile/vector-tile-layer.js var VectorTileLayer = class { version; name; extent; length; _pbf; _keys; _values; _features; constructor(pbf, end) { this.version = 1; this.name = ""; this.extent = 4096; this.length = 0; this._pbf = pbf; this._keys = []; this._values = []; this._features = []; pbf.readFields(readLayer, this, end); this.length = this._features.length; } /** * return feature `i` from this layer as a `VectorTileFeature` * @param index * @returns feature */ getGeoJSONFeature(i) { if (i < 0 || i >= this._features.length) { throw new Error("feature index out of bounds"); } this._pbf.pos = this._features[i]; const end = this._pbf.readVarint() + this._pbf.pos; return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values); } /** * return binary feature `i` from this layer as a `VectorTileFeature` * * @param index * @param geometryInfo * @returns binary feature */ getBinaryFeature(i, geometryInfo) { if (i < 0 || i >= this._features.length) { throw new Error("feature index out of bounds"); } this._pbf.pos = this._features[i]; const end = this._pbf.readVarint() + this._pbf.pos; return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values, geometryInfo); } }; function readLayer(tag, layer, pbf) { if (layer && pbf) { if (tag === 15) layer.version = pbf.readVarint(); else if (tag === 1) layer.name = pbf.readString(); else if (tag === 5) layer.extent = pbf.readVarint(); else if (tag === 2) layer._features.push(pbf.pos); else if (tag === 3) layer._keys.push(pbf.readString()); else if (tag === 4) layer._values.push(readValueMessage(pbf)); } } function readValueMessage(pbf) { let value = null; const end = pbf.readVarint() + pbf.pos; while (pbf.pos < end) { const tag = pbf.readVarint() >> 3; value = tag === 1 ? pbf.readString() : tag === 2 ? pbf.readFloat() : tag === 3 ? pbf.readDouble() : tag === 4 ? pbf.readVarint64() : tag === 5 ? pbf.readVarint() : tag === 6 ? pbf.readSVarint() : tag === 7 ? pbf.readBoolean() : null; } return value; } // dist/lib/vector-tile/vector-tile.js var VectorTile = class { layers; constructor(pbf, end) { this.layers = pbf.readFields(readTile, {}, end); } }; function readTile(tag, layers, pbf) { if (tag === 3) { if (pbf) { const layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos); if (layer.length && layers) { layers[layer.name] = layer; } } } } // dist/lib/parse-mvt.js function parseMVT(arrayBuffer, options) { var _a, _b; const mvtOptions = checkOptions(options); const shape = ((_a = options == null ? void 0 : options.gis) == null ? void 0 : _a.format) || ((_b = options == null ? void 0 : options.mvt) == null ? void 0 : _b.shape) || (options == null ? void 0 : options.shape); switch (shape) { case "columnar-table": return { shape: "columnar-table", data: parseToBinary(arrayBuffer, mvtOptions) }; case "geojson-table": { const table = { shape: "geojson-table", type: "FeatureCollection", features: parseToGeojsonFeatures(arrayBuffer, mvtOptions) }; return table; } case "geojson": return parseToGeojsonFeatures(arrayBuffer, mvtOptions); case "binary-geometry": return parseToBinary(arrayBuffer, mvtOptions); case "binary": return parseToBinary(arrayBuffer, mvtOptions); default: throw new Error(shape || "undefined shape"); } } function parseToBinary(arrayBuffer, options) { const [flatGeoJsonFeatures, geometryInfo] = parseToFlatGeoJson(arrayBuffer, options); const binaryData = (0, import_gis.flatGeojsonToBinary)(flatGeoJsonFeatures, geometryInfo); binaryData.byteLength = arrayBuffer.byteLength; return binaryData; } function parseToFlatGeoJson(arrayBuffer, options) { const features2 = []; const geometryInfo = { coordLength: 2, pointPositionsCount: 0, pointFeaturesCount: 0, linePositionsCount: 0, linePathsCount: 0, lineFeaturesCount: 0, polygonPositionsCount: 0, polygonObjectsCount: 0, polygonRingsCount: 0, polygonFeaturesCount: 0 }; if (arrayBuffer.byteLength <= 0) { return [features2, geometryInfo]; } const tile = new VectorTile(new import_pbf.default(arrayBuffer)); const selectedLayers = options && Array.isArray(options.layers) ? options.layers : Object.keys(tile.layers); selectedLayers.forEach((layerName) => { const vectorTileLayer = tile.layers[layerName]; if (!vectorTileLayer) { return; } for (let i = 0; i < vectorTileLayer.length; i++) { const vectorTileFeature = vectorTileLayer.getBinaryFeature(i, geometryInfo); const decodedFeature = getDecodedFeatureBinary(vectorTileFeature, options, layerName); features2.push(decodedFeature); } }); return [features2, geometryInfo]; } function parseToGeojsonFeatures(arrayBuffer, options) { if (arrayBuffer.byteLength <= 0) { return []; } const features2 = []; const tile = new VectorTile(new import_pbf.default(arrayBuffer)); const selectedLayers = Array.isArray(options.layers) ? options.layers : Object.keys(tile.layers); selectedLayers.forEach((layerName) => { const vectorTileLayer = tile.layers[layerName]; if (!vectorTileLayer) { return; } for (let i = 0; i < vectorTileLayer.length; i++) { const vectorTileFeature = vectorTileLayer.getGeoJSONFeature(i); const decodedFeature = getDecodedFeature(vectorTileFeature, options, layerName); features2.push(decodedFeature); } }); return features2; } function checkOptions(options) { var _a; if (!(options == null ? void 0 : options.mvt)) { throw new Error("mvt options required"); } if (((_a = options.mvt) == null ? void 0 : _a.coordinates) === "wgs84" && !options.mvt.tileIndex) { throw new Error("MVT Loader: WGS84 coordinates need tileIndex property"); } if (options.gis) { import_loader_utils.log.warn('MVTLoader: "options.gis" is deprecated, use "options.mvt.shape" instead')(); } return options.mvt; } function getDecodedFeature(feature, options, layerName) { const decodedFeature = feature.toGeoJSONFeature(options.coordinates || "local", options.tileIndex); if (options.layerProperty) { decodedFeature.properties ||= {}; decodedFeature.properties[options.layerProperty] = layerName; } return decodedFeature; } function getDecodedFeatureBinary(feature, options, layerName) { const decodedFeature = feature.toBinaryFeature(options.coordinates || "local", options.tileIndex); if (options.layerProperty && decodedFeature.properties) { decodedFeature.properties[options.layerProperty] = layerName; } return decodedFeature; } // dist/mvt-format.js var MVTFormat = { name: "Mapbox Vector Tile", id: "mvt", module: "mvt", // Note: ArcGIS uses '.pbf' extension and 'application/octet-stream' extensions: ["mvt", "pbf"], mimeTypes: [ // https://www.iana.org/assignments/media-types/application/vnd.mapbox-vector-tile "application/vnd.mapbox-vector-tile", "application/x-protobuf" // 'application/octet-stream' ], category: "geometry" }; // dist/mvt-loader.js var VERSION2 = true ? "4.4.2" : "latest"; var MVTWorkerLoader = { ...MVTFormat, dataType: null, batchType: null, version: VERSION2, worker: true, options: { mvt: { shape: "geojson", coordinates: "local", layerProperty: "layerName", layers: void 0, tileIndex: void 0 } } }; var MVTLoader = { ...MVTWorkerLoader, parse: async (arrayBuffer, options) => parseMVT(arrayBuffer, options), parseSync: parseMVT, binary: true }; // dist/lib/mapbox-vt-pbf/to-vector-tile.js var import_pbf2 = __toESM(require("pbf"), 1); // dist/lib/mvt-pbf/mvt-constants.js var TileInfo; (function(TileInfo2) { TileInfo2[TileInfo2["layers"] = 3] = "layers"; })(TileInfo || (TileInfo = {})); var LayerInfo; (function(LayerInfo2) { LayerInfo2[LayerInfo2["version"] = 15] = "version"; LayerInfo2[LayerInfo2["name"] = 1] = "name"; LayerInfo2[LayerInfo2["features"] = 2] = "features"; LayerInfo2[LayerInfo2["keys"] = 3] = "keys"; LayerInfo2[LayerInfo2["values"] = 4] = "values"; LayerInfo2[LayerInfo2["extent"] = 5] = "extent"; })(LayerInfo || (LayerInfo = {})); var FeatureInfo; (function(FeatureInfo2) { FeatureInfo2[FeatureInfo2["id"] = 1] = "id"; FeatureInfo2[FeatureInfo2["tags"] = 2] = "tags"; FeatureInfo2[FeatureInfo2["type"] = 3] = "type"; FeatureInfo2[FeatureInfo2["geometry"] = 4] = "geometry"; })(FeatureInfo || (FeatureInfo = {})); var GeometryType; (function(GeometryType2) { GeometryType2[GeometryType2["UNKNOWN"] = 0] = "UNKNOWN"; GeometryType2[GeometryType2["POINT"] = 1] = "POINT"; GeometryType2[GeometryType2["LINESTRING"] = 2] = "LINESTRING"; GeometryType2[GeometryType2["POLYGON"] = 3] = "POLYGON"; })(GeometryType || (GeometryType = {})); var PropertyType; (function(PropertyType2) { PropertyType2[PropertyType2["string_value"] = 1] = "string_value"; PropertyType2[PropertyType2["float_value"] = 2] = "float_value"; PropertyType2[PropertyType2["double_value"] = 3] = "double_value"; PropertyType2[PropertyType2["int_value"] = 4] = "int_value"; PropertyType2[PropertyType2["uint_value"] = 5] = "uint_value"; PropertyType2[PropertyType2["sint_value"] = 6] = "sint_value"; PropertyType2[PropertyType2["bool_value"] = 7] = "bool_value"; })(PropertyType || (PropertyType = {})); var Command; (function(Command2) { Command2[Command2["MoveTo"] = 1] = "MoveTo"; Command2[Command2["LineTo"] = 2] = "LineTo"; Command2[Command2["ClosePath"] = 7] = "ClosePath"; })(Command || (Command = {})); // dist/lib/mvt-pbf/write-mvt-to-pbf.js function writeMVT(tile, pbf) { for (const key in tile.layers) { const context = { layer: tile.layers[key], keys: [], values: [], keycache: {}, valuecache: {} }; pbf.writeMessage(TileInfo.layers, writeLayer, context); } } function writeLayer(context, pbf) { const { layer } = context; pbf.writeVarintField(LayerInfo.version, layer.version || 1); pbf.writeStringField(LayerInfo.name, layer.name || ""); pbf.writeVarintField(LayerInfo.extent, layer.extent || 4096); for (let i = 0; i < layer.length; i++) { context.feature = layer.feature(i); pbf.writeMessage(LayerInfo.features, writeFeature, context); } const keys = context.keys; for (let i = 0; i < keys.length; i++) { pbf.writeStringField(LayerInfo.keys, keys[i]); } const values = context.values; for (let i = 0; i < values.length; i++) { pbf.writeMessage(LayerInfo.values, writeValue, values[i]); } } function writeFeature(context, pbf) { const feature = context.feature; if (feature.id !== void 0) { pbf.writeVarintField(FeatureInfo.id, feature.id); } pbf.writeMessage(FeatureInfo.tags, writeProperties, context); pbf.writeVarintField(FeatureInfo.type, feature.type); pbf.writeMessage(FeatureInfo.geometry, writeGeometry, feature); } function writeProperties(context, pbf) { const feature = context.feature; const { keys, values, keycache, valuecache } = context; for (const key in feature.properties) { let keyIndex = keycache[key]; if (typeof keyIndex === "undefined") { keys.push(key); keyIndex = keys.length - 1; keycache[key] = keyIndex; } pbf.writeVarint(keyIndex); let value = feature.properties[key]; const type = typeof value; if (type !== "string" && type !== "boolean" && type !== "number") { value = JSON.stringify(value); } const valueKey = `${type}:${value}`; let valueIndex = valuecache[valueKey]; if (typeof valueIndex === "undefined") { values.push(value); valueIndex = values.length - 1; valuecache[valueKey] = valueIndex; } pbf.writeVarint(valueIndex); } } function command(cmd, length) { return (length << 3) + (cmd & 7); } function zigzag(num) { return num << 1 ^ num >> 31; } function writeGeometry(feature, pbf) { const geometry = feature.loadGeometry(); const type = feature.type; let x = 0; let y = 0; const rings = geometry.length; for (let r = 0; r < rings; r++) { const ring = geometry[r]; let count = 1; if (type === 1) { count = ring.length; } pbf.writeVarint(command(1, count)); const lineCount = type === 3 ? ring.length - 1 : ring.length; for (let i = 0; i < lineCount; i++) { if (i === 1 && type !== 1) { pbf.writeVarint(command(2, lineCount - 1)); } const dx = ring[i].x - x; const dy = ring[i].y - y; pbf.writeVarint(zigzag(dx)); pbf.writeVarint(zigzag(dy)); x += dx; y += dy; } if (type === 3) { pbf.writeVarint(command(7, 1)); } } } function writeValue(value, pbf) { switch (typeof value) { case "string": pbf.writeStringField(1, value); break; case "boolean": pbf.writeBooleanField(7, value); break; case "number": if (value % 1 !== 0) { pbf.writeDoubleField(3, value); } else if (value < 0) { pbf.writeSVarintField(6, value); } else { pbf.writeVarintField(5, value); } break; default: } } // dist/lib/mapbox-vt-pbf/geojson-wrapper.js var Point = class { x; y; constructor(x, y) { this.x = x; this.y = y; } }; var GeoJSONWrapper = class { options; features; length; constructor(features2, options = {}) { this.options = options; this.features = features2; this.length = features2.length; } feature(index) { return new FeatureWrapper(this.features[index], this.options.extent); } }; var FeatureWrapper = class { id; type; rawGeometry; properties; extent; geometry = []; constructor(feature, extent) { this.id = typeof feature.id === "number" ? feature.id : void 0; this.type = feature.type; this.rawGeometry = feature.type === 1 ? [feature.geometry] : feature.geometry; this.properties = feature.tags; this.extent = extent || 4096; } loadGeometry() { const rings = this.rawGeometry; this.geometry = []; for (const ring of rings) { const newRing = []; for (const coord of ring) { newRing.push(new Point(coord[0], coord[1])); } this.geometry.push(newRing); } return this.geometry; } bbox() { if (!this.geometry) { this.loadGeometry(); } const rings = this.geometry; let x1 = Infinity; let x2 = -Infinity; let y1 = Infinity; let y2 = -Infinity; for (const ring of rings) { for (const coord of ring) { x1 = Math.min(x1, coord.x); x2 = Math.max(x2, coord.x); y1 = Math.min(y1, coord.y); y2 = Math.max(y2, coord.y); } } return [x1, y1, x2, y2]; } }; // dist/lib/mapbox-vt-pbf/to-vector-tile.js var import_loader_utils2 = require("@loaders.gl/loader-utils"); function fromGeojson(geojson, options) { options = options || {}; geojson = normalizeGeojson(geojson); const extent = options.extent || 4096; const features2 = convertFeaturesToVectorTileFeatures(geojson.features, extent, options.tileIndex); const layer = new GeoJSONWrapper(features2, { ...options, extent }); layer.name = options.layerName || "geojsonLayer"; layer.version = options.version || 1; layer.extent = options.extent || 4096; return fromVectorTileJs({ layers: { [layer.name]: layer } }); } function fromVectorTileJs(tile) { const pbf = new import_pbf2.default(); writeMVT(tile, pbf); const uint8Array = pbf.finish(); return (0, import_loader_utils2.copyToArrayBuffer)(uint8Array.buffer, uint8Array.byteOffset, uint8Array.byteOffset + uint8Array.byteLength); } function normalizeGeojson(geojson) { if (Array.isArray(geojson)) { return { type: "FeatureCollection", features: geojson }; } if (geojson.type === "Feature") { return { type: "FeatureCollection", features: [geojson] }; } throw new Error("Invalid GeoJSON object"); } function convertFeaturesToVectorTileFeatures(features2, extent, tileIndex) { if (features2.every(isVectorTileFeature)) { return features2; } return features2.map((feature) => convertFeatureToVectorTile(feature, extent, tileIndex)); } function convertFeatureToVectorTile(feature, extent, tileIndex) { const geometry = feature.geometry; const type = getVectorTileType(geometry.type); return { id: typeof feature.id === "number" ? feature.id : void 0, type, geometry: projectGeometryToTileSpace(geometry, extent, tileIndex), tags: feature.properties || {} }; } function projectGeometryToTileSpace(geometry, extent, tileIndex) { switch (geometry.type) { case "Point": return [projectPointToTile(geometry.coordinates, extent, tileIndex)]; case "MultiPoint": return geometry.coordinates.map((coord) => projectPointToTile(coord, extent, tileIndex)); case "LineString": return [ geometry.coordinates.map((coord) => projectPointToTile(coord, extent, tileIndex)) ]; case "MultiLineString": return geometry.coordinates.map((line) => line.map((coord) => projectPointToTile(coord, extent, tileIndex))); case "Polygon": return geometry.coordinates.map((ring) => ring.map((coord) => projectPointToTile(coord, extent, tileIndex))); case "MultiPolygon": return geometry.coordinates.flatMap((polygon) => polygon.map((ring) => ring.map((coord) => projectPointToTile(coord, extent, tileIndex)))); default: throw new Error(`Unsupported geometry type: ${geometry.type}`); } } function projectPointToTile(point, extent, tileIndex) { if (isNormalizedPoint(point)) { return [Math.round(point[0] * extent), Math.round(point[1] * extent)]; } if (tileIndex && isLngLatPoint(point)) { return projectLngLatToTile(point, tileIndex, extent); } return [Math.round(point[0]), Math.round(point[1])]; } function isNormalizedPoint(point) { return Math.abs(point[0]) <= 1 && Math.abs(point[1]) <= 1; } function isLngLatPoint(point) { return Math.abs(point[0]) <= 180 && Math.abs(point[1]) <= 90; } function projectLngLatToTile(point, tileIndex, extent) { const [lng, lat] = point; const { x, y, z } = tileIndex; const size = extent * Math.pow(2, z); const x0 = extent * x; const y0 = extent * y; const worldX = (lng + 180) / 360 * size; const worldY = (180 - 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 180 / 2))) * size / 360; return [Math.round(worldX - x0), Math.round(worldY - y0)]; } function isVectorTileFeature(feature) { return typeof (feature == null ? void 0 : feature.type) === "number" && Array.isArray(feature.geometry); } function getVectorTileType(type) { switch (type) { case "Point": case "MultiPoint": return 1; case "LineString": case "MultiLineString": return 2; case "Polygon": case "MultiPolygon": return 3; default: throw new Error(`Unknown geometry type: ${type}`); } } // dist/lib/encode-mvt.js function encodeMVT(data, options) { const { mvt } = options || {}; const encodeOptions = { layerName: (mvt == null ? void 0 : mvt.layerName) || "geojsonLayer", version: (mvt == null ? void 0 : mvt.version) || 1, extent: (mvt == null ? void 0 : mvt.extent) || 4096, tileIndex: mvt == null ? void 0 : mvt.tileIndex }; return fromGeojson(data, encodeOptions); } // dist/mvt-writer.js var VERSION3 = true ? "4.4.2" : "latest"; var MVTWriter = { ...MVTFormat, version: VERSION3, binary: true, options: { mvt: { layerName: "geojsonLayer", version: 1, extent: 4096 } }, async encode(data, options) { return encodeMVT(data, options); }, encodeSync(data, options) { return encodeMVT(data, options); } }; // dist/mvt-source.js var import_loader_utils3 = require("@loaders.gl/loader-utils"); var import_images = require("@loaders.gl/images"); var import_mvt = require("@loaders.gl/mvt"); var MVTSource = { ...MVTFormat, version: "0.0.0", type: "mvt", fromUrl: true, fromBlob: false, defaultOptions: { mvt: { // TODO - add options here } }, testURL: (url) => true, createDataSource(url, options) { return new MVTTileSource(url, options); } }; var MVTTileSource = class extends import_loader_utils3.DataSource { metadataUrl = null; schema = "tms"; metadata; extension; mimeType = null; constructor(url, options) { var _a, _b; super(url, options, MVTSource.defaultOptions); this.metadataUrl = ((_a = options.mvt) == null ? void 0 : _a.metadataUrl) || `${this.url}/tilejson.json`; this.extension = ((_b = options.mvt) == null ? void 0 : _b.extension) || ".png"; this.getTileData = this.getTileData.bind(this); this.metadata = this.getMetadata(); if (isURLTemplate(this.url)) { this.schema = "template"; } } // @ts-ignore - Metadata type misalignment async getMetadata() { var _a, _b; if (!this.metadataUrl) { return null; } let response; try { response = await this.fetch(this.metadataUrl); } catch (error) { console.error(error.message); return null; } if (!response.ok) { console.error(response.statusText); return null; } const tileJSON = await response.text(); const metadata = ((_b = (_a = import_mvt.TileJSONLoader).parseTextSync) == null ? void 0 : _b.call(_a, tileJSON)) || null; return metadata; } getTileMIMEType() { return this.mimeType; } async getTile(parameters) { const { x, y, z } = parameters; const tileUrl = this.getTileURL(x, y, z); const response = await this.fetch(tileUrl); if (!response.ok) { return null; } const arrayBuffer = await response.arrayBuffer(); return arrayBuffer; } // Tile Source interface implementation: deck.gl compatible API // TODO - currently only handles image tiles, not vector tiles async getTileData(parameters) { const { x, y, z } = parameters.index; const arrayBuffer = await this.getTile({ x, y, z, layers: [] }); if (arrayBuffer === null) { return null; } const imageMetadata = (0, import_images.getBinaryImageMetadata)(arrayBuffer); this.mimeType = this.mimeType || (imageMetadata == null ? void 0 : imageMetadata.mimeType) || "application/vnd.mapbox-vector-tile"; switch (this.mimeType) { case "application/vnd.mapbox-vector-tile": return await this._parseVectorTile(arrayBuffer, { x, y, z, layers: [] }); default: return await this._parseImageTile(arrayBuffer); } } // ImageTileSource interface implementation async getImageTile(tileParams) { const arrayBuffer = await this.getTile(tileParams); return arrayBuffer ? this._parseImageTile(arrayBuffer) : null; } async _parseImageTile(arrayBuffer) { return await import_images.ImageLoader.parse(arrayBuffer, this.loadOptions); } // VectorTileSource interface implementation async getVectorTile(tileParams) { const arrayBuffer = await this.getTile(tileParams); return arrayBuffer ? this._parseVectorTile(arrayBuffer, tileParams) : null; } async _parseVectorTile(arrayBuffer, tileParams) { var _a; const loadOptions = { mvt: { shape: "geojson-table", coordinates: "wgs84", tileIndex: { x: tileParams.x, y: tileParams.y, z: tileParams.z }, ...(_a = this.loadOptions) == null ? void 0 : _a.mvt }, ...this.loadOptions }; return await import_mvt.MVTLoader.parse(arrayBuffer, loadOptions); } getMetadataUrl() { return this.metadataUrl; } getTileURL(x, y, z) { switch (this.schema) { case "xyz": return `${this.url}/${x}/${y}/${z}${this.extension}`; case "tms": return `${this.url}/${z}/${x}/${y}${this.extension}`; case "template": return getURLFromTemplate(this.url, x, y, z, "0"); default: throw new Error(this.schema); } } }; function isURLTemplate(s) { return /(?=.*{z})(?=.*{x})(?=.*({y}|{-y}))|(?=.*{x})(?=.*({y}|{-y})(?=.*{z}))/.test(s); } var xRegex = new RegExp("{x}", "g"); var yRegex = new RegExp("{y}", "g"); var zRegex = new RegExp("{z}", "g"); function getURLFromTemplate(template, x, y, z, id = "0") { if (Array.isArray(template)) { const i = stringHash(id) % template.length; template = template[i]; } let url = template; url = url.replace(xRegex, String(x)); url = url.replace(yRegex, String(y)); url = url.replace(zRegex, String(z)); if (Number.isInteger(y) && Number.isInteger(z)) { url = url.replace(/\{-y\}/g, String(Math.pow(2, z) - y - 1)); } return url; } function stringHash(s) { return Math.abs(s.split("").reduce((a, b) => (a << 5) - a + b.charCodeAt(0) | 0, 0)); } // dist/table-tile-source.js var import_loader_utils4 = require("@loaders.gl/loader-utils"); var import_schema_utils = require("@loaders.gl/schema-utils"); var import_stats = require("@probe.gl/stats"); // dist/lib/vector-tiler/proto-tile.js function createProtoTile(features2, z, tx, ty, options) { const tolerance = z === options.maxZoom ? 0 : options.tolerance / ((1 << z) * options.extent); const tile = { protoFeatures: [], sourceFeatures: null, numPoints: 0, numSimplified: 0, numFeatures: features2.length, x: tx, y: ty, z, transformed: false, minX: 2, minY: 1, maxX: -1, maxY: 0 }; for (const feature of features2) { addProtoFeature(tile, feature, tolerance, options); } return tile; } function addProtoFeature(tile, feature, tolerance, options) { const geometry = feature.geometry; const type = feature.type; const simplifiedGeometry = []; tile.minX = Math.min(tile.minX, feature.minX); tile.minY = Math.min(tile.minY, feature.minY); tile.maxX = Math.max(tile.maxX, feature.maxX); tile.maxY = Math.max(tile.maxY, feature.maxY); let simplifiedType; switch (type) { case "Point": case "MultiPoint": simplifiedType = 1; for (let i = 0; i < geometry.length; i += 3) { simplifiedGeometry.push(geometry[i], geometry[i + 1]); tile.numPoints++; tile.numSimplified++; } break; case "LineString": simplifiedType = 2; addProtoLine(simplifiedGeometry, geometry, tile, tolerance, false, false); break; case "MultiLineString": simplifiedType = 2; for (let i = 0; i < geometry.length; i++) { addProtoLine(simplifiedGeometry, geometry[i], tile, tolerance, false, i === 0); } break; case "Polygon": simplifiedType = 3; for (let i = 0; i < geometry.length; i++) { addProtoLine(simplifiedGeometry, geometry[i], tile, tolerance, true, i === 0); } break; case "MultiPolygon": simplifiedType = 3; for (let k = 0; k < geometry.length; k++) { const polygon = geometry[k]; for (let i = 0; i < polygon.length; i++) { addProtoLine(simplifiedGeometry, polygon[i], tile, tolerance, true, i === 0); } } break; default: throw new Error(`Unknown geometry type: ${type}`); } if (simplifiedGeometry.length) { let tags = feature.tags || null; if (type === "LineString" && options.lineMetrics) { tags = {}; for (const key in feature.tags) { tags[key] = feature.tags[key]; } tags.mapbox_clip_start = geometry.start / geometry.size; tags.mapbox_clip