UNPKG

@maticoapp/deck.gl-pmtiles

Version:

This repo provides a typed Deck.gl layer and loader for PMTiles data. PMTiles data provides a serverless and compact way to store tile geospatial data. Combined with Deck.gl's rendering, this provides a flexible and powerful way to cheaply manage geospati

402 lines (393 loc) 12.9 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var typed$1 = require('@deck.gl/geo-layers/typed'); var typed = require('@deck.gl/layers/typed'); var pmtiles = require('pmtiles'); var fflate = require('fflate'); var ParseMVT = require('@loaders.gl/mvt/dist/lib/parse-mvt'); var react = require('react'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var ParseMVT__default = /*#__PURE__*/_interopDefaultLegacy(ParseMVT); var __defProp$2 = Object.defineProperty; var __defProps$2 = Object.defineProperties; var __getOwnPropDescs$2 = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols$2 = Object.getOwnPropertySymbols; var __hasOwnProp$2 = Object.prototype.hasOwnProperty; var __propIsEnum$2 = Object.prototype.propertyIsEnumerable; var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues$2 = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp$2.call(b, prop)) __defNormalProp$2(a, prop, b[prop]); if (__getOwnPropSymbols$2) for (var prop of __getOwnPropSymbols$2(b)) { if (__propIsEnum$2.call(b, prop)) __defNormalProp$2(a, prop, b[prop]); } return a; }; var __spreadProps$2 = (a, b) => __defProps$2(a, __getOwnPropDescs$2(b)); var __async$2 = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : "latest"; const DEFAULT_PMT_LOADER_OPTIONS = { pmt: { raster: false }, mvt: {}, image: {} }; const PMTWorkerLoader = { id: "pmt", module: "pmt", name: "PMTiles", version: VERSION, extensions: ["pmtiles"], mimeTypes: ["application/x-protobuf"], worker: true, category: "geometry", options: DEFAULT_PMT_LOADER_OPTIONS }; const PMTLoader = __spreadProps$2(__spreadValues$2({}, PMTWorkerLoader), { parse: (arrayBuffer, options) => __async$2(void 0, null, function* () { return parsePMT(arrayBuffer, options); }), parseSync: (arrayBuffer, options) => { return parsePMT(arrayBuffer, options); }, binary: true }); function parsePMT(arrayBuffer, options) { var _a, _b; if (options && ((_a = options == null ? void 0 : options.pmt) == null ? void 0 : _a.raster)) { const blob = new Blob([arrayBuffer], { type: "image/png" }); URL.createObjectURL(blob); return createImageBitmap(blob); } else if ((_b = options == null ? void 0 : options.pmt) == null ? void 0 : _b.tileCompression) { const decompressed = fflateDecompress(arrayBuffer, options.pmt.tileCompression); const tiledata = ParseMVT__default["default"](decompressed, options); return tiledata; } } function fflateDecompress(buf, compression) { if (compression === pmtiles.Compression.None || compression === pmtiles.Compression.Unknown) { return buf; } else if (compression === pmtiles.Compression.Gzip) { return fflate.decompressSync(new Uint8Array(buf)); } else { throw Error("Compression method not supported"); } } var __defProp$1 = Object.defineProperty; var __defProps$1 = Object.defineProperties; var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols; var __hasOwnProp$1 = Object.prototype.hasOwnProperty; var __propIsEnum$1 = Object.prototype.propertyIsEnumerable; var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues$1 = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp$1.call(b, prop)) __defNormalProp$1(a, prop, b[prop]); if (__getOwnPropSymbols$1) for (var prop of __getOwnPropSymbols$1(b)) { if (__propIsEnum$1.call(b, prop)) __defNormalProp$1(a, prop, b[prop]); } return a; }; var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b)); var __async$1 = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; const defaultProps = __spreadProps$1(__spreadValues$1({}, typed.GeoJsonLayer.defaultProps), { onDataLoad: { type: "function", value: null, optional: true, compare: false }, uniqueIdProperty: "", highlightedFeatureId: null, binary: true, raster: false, loaders: [PMTWorkerLoader] }); class DeckglPmtiles extends pmtiles.PMTiles { getZxyOffset(z, x, y, signal) { return __async$1(this, null, function* () { const tile_id = pmtiles.zxyToTileId(z, x, y); const header = yield this.cache.getHeader(this.source); if (z < header.minZoom || z > header.maxZoom) { return void 0; } let d_o = header.rootDirectoryOffset; let d_l = header.rootDirectoryLength; for (let depth = 0; depth <= 3; depth++) { const directory = yield this.cache.getDirectory( this.source, d_o, d_l, header ); const entry = pmtiles.findTile(directory, tile_id); if (entry) { if (entry.runLength > 0) { return { offset: entry.offset, length: entry.length }; } else { d_o = header.leafDirectoryOffset + entry.offset; d_l = entry.length; } } else { return void 0; } } throw Error("Maximum directory depth exceeded"); }); } } class PMTLayer extends typed$1.MVTLayer { initializeState() { super.initializeState(); const binary = this.context.viewport.resolution !== void 0 ? false : this.props.binary; const raster = this.props.raster; this._updateTileData = () => __async$1(this, null, function* () { const data = this.props.data; const raster2 = this.props.raster; const pmtiles = new DeckglPmtiles(data); const header = yield pmtiles.getHeader(); this.setState({ data, pmtiles, raster: raster2, header }); }); this.setState({ binary, raster, data: null }); } getTileData(loadProps, iter) { const { index, signal } = loadProps; const { data, binary, raster, pmtiles, header } = this.state; const { x, y, z } = index; let loadOptions = this.getLoadOptions(); const { fetch } = this.props; return pmtiles.getZxyOffset(z, x, y, signal).then((entry) => { if (!entry) { return new Promise((resolve) => resolve(null)); } const tileOffset = entry.offset + header.tileDataOffset; const tileLength = entry.length; loadOptions = __spreadProps$1(__spreadValues$1({}, loadOptions), { mimeType: "application/x-protobuf", pmt: __spreadValues$1({ workerUrl: "https://unpkg.com/@maticoapp/deck.gl-pmtiles@latest/dist/pmt-worker.js", coordinates: this.context.viewport.resolution ? "wgs84" : "local", tileIndex: index, raster, tileCompression: header.tileCompression }, loadOptions == null ? void 0 : loadOptions.pmt), gis: binary ? { format: "binary" } : {}, fetch: { headers: { Range: `bytes=${tileOffset}-${tileOffset + tileLength - 1}` } } }); return fetch(data, { propName: "data", layer: this, loadOptions, signal }); }); } } PMTLayer.layerName = "PMTilesLayer"; PMTLayer.defaultProps = defaultProps; var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __async = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; function join({ mapData, shape, leftId, dataAccessor }) { switch (shape) { case "columnar-table": case "binary-geometry": case "binary": { const isColumnar = shape === "columnar-table"; const dataInner = isColumnar ? mapData["data"] : mapData; Object.entries(dataInner).forEach( ([featureType, { properties }]) => { properties && properties.forEach((entry, i) => { const id = entry[leftId]; const data = dataAccessor(id); if (data && (dataInner == null ? void 0 : dataInner[featureType])) { dataInner[featureType].properties[i] = __spreadValues(__spreadValues({}, entry), data); } }); } ); break; } case "geojson-row-table": case "geojson": { const isRowTable = shape === "geojson-row-table"; const dataInner = isRowTable ? mapData["data"] : mapData; dataInner.features.forEach((entry) => { const id = entry.properties[leftId]; const data = dataAccessor(id); if (data) { entry.properties = __spreadValues(__spreadValues({}, entry.properties), data); } }); break; } } return mapData; } const useJoinLoader = ({ loader, shape, leftId, rightId, tableData, dataDict, dataMap, updateTriggers }) => { const dataAccessor = react.useMemo(() => { if (!dataDict && !dataMap) { const tempMap = /* @__PURE__ */ new Map(); tableData && tableData.forEach((entry) => tempMap.set(entry[rightId], entry)); return (key) => tempMap.get(key); } else if (dataMap) { return (key) => dataMap.get(key); } else if (dataDict) { return (key) => dataDict[key]; } else { return (_key) => { }; } }, [rightId, updateTriggers || tableData]); const injectedParse = (arrayBuffer, options) => __async(void 0, null, function* () { const mapData = yield loader.parse(arrayBuffer, options); return join({ shape, mapData, leftId, dataAccessor }); }); const injectedLoader = __spreadProps(__spreadValues({}, loader), { parse: injectedParse }); return injectedLoader; }; function useJoinData({ shape, leftId, rightId, tableData, dataDict, dataMap, updateTriggers }) { const dataAccessor = react.useMemo(() => { if (!dataDict && !dataMap) { const tempMap = /* @__PURE__ */ new Map(); tableData && tableData.forEach((entry) => tempMap.set(entry[rightId], entry)); return (key) => tempMap.get(key); } else if (dataMap) { return (key) => dataMap.get(key); } else if (dataDict) { return (key) => dataDict[key]; } else { return (_key) => { }; } }, [rightId, updateTriggers || tableData]); const doJoin = (mapData) => join({ shape, mapData, leftId, dataAccessor }); return doJoin; } exports.PMTLayer = PMTLayer; exports.PMTLoader = PMTLoader; exports.PMTWorkerLoader = PMTWorkerLoader; exports.useJoinData = useJoinData; exports.useJoinLoader = useJoinLoader; //# sourceMappingURL=index.js.map