UNPKG

@loaders.gl/mvt

Version:

Loader for Mapbox Vector Tiles

4 lines 175 kB
{ "version": 3, "sources": ["../src/index.ts", "../src/lib/get-schemas-from-tilejson.ts", "../src/lib/parse-tilejson.ts", "../src/tilejson-loader.ts", "../src/lib/parse-mvt.ts", "../src/lib/utils/geometry-utils.ts", "../src/lib/vector-tile/vector-tile-feature.ts", "../src/lib/vector-tile/vector-tile-layer.ts", "../src/lib/vector-tile/vector-tile.ts", "../src/mvt-format.ts", "../src/mvt-loader.ts", "../src/lib/mapbox-vt-pbf/to-vector-tile.ts", "../src/lib/mvt-pbf/mvt-constants.ts", "../src/lib/mvt-pbf/write-mvt-to-pbf.ts", "../src/lib/mapbox-vt-pbf/geojson-wrapper.ts", "../src/lib/encode-mvt.ts", "../src/mvt-writer.ts", "../src/mvt-source.ts", "../src/table-tile-source.ts", "../src/lib/vector-tiler/proto-tile.ts", "../src/lib/vector-tiler/transform-tile.ts", "../src/lib/vector-tiler/tile-to-geojson.ts", "../src/lib/vector-tiler/features/proto-feature.ts", "../src/lib/vector-tiler/features/simplify-path.ts", "../src/lib/vector-tiler/features/convert-feature.ts", "../src/lib/vector-tiler/features/clip-features.ts", "../src/lib/vector-tiler/features/wrap-features.ts"], "sourcesContent": ["// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\n// TileJSONLoader\n\nexport {TileJSONLoader} from './tilejson-loader';\nexport type {TileJSONLoaderOptions} from './tilejson-loader';\nexport type {TileJSON} from './lib/parse-tilejson';\n\n// MVTLoader\n\nexport {MVTLoader, MVTWorkerLoader} from './mvt-loader';\nexport type {MVTLoaderOptions} from './mvt-loader';\n\n// MVTWriter\n\nexport {MVTWriter} from './mvt-writer';\nexport type {MVTWriterOptions} from './lib/encode-mvt';\n\n// MVTSource\n\nexport {MVTSource} from './mvt-source';\nexport type {MVTTileSource, MVTSourceOptions} from './mvt-source';\n\n// TableTileSource (dynamically tiles a table)\n\nexport type {TableTileSourceOptions, TableVectorTileSource} from './table-tile-source';\nexport {TableTileSource} from './table-tile-source';\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport type {Schema, Field, DataType, SchemaMetadata, FieldMetadata} from '@loaders.gl/schema';\nimport type {TileJSONLayer, TileJSONField} from './parse-tilejson';\n\n// LAYERS\n\nexport function getSchemaFromTileJSONLayer(layer: TileJSONLayer): Schema {\n const fields: Field[] = [];\n if (layer.fields) {\n for (const field of layer.fields) {\n fields.push({\n name: field.name,\n type: getDataTypeFromTileJSONField(field),\n metadata: getMetadataFromTileJSONField(field)\n });\n }\n }\n return {\n metadata: getMetadataFromTileJSONLayer(layer),\n fields\n };\n}\n\nfunction getMetadataFromTileJSONLayer(layer: TileJSONLayer): SchemaMetadata {\n const metadata: Record<string, string> = {};\n for (const [key, value] of Object.entries(layer)) {\n if (key !== 'fields' && value) {\n metadata[key] = JSON.stringify(value);\n }\n }\n return metadata;\n}\n\n// FIELDS\n\nfunction getDataTypeFromTileJSONField(field: TileJSONField): DataType {\n switch (field.type.toLowerCase()) {\n case 'float32':\n return 'float32';\n case 'number':\n case 'float64':\n return 'float64';\n case 'string':\n case 'utf8':\n return 'utf8';\n case 'boolean':\n return 'bool';\n default:\n return 'null';\n }\n}\n\nfunction getMetadataFromTileJSONField(field: TileJSONField): FieldMetadata {\n const metadata: Record<string, string> = {};\n for (const [key, value] of Object.entries(field)) {\n if (key !== 'name' && value) {\n metadata[key] = JSON.stringify(value);\n }\n }\n return metadata;\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport {Schema} from '@loaders.gl/schema';\nimport {getSchemaFromTileJSONLayer} from './get-schemas-from-tilejson';\n\nexport type TileJSONOptions = {\n /** max number of values. If not provided, include all values in the source tilestats */\n maxValues?: number;\n};\n\n/** Parsed and typed TileJSON, merges Tilestats information if present */\nexport type TileJSON = {\n /** Name of the tileset (for presentation in UI) */\n name?: string;\n /** A description of the contents or purpose of the tileset */\n description?: string;\n /** The version of the tileset */\n version?: string;\n\n tileFormat?: string;\n tilesetType?: string;\n\n /** Generating application. Tippecanoe adds this. */\n generator?: string;\n /** Generating application options. Tippecanoe adds this. */\n generatorOptions?: string;\n\n /** Tile indexing scheme */\n scheme?: 'xyz' | 'tms';\n /** Sharded URLs */\n tiles?: string[];\n /** `[[w, s], [e, n]]`, indicates the limits of the bounding box using the axis units and order of the specified CRS. */\n boundingBox?: [min: [w: number, s: number], max: [e: number, n: number]];\n /** May be set to the maxZoom of the first layer */\n maxZoom?: number | null;\n /** May be set to the minZoom of the first layer */\n minZoom?: number | null;\n center?: number[] | null;\n htmlAttribution?: string;\n htmlLegend?: string;\n\n // Combination of tilestats (if present) and tilejson layer information\n layers?: TileJSONLayer[];\n\n /** Any nested JSON metadata */\n metaJson?: any | null;\n};\n\nexport type TileJSONLayer = {\n /** The name (id) of this layer (tilejson.vector_layers[].id / tilestats.layers[].layer) */\n name: string;\n\n /** The description of this layer (tilejson.layer.description) */\n description?: string;\n\n // tilestats\n\n /** The number of features in this layer (tilestats.layer.count) */\n featureCount?: number;\n /** The dominant geometry type in this layer (tilestats.layer.geometry) */\n dominantGeometry?: string;\n /** An array of details about the first 100 attributes in this layer */\n\n /** */\n minZoom?: number;\n maxZoom?: number;\n fields: TileJSONField[];\n\n schema?: Schema;\n};\n\nexport type TileJSONField = {\n /** The name of this attribute */\n name: string;\n description?: string;\n\n // tilestats\n\n type: string;\n /** min value (if there are *any* numbers in the values) */\n min?: number;\n /** max value (if there are *any* numbers in the values) */\n max?: number;\n /** Number of unique values across the tileset */\n uniqueValueCount?: number;\n /** An array of this attribute's first 100 unique values */\n values?: unknown[];\n};\n\n/**\n * The raw/unparsed tilestats layer type\n * @see https://github.com/mapbox/mapbox-geostats#output-the-stats\n */\ntype TilestatsLayer = {\n /** The name of this layer */\n layer: string;\n /** The number of features in this layer */\n count: number;\n /** The dominant geometry type in this layer */\n geometry: string;\n /** The number of unique attributes in this layer (max. 1000) */\n attributeCount: number;\n /** Fields for this layer */\n attributes?: TilestatsLayerAttribute[];\n};\n\n/**\n * The raw/unparsed tilestats attribute type\n * @see https://github.com/mapbox/mapbox-geostats#output-the-stats\n */\ntype TilestatsLayerAttribute = {\n /** The name of this layer */\n attribute?: string;\n /** Each attribute has one of the following types:\n * - 'string' if all its values are strings (or null).\n * - 'number' if all its values are numbers (or null).\n * - 'boolean' if all its values are booleans (or null).\n * - 'null' if its only value is null.\n * - 'mixed' if it has values of multiple types.\n * - Array and object values are coerced to strings.\n */\n type?: string;\n /** min value (if there are *any* numbers in the values) */\n min?: number;\n /** max value (if there are *any* numbers in the values) */\n max?: number;\n /** Number of unique values */\n count?: number;\n /** First 100 values */\n values?: unknown[];\n};\n\nconst isObject: (x: unknown) => boolean = (x) => x !== null && typeof x === 'object';\n\n/**\n * Parse TileJSON from metadata\n * @param jsonMetadata - metadata object\n * @param options - options\n * @returns - parsed TileJSON\n */\n// eslint-disable-next-line complexity\nexport function parseTileJSON(jsonMetadata: any, options: TileJSONOptions): TileJSON | null {\n if (!jsonMetadata || !isObject(jsonMetadata)) {\n return null;\n }\n\n let tileJSON: TileJSON = {\n name: jsonMetadata.name || '',\n description: jsonMetadata.description || ''\n };\n\n // tippecanoe\n\n if (typeof jsonMetadata.generator === 'string') {\n tileJSON.generator = jsonMetadata.generator;\n }\n if (typeof jsonMetadata.generator_options === 'string') {\n tileJSON.generatorOptions = jsonMetadata.generator_options;\n }\n\n // Tippecanoe emits `antimeridian_adjusted_bounds` instead of `bounds`\n tileJSON.boundingBox =\n parseBounds(jsonMetadata.bounds) || parseBounds(jsonMetadata.antimeridian_adjusted_bounds);\n\n // TODO - can be undefined - we could set to center of bounds...\n tileJSON.center = parseCenter(jsonMetadata.center);\n // TODO - can be undefined, we could extract from layers...\n tileJSON.maxZoom = safeParseFloat(jsonMetadata.maxzoom);\n // TODO - can be undefined, we could extract from layers...\n tileJSON.minZoom = safeParseFloat(jsonMetadata.minzoom);\n\n // Look for nested metadata embedded in .json field\n // TODO - document what source this applies to, when is this needed?\n if (typeof jsonMetadata?.json === 'string') {\n // try to parse json\n try {\n tileJSON.metaJson = JSON.parse(jsonMetadata.json);\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn('Failed to parse tilejson.json field', error);\n // do nothing\n }\n }\n\n // Look for fields in tilestats\n\n const tilestats = jsonMetadata.tilestats || tileJSON.metaJson?.tilestats;\n const tileStatsLayers = parseTilestatsLayers(tilestats, options);\n const tileJSONlayers = parseTileJSONLayers(jsonMetadata.vector_layers); // eslint-disable-line camelcase\n // TODO - merge in description from tilejson\n const layers = mergeLayers(tileJSONlayers, tileStatsLayers);\n\n tileJSON = {\n ...tileJSON,\n layers\n };\n\n if (tileJSON.maxZoom === null && layers.length > 0) {\n tileJSON.maxZoom = layers[0].maxZoom || null;\n }\n\n if (tileJSON.minZoom === null && layers.length > 0) {\n tileJSON.minZoom = layers[0].minZoom || null;\n }\n\n return tileJSON;\n}\n\nfunction parseTileJSONLayers(layers: any[]): TileJSONLayer[] {\n // Look for fields in vector_layers\n if (!Array.isArray(layers)) {\n return [];\n }\n return layers.map((layer) => parseTileJSONLayer(layer));\n}\n\nfunction parseTileJSONLayer(layer: any): TileJSONLayer {\n const fields = Object.entries(layer.fields || []).map(([key, datatype]) => ({\n name: key,\n ...attributeTypeToFieldType(String(datatype))\n }));\n const layer2 = {...layer};\n delete layer2.fields;\n return {\n name: layer.id || '',\n ...layer2,\n fields\n };\n}\n\n/** parse Layers array from tilestats */\nfunction parseTilestatsLayers(tilestats: any, options: TileJSONOptions): TileJSONLayer[] {\n if (isObject(tilestats) && Array.isArray(tilestats.layers)) {\n // we are in luck!\n return tilestats.layers.map((layer) => parseTilestatsForLayer(layer, options));\n }\n return [];\n}\n\nfunction parseTilestatsForLayer(layer: TilestatsLayer, options: TileJSONOptions): TileJSONLayer {\n const fields: TileJSONField[] = [];\n const indexedAttributes: {[key: string]: TilestatsLayerAttribute[]} = {};\n\n const attributes = layer.attributes || [];\n for (const attribute of attributes) {\n const name = attribute.attribute;\n if (typeof name === 'string') {\n // TODO - code copied from kepler.gl, need sample tilestats files to test\n if (name.split('|').length > 1) {\n // indexed field\n const fname = name.split('|')[0];\n indexedAttributes[fname] = indexedAttributes[fname] || [];\n indexedAttributes[fname].push(attribute);\n // eslint-disable-next-line no-console\n console.warn('ignoring tilestats indexed field', fname);\n } else if (!fields[name]) {\n fields.push(attributeToField(attribute, options));\n } else {\n // return (fields[name], attribute);\n }\n }\n }\n return {\n name: layer.layer || '',\n dominantGeometry: layer.geometry,\n fields\n };\n}\n\nfunction mergeLayers(layers: TileJSONLayer[], tilestatsLayers: TileJSONLayer[]): TileJSONLayer[] {\n return layers.map((layer: TileJSONLayer): TileJSONLayer => {\n const tilestatsLayer = tilestatsLayers.find((tsLayer) => tsLayer.name === layer.name);\n const fields = tilestatsLayer?.fields || layer.fields || [];\n const mergedLayer = {\n ...layer,\n ...tilestatsLayer,\n fields\n } as TileJSONLayer;\n mergedLayer.schema = getSchemaFromTileJSONLayer(mergedLayer);\n return mergedLayer;\n });\n}\n\n/**\n * bounds should be [minLng, minLat, maxLng, maxLat]\n *`[[w, s], [e, n]]`, indicates the limits of the bounding box using the axis units and order of the specified CRS.\n */\nfunction parseBounds(\n bounds: string | number[]\n): [[east: number, south: number], [west: number, north: number]] | undefined {\n // supported formats\n // string: \"-96.657715,40.126127,-90.140061,43.516689\",\n // array: [ -180, -85.05112877980659, 180, 85.0511287798066 ]\n const result = fromArrayOrString(bounds);\n // validate bounds\n if (\n Array.isArray(result) &&\n result.length === 4 &&\n [result[0], result[2]].every(isLng) &&\n [result[1], result[3]].every(isLat)\n ) {\n return [\n [result[0], result[1]],\n [result[2], result[3]]\n ];\n }\n return undefined;\n}\n\nfunction parseCenter(center: string | number[]): number[] | null {\n // supported formats\n // string: \"-96.657715,40.126127,-90.140061,43.516689\",\n // array: [-91.505127,41.615442,14]\n const result = fromArrayOrString(center);\n if (\n Array.isArray(result) &&\n result.length === 3 &&\n isLng(result[0]) &&\n isLat(result[1]) &&\n isZoom(result[2])\n ) {\n return result;\n }\n return null;\n}\n\nfunction safeParseFloat(input: unknown): number | null {\n const result =\n typeof input === 'string' ? parseFloat(input) : typeof input === 'number' ? input : null;\n return result === null || isNaN(result) ? null : result;\n}\n\n// https://github.com/mapbox/tilejson-spec/tree/master/2.2.0\nfunction isLat(num: any): boolean {\n return Number.isFinite(num) && num <= 90 && num >= -90;\n}\nfunction isLng(num: any): boolean {\n return Number.isFinite(num) && num <= 180 && num >= -180;\n}\nfunction isZoom(num: any): boolean {\n return Number.isFinite(num) && num >= 0 && num <= 22;\n}\nfunction fromArrayOrString(data: string | number[]): number[] | null {\n if (typeof data === 'string') {\n return data.split(',').map(parseFloat);\n } else if (Array.isArray(data)) {\n return data;\n }\n return null;\n}\n\n// possible types https://github.com/mapbox/tippecanoe#modifying-feature-attributes\nconst attrTypeMap = {\n number: {\n type: 'float32'\n },\n numeric: {\n type: 'float32'\n },\n string: {\n type: 'utf8'\n },\n vachar: {\n type: 'utf8'\n },\n float: {\n type: 'float32'\n },\n int: {\n type: 'int32'\n },\n int4: {\n type: 'int32'\n },\n boolean: {\n type: 'boolean'\n },\n bool: {\n type: 'boolean'\n }\n};\n\nfunction attributeToField(\n attribute: TilestatsLayerAttribute = {},\n options: TileJSONOptions\n): TileJSONField {\n const fieldTypes = attributeTypeToFieldType(attribute.type!);\n const field: TileJSONField = {\n name: attribute.attribute as string,\n // what happens if attribute type is string...\n // filterProps: getFilterProps(fieldTypes.type, attribute),\n ...fieldTypes\n };\n\n // attribute: \"_season_peaks_color\"\n // count: 1000\n // max: 0.95\n // min: 0.24375\n // type: \"number\"\n\n if (typeof attribute.min === 'number') {\n field.min = attribute.min;\n }\n if (typeof attribute.max === 'number') {\n field.max = attribute.max;\n }\n if (typeof attribute.count === 'number') {\n field.uniqueValueCount = attribute.count;\n }\n if (attribute.values) {\n // Too much data? Add option?\n field.values = attribute.values;\n }\n\n if (field.values && typeof options.maxValues === 'number') {\n // Too much data? Add option?\n field.values = field.values?.slice(0, options.maxValues);\n }\n\n return field;\n}\n\nfunction attributeTypeToFieldType(aType: string): {type: string} {\n const type = aType.toLowerCase();\n if (!type || !attrTypeMap[type]) {\n // console.warn(\n // `cannot convert attribute type ${type} to loaders.gl data type, use string by default`\n // );\n }\n return attrTypeMap[type] || {type: 'string'};\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport type {LoaderWithParser, LoaderOptions} from '@loaders.gl/loader-utils';\nimport type {TileJSON} from './lib/parse-tilejson';\nimport {parseTileJSON} from './lib/parse-tilejson';\n\n// __VERSION__ is injected by babel-plugin-version-inline\n// @ts-ignore TS2304: Cannot find name '__VERSION__'.\nconst VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'latest';\n\nexport type TileJSONLoaderOptions = LoaderOptions & {\n /** Options for the TileJSONLoader */\n tilejson?: {\n /** Max number of unique values */\n maxValues?: number;\n };\n};\n\n/**\n * Loader for TileJSON metadata\n */\nexport const TileJSONLoader = {\n dataType: null as unknown as TileJSON,\n batchType: null as never,\n\n name: 'TileJSON',\n id: 'tilejson',\n module: 'pmtiles',\n version: VERSION,\n worker: true,\n extensions: ['json'],\n mimeTypes: ['application/json'],\n text: true,\n options: {\n tilejson: {\n maxValues: undefined\n }\n },\n parse: async (arrayBuffer: ArrayBuffer, options?: TileJSONLoaderOptions) => {\n const jsonString = new TextDecoder().decode(arrayBuffer);\n const json = JSON.parse(jsonString);\n const tilejsonOptions = {...TileJSONLoader.options.tilejson, ...options?.tilejson};\n return parseTileJSON(json, tilejsonOptions) as TileJSON;\n },\n parseTextSync: (text: string, options?: TileJSONLoaderOptions) => {\n const json = JSON.parse(text);\n const tilejsonOptions = {...TileJSONLoader.options.tilejson, ...options?.tilejson};\n return parseTileJSON(json, tilejsonOptions) as TileJSON;\n }\n} as const satisfies LoaderWithParser<TileJSON, never, TileJSONLoaderOptions>;\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright vis.gl contributors\n\nimport type {FlatFeature, Feature, GeoJSONTable, BinaryFeatureCollection} from '@loaders.gl/schema';\nimport {flatGeojsonToBinary, GeojsonGeometryInfo} from '@loaders.gl/gis';\nimport {log} from '@loaders.gl/loader-utils';\nimport Protobuf from 'pbf';\n\nimport {VectorTile} from './vector-tile/vector-tile';\nimport {VectorTileFeature} from './vector-tile/vector-tile-feature';\n\nimport type {MVTLoaderOptions} from '../mvt-loader';\ntype MVTOptions = Required<MVTLoaderOptions>['mvt'];\n\n/**\n * Parse MVT arrayBuffer and return GeoJSON.\n *\n * @param arrayBuffer A MVT arrayBuffer\n * @param options\n * @returns A GeoJSON geometry object or a binary representation\n */\nexport function parseMVT(arrayBuffer: ArrayBuffer, options?: MVTLoaderOptions) {\n const mvtOptions = checkOptions(options);\n\n const shape: string | undefined =\n (options?.gis as {format?: string} | undefined)?.format ||\n options?.mvt?.shape ||\n (options as {shape?: string} | undefined)?.shape;\n switch (shape) {\n case 'columnar-table': // binary + some JS arrays\n return {shape: 'columnar-table', data: parseToBinary(arrayBuffer, mvtOptions)};\n case 'geojson-table': {\n const table: GeoJSONTable = {\n shape: 'geojson-table',\n type: 'FeatureCollection',\n features: parseToGeojsonFeatures(arrayBuffer, mvtOptions)\n };\n return table;\n }\n case 'geojson':\n return parseToGeojsonFeatures(arrayBuffer, mvtOptions);\n case 'binary-geometry':\n return parseToBinary(arrayBuffer, mvtOptions);\n case 'binary':\n return parseToBinary(arrayBuffer, mvtOptions);\n default:\n throw new Error(shape || 'undefined shape');\n }\n}\n\nfunction parseToBinary(arrayBuffer: ArrayBuffer, options: MVTOptions): BinaryFeatureCollection {\n const [flatGeoJsonFeatures, geometryInfo] = parseToFlatGeoJson(arrayBuffer, options);\n\n const binaryData = flatGeojsonToBinary(flatGeoJsonFeatures, geometryInfo);\n // Add the original byteLength (as a reasonable approximation of the size of the binary data)\n // TODO decide where to store extra fields like byteLength (header etc) and document\n // @ts-ignore\n binaryData.byteLength = arrayBuffer.byteLength;\n return binaryData;\n}\n\nfunction parseToFlatGeoJson(\n arrayBuffer: ArrayBuffer,\n options: MVTOptions\n): [FlatFeature[], GeojsonGeometryInfo] {\n const features: FlatFeature[] = [];\n const geometryInfo: GeojsonGeometryInfo = {\n coordLength: 2,\n pointPositionsCount: 0,\n pointFeaturesCount: 0,\n linePositionsCount: 0,\n linePathsCount: 0,\n lineFeaturesCount: 0,\n polygonPositionsCount: 0,\n polygonObjectsCount: 0,\n polygonRingsCount: 0,\n polygonFeaturesCount: 0\n };\n\n if (arrayBuffer.byteLength <= 0) {\n return [features, geometryInfo];\n }\n\n const tile = new VectorTile(new Protobuf(arrayBuffer));\n\n const selectedLayers =\n options && Array.isArray(options.layers) ? options.layers : Object.keys(tile.layers);\n\n selectedLayers.forEach((layerName: string) => {\n const vectorTileLayer = tile.layers[layerName];\n if (!vectorTileLayer) {\n return;\n }\n\n for (let i = 0; i < vectorTileLayer.length; i++) {\n const vectorTileFeature = vectorTileLayer.getBinaryFeature(i, geometryInfo);\n const decodedFeature = getDecodedFeatureBinary(vectorTileFeature, options, layerName);\n features.push(decodedFeature);\n }\n });\n\n return [features, geometryInfo];\n}\n\nfunction parseToGeojsonFeatures(arrayBuffer: ArrayBuffer, options: MVTOptions): Feature[] {\n if (arrayBuffer.byteLength <= 0) {\n return [];\n }\n\n const features: Feature[] = [];\n const tile = new VectorTile(new Protobuf(arrayBuffer));\n\n const selectedLayers = Array.isArray(options.layers) ? options.layers : Object.keys(tile.layers);\n\n selectedLayers.forEach((layerName: string) => {\n const vectorTileLayer = tile.layers[layerName];\n if (!vectorTileLayer) {\n return;\n }\n\n for (let i = 0; i < vectorTileLayer.length; i++) {\n const vectorTileFeature = vectorTileLayer.getGeoJSONFeature(i);\n const decodedFeature = getDecodedFeature(vectorTileFeature, options, layerName);\n features.push(decodedFeature);\n }\n });\n\n return features;\n}\n\n/** Check that options are good */\nfunction checkOptions(options?: MVTLoaderOptions): MVTOptions {\n if (!options?.mvt) {\n throw new Error('mvt options required');\n }\n\n if (options.mvt?.coordinates === 'wgs84' && !options.mvt.tileIndex) {\n throw new Error('MVT Loader: WGS84 coordinates need tileIndex property');\n }\n\n if (options.gis) {\n log.warn('MVTLoader: \"options.gis\" is deprecated, use \"options.mvt.shape\" instead')();\n }\n\n return options.mvt;\n}\n\n/**\n * @param feature\n * @param options\n * @returns decoded feature\n */\nfunction getDecodedFeature(\n feature: VectorTileFeature,\n options: MVTOptions,\n layerName: string\n): Feature {\n const decodedFeature = feature.toGeoJSONFeature(\n options.coordinates || 'local',\n options.tileIndex\n );\n\n // Add layer name to GeoJSON properties\n if (options.layerProperty) {\n decodedFeature.properties ||= {};\n decodedFeature.properties[options.layerProperty] = layerName;\n }\n\n return decodedFeature;\n}\n\n/**\n * @param feature\n * @param options\n * @returns decoded binary feature\n */\nfunction getDecodedFeatureBinary(\n feature: VectorTileFeature,\n options: MVTOptions,\n layerName: string\n): FlatFeature {\n const decodedFeature = feature.toBinaryFeature(options.coordinates || 'local', options.tileIndex);\n\n // Add layer name to GeoJSON properties\n if (options.layerProperty && decodedFeature.properties) {\n decodedFeature.properties[options.layerProperty] = layerName;\n }\n\n return decodedFeature;\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright vis.gl contributors\n\nimport {getPolygonSignedArea} from '@math.gl/polygon';\nimport {FlatIndexedGeometry, FlatPolygon} from '@loaders.gl/schema';\n\n/**\n *\n * @param ring\n * @returns sum\n */\nexport function signedArea(ring: number[][]) {\n let sum = 0;\n for (let i = 0, j = ring.length - 1, p1: number[], p2: number[]; i < ring.length; j = i++) {\n p1 = ring[i];\n p2 = ring[j];\n sum += (p2[0] - p1[0]) * (p1[1] + p2[1]);\n }\n return sum;\n}\n\n/**\n * This function projects local coordinates in a\n * [0 - bufferSize, this.extent + bufferSize] range to a\n * [0 - (bufferSize / this.extent), 1 + (bufferSize / this.extent)] range.\n * The resulting extent would be 1.\n * @param line\n * @param feature\n */\nexport function convertToLocalCoordinates(\n coordinates: number[] | number[][] | number[][][] | number[][][][],\n extent: number\n): void {\n if (Array.isArray(coordinates[0])) {\n for (const subcoords of coordinates) {\n convertToLocalCoordinates(subcoords as number[] | number[][] | number[][][], extent);\n }\n return;\n }\n\n // Just a point\n const p = coordinates as number[];\n p[0] /= extent;\n p[1] /= extent;\n}\n\n/**\n * For the binary code path, the feature data is just\n * one big flat array, so we just divide each value\n * @param data\n * @param feature\n */\nexport function convertToLocalCoordinatesFlat(data: number[], extent: number): void {\n for (let i = 0; i < data.length; ++i) {\n data[i] /= extent;\n }\n}\n\n/**\n * Projects local tile coordinates to lngLat in place.\n * @param points\n * @param tileIndex\n */\nexport function projectToLngLat(\n line: number[] | number[][] | number[][][],\n tileIndex: {x: number; y: number; z: number},\n extent: number\n): void {\n if (typeof line[0][0] !== 'number') {\n for (const point of line) {\n // @ts-expect-error\n projectToLngLat(point, tileIndex, extent);\n }\n return;\n }\n const size = extent * Math.pow(2, tileIndex.z);\n const x0 = extent * tileIndex.x;\n const y0 = extent * tileIndex.y;\n for (let j = 0; j < line.length; j++) {\n const p = line[j];\n p[0] = ((p[0] + x0) * 360) / size - 180;\n const y2 = 180 - ((p[1] + y0) * 360) / size;\n p[1] = (360 / Math.PI) * Math.atan(Math.exp((y2 * Math.PI) / 180)) - 90;\n }\n}\n\n/**\n * Projects local tile coordinates to lngLat in place.\n * @param points\n * @param tileIndex\nexport function projectTileCoordinatesToLngLat(\n points: number[][],\n tileIndex: {x: number; y: number; z: number},\n extent: number\n): void {\n const {x, y, z} = tileIndex;\n const size = extent * Math.pow(2, z);\n const x0 = extent * x;\n const y0 = extent * y;\n\n for (const p of points) {\n p[0] = ((p[0] + x0) * 360) / size - 180;\n const y2 = 180 - ((p[1] + y0) * 360) / size;\n p[1] = (360 / Math.PI) * Math.atan(Math.exp((y2 * Math.PI) / 180)) - 90;\n }\n}\n */\n\n/**\n *\n * @param data\n * @param x0\n * @param y0\n * @param size\n */\nexport function projectToLngLatFlat(\n data: number[],\n tileIndex: {x: number; y: number; z: number},\n extent: number\n): void {\n const {x, y, z} = tileIndex;\n const size = extent * Math.pow(2, z);\n const x0 = extent * x;\n const y0 = extent * y;\n\n for (let j = 0, jl = data.length; j < jl; j += 2) {\n data[j] = ((data[j] + x0) * 360) / size - 180;\n const y2 = 180 - ((data[j + 1] + y0) * 360) / size;\n data[j + 1] = (360 / Math.PI) * Math.atan(Math.exp((y2 * Math.PI) / 180)) - 90;\n }\n}\n\n/**\n * Classifies an array of rings into polygons with outer rings and holes\n * @param rings\n * @returns polygons\n */\nexport function classifyRings(rings: number[][][]): number[][][][] {\n const len = rings.length;\n\n if (len <= 1) return [rings];\n\n const polygons: number[][][][] = [];\n let polygon: number[][][] | undefined;\n let ccw: boolean | undefined;\n\n for (let i = 0; i < len; i++) {\n const area = signedArea(rings[i]);\n if (area === 0) continue; // eslint-disable-line no-continue\n\n if (ccw === undefined) ccw = area < 0;\n\n if (ccw === area < 0) {\n if (polygon) polygons.push(polygon);\n polygon = [rings[i]];\n } else if (polygon) polygon.push(rings[i]);\n }\n if (polygon) polygons.push(polygon);\n\n return polygons;\n}\n\n/**\n * Classifies an array of rings into polygons with outer rings and holes\n * The function also detects holes which have zero area and\n * removes them. In doing so it modifies the input\n * `geom.data` array to remove the unneeded data\n *\n * @param geometry\n * @returns object\n */\n// eslint-disable-next-line max-statements\nexport function classifyRingsFlat(geom: FlatIndexedGeometry): FlatPolygon {\n const len = geom.indices.length;\n const type = 'Polygon';\n\n if (len <= 1) {\n return {\n type,\n data: geom.data,\n areas: [[getPolygonSignedArea(geom.data)]],\n indices: [geom.indices]\n };\n }\n\n const areas: any[] = [];\n const polygons: any[] = [];\n let ringAreas: number[] = [];\n let polygon: number[] = [];\n let ccw: boolean | undefined;\n let offset = 0;\n\n for (let endIndex: number, i = 0, startIndex: number; i < len; i++) {\n startIndex = geom.indices[i] - offset;\n\n endIndex = geom.indices[i + 1] - offset || geom.data.length;\n const shape = geom.data.slice(startIndex, endIndex);\n const area = getPolygonSignedArea(shape);\n\n if (area === 0) {\n // This polygon has no area, so remove it from the shape\n // Remove the section from the data array\n const before = geom.data.slice(0, startIndex);\n const after = geom.data.slice(endIndex);\n geom.data = before.concat(after);\n\n // Need to offset any remaining indices as we have\n // modified the data buffer\n offset += endIndex - startIndex;\n\n // Do not add this index to the output and process next shape\n continue; // eslint-disable-line no-continue\n }\n\n if (ccw === undefined) ccw = area < 0;\n\n if (ccw === area < 0) {\n if (polygon.length) {\n areas.push(ringAreas);\n polygons.push(polygon);\n }\n polygon = [startIndex];\n ringAreas = [area];\n } else {\n ringAreas.push(area);\n polygon.push(startIndex);\n }\n }\n if (ringAreas) areas.push(ringAreas);\n if (polygon.length) polygons.push(polygon);\n\n return {type, areas, indices: polygons, data: geom.data};\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright vis.gl contributors\n\n// This code is forked from https://github.com/mapbox/vector-tile-js under BSD 3-clause license.\n\nimport type {Feature, FlatFeature, FlatIndexedGeometry} from '@loaders.gl/schema';\nimport type {GeojsonGeometryInfo} from '@loaders.gl/gis';\nimport Protobuf from 'pbf';\nimport {\n classifyRings,\n classifyRingsFlat,\n projectToLngLat,\n projectToLngLatFlat,\n convertToLocalCoordinates,\n convertToLocalCoordinatesFlat\n} from '../utils/geometry-utils';\n\nexport class VectorTileFeature {\n properties: {[x: string]: string | number | boolean | null};\n extent: any;\n type: number;\n id: number | null;\n _pbf: Protobuf;\n _geometry: number;\n _keys: string[];\n _values: (string | number | boolean | null)[];\n _geometryInfo: GeojsonGeometryInfo;\n\n static types: Readonly<string[]> = ['Unknown', 'Point', 'LineString', 'Polygon'];\n\n // eslint-disable-next-line max-params\n constructor(\n pbf: Protobuf,\n end: number,\n extent: any,\n keys: string[],\n values: (string | number | boolean | null)[],\n geometryInfo?: GeojsonGeometryInfo\n ) {\n // Public\n this.properties = {};\n this.extent = extent;\n this.type = 0;\n this.id = null;\n\n // Private\n this._pbf = pbf;\n this._geometry = -1;\n this._keys = keys;\n this._values = values;\n\n // Only used by binary tiles\n this._geometryInfo = geometryInfo!;\n\n pbf.readFields(readFeature, this, end);\n }\n\n toGeoJSONFeature(\n coordinates: 'wgs84' | 'local',\n tileIndex?: {x: number; y: number; z: number}\n ): Feature {\n const coords = this.loadGeometry();\n\n switch (coordinates) {\n case 'wgs84':\n return _toGeoJSONFeature(this, coords, (line: number[][]) =>\n projectToLngLat(line, tileIndex!, this.extent)\n );\n\n default:\n return _toGeoJSONFeature(this, coords, convertToLocalCoordinates);\n }\n }\n /**\n *\n * @param options\n * @returns\n */\n toBinaryFeature(\n coordinates: 'wgs84' | 'local',\n tileIndex?: {x: number; y: number; z: number}\n ): FlatFeature {\n const geom = this.loadFlatGeometry();\n\n switch (coordinates) {\n case 'wgs84':\n return this._toBinaryCoordinates(geom, (coords: number[]) =>\n projectToLngLatFlat(coords, tileIndex!, this.extent)\n );\n\n default:\n return this._toBinaryCoordinates(geom, convertToLocalCoordinatesFlat);\n }\n }\n\n /** Read a bounding box from the feature */\n // eslint-disable-next-line max-statements\n bbox() {\n const pbf = this._pbf;\n pbf.pos = this._geometry;\n\n const end = pbf.readVarint() + pbf.pos;\n let cmd = 1;\n let length = 0;\n let x = 0;\n let y = 0;\n let x1 = Infinity;\n let x2 = -Infinity;\n let y1 = Infinity;\n let y2 = -Infinity;\n\n while (pbf.pos < end) {\n if (length <= 0) {\n const cmdLen = pbf.readVarint();\n cmd = cmdLen & 0x7;\n length = cmdLen >> 3;\n }\n\n length--;\n\n if (cmd === 1 || cmd === 2) {\n x += pbf.readSVarint();\n y += pbf.readSVarint();\n if (x < x1) x1 = x;\n if (x > x2) x2 = x;\n if (y < y1) y1 = y;\n if (y > y2) y2 = y;\n } else if (cmd !== 7) {\n throw new Error(`unknown command ${cmd}`);\n }\n }\n\n return [x1, y1, x2, y2];\n }\n\n // BINARY HELPERS\n\n /**\n *\n * @param transform\n * @returns result\n */\n _toBinaryCoordinates(\n geom: FlatIndexedGeometry,\n transform: (data: number[], extent: number) => void\n ) {\n let geometry;\n\n // Apply the supplied transformation to data\n transform(geom.data, this.extent);\n\n const coordLength = 2;\n\n // eslint-disable-next-line default-case\n switch (this.type) {\n case 1: // Point\n this._geometryInfo.pointFeaturesCount++;\n this._geometryInfo.pointPositionsCount += geom.indices.length;\n geometry = {type: 'Point', ...geom};\n break;\n\n case 2: // LineString\n this._geometryInfo.lineFeaturesCount++;\n this._geometryInfo.linePathsCount += geom.indices.length;\n this._geometryInfo.linePositionsCount += geom.data.length / coordLength;\n geometry = {type: 'LineString', ...geom};\n break;\n\n case 3: // Polygon\n geometry = classifyRingsFlat(geom);\n\n // Unlike Point & LineString geom.indices is a 2D array, thanks\n // to the classifyRings method\n this._geometryInfo.polygonFeaturesCount++;\n this._geometryInfo.polygonObjectsCount += geometry.indices.length;\n\n for (const indices of geometry.indices) {\n this._geometryInfo.polygonRingsCount += indices.length;\n }\n this._geometryInfo.polygonPositionsCount += geometry.data.length / coordLength;\n\n break;\n default:\n throw new Error(`Invalid geometry type: ${this.type}`);\n }\n\n const result: FlatFeature = {type: 'Feature', geometry, properties: this.properties};\n\n if (this.id !== null) {\n result.id = this.id;\n }\n\n return result;\n }\n\n // GEOJSON HELPER\n\n // eslint-disable-next-line complexity, max-statements\n loadGeometry(): number[][][] {\n const pbf = this._pbf;\n pbf.pos = this._geometry;\n\n const end = pbf.readVarint() + pbf.pos;\n let cmd = 1;\n let length = 0;\n let x = 0;\n let y = 0;\n const lines: number[][][] = [];\n let line: number[][] | undefined;\n\n while (pbf.pos < end) {\n if (length <= 0) {\n const cmdLen = pbf.readVarint();\n cmd = cmdLen & 0x7;\n length = cmdLen >> 3;\n }\n\n length--;\n\n switch (cmd) {\n case 1:\n case 2:\n x += pbf.readSVarint();\n y += pbf.readSVarint();\n\n if (cmd === 1) {\n // moveTo\n if (line) lines.push(line);\n line = [];\n }\n if (line) line.push([x, y]);\n break;\n case 7:\n // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90\n if (line) {\n line.push(line[0].slice()); // closePolygon\n }\n break;\n default:\n throw new Error(`unknown command ${cmd}`);\n }\n }\n\n if (line) lines.push(line);\n\n return lines;\n }\n\n /**\n * Expands the protobuf data to an intermediate Flat GeoJSON\n * data format, which maps closely to the binary data buffers.\n * It is similar to GeoJSON, but rather than storing the coordinates\n * in multidimensional arrays, we have a 1D `data` with all the\n * coordinates, and then index into this using the `indices`\n * parameter, e.g.\n *\n * geometry: {\n * type: 'Point', data: [1,2], indices: [0]\n * }\n * geometry: {\n * type: 'LineString', data: [1,2,3,4,...], indices: [0]\n * }\n * geometry: {\n * type: 'Polygon', data: [1,2,3,4,...], indices: [[0, 2]]\n * }\n * Thus the indices member lets us look up the relevant range\n * from the data array.\n * The Multi* versions of the above types share the same data\n * structure, just with multiple elements in the indices array\n */\n // eslint-disable-next-line complexity, max-statements\n loadFlatGeometry(): FlatIndexedGeometry {\n const pbf = this._pbf;\n pbf.pos = this._geometry;\n\n const endPos = pbf.readVarint() + pbf.pos;\n let cmd = 1;\n let cmdLen: number;\n let length = 0;\n let x = 0;\n let y = 0;\n let i = 0;\n\n // Note: I attempted to replace the `data` array with a\n // Float32Array, but performance was worse, both using\n // `set()` and direct index access. Also, we cannot\n // know how large the buffer should be, so it would\n // increase memory usage\n const indices: number[] = []; // Indices where geometries start\n const data: number[] = []; // Flat array of coordinate data\n\n while (pbf.pos < endPos) {\n if (length <= 0) {\n cmdLen = pbf.readVarint();\n cmd = cmdLen & 0x7;\n length = cmdLen >> 3;\n }\n\n length--;\n\n if (cmd === 1 || cmd === 2) {\n x += pbf.readSVarint();\n y += pbf.readSVarint();\n\n if (cmd === 1) {\n // New line\n indices.push(i);\n }\n data.push(x, y);\n i += 2;\n } else if (cmd === 7) {\n // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90\n if (i > 0) {\n const start = indices[indices.length - 1]; // start index of polygon\n data.push(data[start], data[start + 1]); // closePolygon\n i += 2;\n }\n } else {\n throw new Error(`unknown command ${cmd}`);\n }\n }\n\n return {data, indices};\n }\n}\n\nfunction _toGeoJSONFeature(\n vtFeature: VectorTileFeature,\n coords: number[][][],\n transform: (data: number[][], extent: number) => void\n): Feature {\n let type = VectorTileFeature.types[vtFeature.type];\n let i: number;\n let j: number;\n\n let coordinates: number[][] | number[][][] | number[][][][];\n switch (vtFeature.type) {\n case 1:\n const points: number[][] = [];\n for (i = 0; i < coords.length; i++) {\n points[i] = coords[i][0];\n }\n coordinates = points;\n transform(coordinates, vtFeature.extent);\n break;\n\n case 2:\n coordinates = coords;\n for (i = 0; i < coordinates.length; i++) {\n transform(coordinates[i], vtFeature.extent);\n }\n break;\n\n case 3:\n coordinates = classifyRings(coords);\n for (i = 0; i < coordinates.length; i++) {\n for (j = 0; j < coordinates[i].length; j++) {\n transform(coordinates[i][j], vtFeature.extent);\n }\n }\n break;\n\n default:\n throw new Error('illegal vector tile type');\n }\n\n if (coordinates.length === 1) {\n // @ts-expect-error\n coordinates = coordinates[0];\n } else {\n type = `Multi${type}`;\n }\n\n const result: Feature = {\n type: 'Feature',\n geometry: {\n type: type as any,\n coordinates: coordinates as any\n },\n properties: vtFeature.properties\n };\n\n if (vtFeature.id !== null) {\n result.properties ||= {};\n result.properties.id = vtFeature.id;\n }\n\n return result;\n}\n\n// PBF READER UTILS\n\n/**\n *\n * @param tag\n * @param feature\n * @param pbf\n */\nfunction readFeature(tag: number, feature?: VectorTileFeature, pbf?: Protobuf): void {\n if (feature && pbf) {\n if (tag === 1) feature.id = pbf.readVarint();\n else if (tag === 2) readTag(pbf, feature);\n else if (tag === 3) feature.type = pbf.readVarint();\n else if (tag === 4) feature._geometry = pbf.pos;\n }\n}\n\n/**\n *\n * @param pbf\n * @param feature\n */\nfunction readTag(pbf: Protobuf, feature: VectorTileFeature): void {\n const end = pbf.readVarint() + pbf.pos;\n\n while (pbf.pos < end) {\n const key = feature._keys[pbf.readVarint()];\n const value = feature._values[pbf.readVarint()];\n feature.properties[key] = value;\n }\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright vis.gl contributors\n\n/* eslint-disable indent */\n// This code is forked from https://github.com/mapbox/vector-tile-js under BSD 3-clause license.\n\nimport Protobuf from 'pbf';\nimport {VectorTileFeature} from './vector-tile-feature';\nimport {GeojsonGeometryInfo} from '@loaders.gl/gis';\n\nexport class VectorTileLayer {\n version: number;\n name: string;\n extent: number;\n length: number;\n _pbf: Protobuf;\n _keys: string[];\n _values: (string | number | boolean | null)[];\n _features: number[];\n\n constructor(pbf: Protobuf, end: number) {\n // Public\n this.version = 1;\n this.name = '';\n this.extent = 4096;\n this.length = 0;\n\n // Private\n this._pbf = pbf;\n this._keys = [];\n this._values = [];\n this._features = [];\n\n pbf.readFields(readLayer, this, end);\n\n this.length = this._features.length;\n }\n\n /**\n * return feature `i` from this layer as a `VectorTileFeature`\n * @param index\n * @returns feature\n */\n getGeoJSONFeature(i: number): VectorTileFeature {\n if (i < 0 || i >= this._features.length) {\n throw new Error('feature index out of bounds');\n }\n\n this._pbf.pos = this._features[i];\n\n const end = this._pbf.readVarint() + this._pbf.pos;\n return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values);\n }\n\n /**\n * return binary feature `i` from this layer as a `VectorTileFeature`\n *\n * @param index\n * @param geometryInfo\n * @returns binary feature\n */\n getBinaryFeature(i: number, geometryInfo: GeojsonGeometryInfo): VectorTileFeature {\n if (i < 0 || i >= this._features.length) {\n throw new Error('feature index out of bounds');\n }\n\n this._pbf.pos = this._features[i];\n\n const end = this._pbf.readVarint() + this._pbf.pos;\n return new VectorTileFeature(\n this._pbf,\n end,\n this.extent,\n this._keys,\n this._values,\n geometryInfo\n );\n }\n}\n\n/**\n *\n * @param tag\n * @param layer\n * @param pbf\n */\nfunction readLayer(tag: number, layer?: VectorTileLayer, pbf?: Protobuf): void {\n if (layer && pbf) {\n if (tag === 15) layer.version = pbf.readVarint();\n else if (tag === 1) layer.name = pbf.readString();\n else if (tag === 5) layer.extent = pbf.readVarint();\n else if (tag === 2) layer._features.push(pbf.pos);\n else if (tag === 3) layer._keys.push(pbf.readString());\n else if (tag === 4) layer._values.push(readValueMessage(pbf));\n }\n}\n\n/**\n *\n * @param pbf\n * @returns value\n */\nfunction readValueMessage(pbf: Protobuf) {\n let value: string | number | boolean | null = null;\n const end = pbf.readVarint() + pbf.pos;\n\n while (pbf.pos < end) {\n const tag = pbf.readVarint() >> 3;\n\n value =\n tag === 1\n ? pbf.readString()\n : tag === 2\n ? pbf.readFloat()\n : tag === 3\n ? pbf.readDouble()\n : tag === 4\n ? pbf.readVarint64()\n : tag === 5\n ? pbf.readVarint()\n : tag === 6\n ? pbf.readSVarint()\n : tag === 7\n ? pbf.readBoolean()\n : null;\n }\n\n return value;\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright vis.gl contributors\n\n// This code is forked from https://github.com/mapbox/vector-tile-js under BSD 3-clause license.\n\nimport {VectorTileLayer} from './vector-tile-layer';\nimport Protobuf from 'pbf';\n\nexport class VectorTile {\n layers: {[x: string]: VectorTileLayer};\n constructor(pbf: Protobuf, end?: number) {\n this.layers = pbf.readFields(readTile, {}, end);\n }\n}\n\n/**\n *\n * @param tag\n * @param layers\n * @param pbf\n */\nfunction readTile(tag: number, layers?: {[x: string]: VectorTileLayer}, pbf?: Protobuf): void {\n if (tag === 3) {\n if (pbf) {\n const layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos);\n if (layer.length && layers) {\n layers[layer.name] = layer;\n }\n }\n }\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright vis.gl contributors\n\nimport type {Format} from '@loaders.gl/loader-utils';\n\n/**\n * Worker loader for the Mapbox Vector Tile format\n */\nexport const MVTFormat = {\n name: 'Mapbox Vector Tile',\n id: 'mvt',\n module: 'mvt',\n // Note: ArcGIS uses '.pbf' extension and 'application/octet-stream'\n extensions: ['mvt', 'pbf'],\n mimeTypes: [\n // https://www.iana.org/assignments/media-types/application/vnd.mapbox-vector-tile\n 'application/vnd.mapbox-vector-tile',\n 'application/x-protobuf'\n // 'application/octet-stream'\n ],\n category: 'geometry'\n} as const satisfies Format;\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright vis.gl contributors\n\nimport type {Loader, LoaderWithParser, LoaderOptions} from '@loaders.gl/loader-utils';\n// import type {MVTOptions} from './lib/types';\nimport {parseMVT} from './lib/parse-mvt';\nimport {MVTFormat} from './mvt-format';\n\n// __VERSION__ is injected by babel-plugin-version-inline\n// @ts-ignore TS2304: Cannot find name '__VERSION__'.\nconst VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'latest';\n\nexport type MVTLoaderOptions = LoaderOptions & {\n mvt?: {\n /** Shape of returned data */\n shape?: 'geojson-table' | 'columnar-table' | 'geojson' | 'binary' | 'binary-geometry';\n /** `wgs84`: coordinates in long, lat (`tileIndex` must be provided. `local` coordinates are `0-1` from tile origin */\n coordinates?: 'wgs84' | 'local';\n /** An object containing tile index values (`x`, `y`, `z`) to reproject features' coordinates into WGS84. Mandatory with `wgs84` coordinates option. */\n tileIndex?: {x: number; y: number; z: number};\n /** If provided, stored the layer name of each feature is added to `feature.properties[layerProperty]`. */\n layerProperty?: string | number;\n /** layer filter. If provided, only features belonging to the named layers will be included, otherwise features from all layers are returned. */\n layers?: string[];\n /** Override the URL to the worker bundle (by default loads from unpkg.com) */\n workerUrl?: string;\n };\n gis?: {\n /** @deprecated Use options.mvt.shape === 'binary-geometry' */\n binary?: boolean;\n /** @deprecated. Use options.mvt.shape */\n format?: 'geojson-table' | 'columnar-table' | 'geojson' | 'binary' | 'binary-geometry';\n };\n};\n\n/**\n * Worker loader for the Mapbox Vector Tile format\n */\nexport const MVTWorkerLoader = {\n ...MVTFormat,\n dataType: null as any,\n batchType: null as never,\n version: VERSION,\n worker: true,\n options: {\n mvt: {\n shape: 'geojson',\n coordinates: 'local',\n layerProperty: 'layerName',\n layers: undefined!,\n tileIndex: undefined!\n }\n }\n} as const satisfies Loader<\n any, // BinaryFeatureCollection | GeoJSONTable | Feature<Geometry, GeoJsonProperties>,\n never,\n MVTLoaderOptions\n>;\n\n/**\n * Loader for the Mapbox Vector Tile format\n */\nexport const MVTLoader = {\n ...MVTWorkerLoader,\n parse: async (arrayBuffer, options?: MVTLoaderOptions) => parseMVT(arrayBuffer, options),\n parseSync: parseMVT,\n binary: true\n} as const satisfies LoaderWithParser<\n any, // BinaryFeatureCollection | GeoJSONTable | Feature<Geometry, GeoJsonProperties>,\n never,\n MVTLoaderOptions\n>;\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright vis.gl contributors\n\n// Forked from https://github.com/mapbox/vt-pbf under MIT License Copyright (c) 2015 Anand Thakker\n\nimport Pbf from 'pbf';\nimport type {MVTTile} from '../mvt-pbf/mvt-types';\nimport {writ