@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
JavaScript
;
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