@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
186 lines (174 loc) • 4.97 kB
text/typescript
import { useMemo } from "react";
import { LoaderWithParser } from "@loaders.gl/loader-utils";
import type { BinaryFeatures } from "@loaders.gl/schema";
type DataShapeNames = keyof DataShapes;
type DataShapes = {
binary: BinaryFeatures;
"binary-geometry": BinaryFeatures;
"columnar-table": { shape: "columnar-table"; data: BinaryFeatures };
geojson: GeoJSON.FeatureCollection;
"geojson-row-table": {
shape: "geojson-row-table";
data: GeoJSON.FeatureCollection;
};
};
type BinaryEntries = [keyof BinaryFeatures, any];
function join<T extends DataShapeNames>({
mapData,
shape,
leftId,
dataAccessor,
}: {
mapData: DataShapes[T];
shape: T;
leftId: string;
dataAccessor: (key: string) => object;
}): DataShapes[T] {
switch (shape) {
case "columnar-table":
case "binary-geometry":
case "binary": {
const isColumnar = shape === "columnar-table";
const dataInner = isColumnar
? (mapData as DataShapes["columnar-table"])['data']
: mapData as DataShapes["binary"];
// @ts-ignore
Object.entries(dataInner).forEach(
// @ts-ignore
([featureType, { properties }]: BinaryEntries) => {
properties &&
properties.forEach((entry: { [key: string]: any }, i: number) => {
const id = entry[leftId];
const data = dataAccessor(id);
if (data && dataInner?.[featureType]) { // @ts-ignore
dataInner[featureType].properties[i] = {
...entry,
...data,
};
}
});
}
);
break;
}
case "geojson-row-table":
case "geojson": {
const isRowTable = shape === "geojson-row-table";
const dataInner = isRowTable
? (mapData as DataShapes["geojson-row-table"])['data']
: mapData as DataShapes["geojson"];
dataInner.features.forEach((entry: { [key: string]: any }) => {
const id = entry.properties[leftId];
const data = dataAccessor(id);
if (data) {
entry.properties = {
...entry.properties,
...data,
};
}
});
break;
}
default:
break;
}
return mapData as DataShapes[T];
}
export const useJoinLoader = ({
loader,
shape,
leftId,
rightId,
tableData,
dataDict,
dataMap,
updateTriggers,
}: {
loader: LoaderWithParser;
shape: keyof DataShapes;
leftId: string;
rightId: string;
tableData?: { [key: string]: any }[];
dataDict?: { [key: string]: object };
dataMap?: Map<string, object>;
updateTriggers?: any[];
}): LoaderWithParser => {
const dataAccessor = useMemo(() => {
if (!dataDict && !dataMap) {
const tempMap = new Map();
tableData &&
tableData.forEach((entry) => tempMap.set(entry[rightId], entry));
return (key: string) => tempMap.get(key);
} else if (dataMap) {
return (key: string) => dataMap.get(key);
} else if (dataDict) {
return (key: string) => dataDict[key];
} else {
return (_key: string) => {};
}
}, [rightId, updateTriggers || tableData]);
const injectedParse: typeof loader.parse = async (arrayBuffer, options) => {
const mapData = await loader.parse(arrayBuffer, options);
return join({
shape,
mapData,
leftId,
dataAccessor,
});
};
const injectedLoader = {
...loader,
parse: injectedParse,
};
return injectedLoader;
};
export function useJoinData<T extends DataShapeNames>({
shape,
leftId,
rightId,
tableData,
dataDict,
dataMap,
updateTriggers,
}: {
shape: T;
leftId: string;
rightId: string;
tableData?: { [key: string]: any }[];
dataDict?: { [key: string]: object };
dataMap?: Map<string, object>;
updateTriggers?: any[];
}): (data: DataShapes[T]) => DataShapes[T] {
/**
* Returns a function that can be used to join data in a given format with another table.
*
*
* @shape x - The first input number
* @param y - The second input number
* @returns The arithmetic mean of `x` and `y`
*
* @beta
*/
const dataAccessor = useMemo(() => {
if (!dataDict && !dataMap) {
const tempMap = new Map();
tableData &&
tableData.forEach((entry) => tempMap.set(entry[rightId], entry));
return (key: string) => tempMap.get(key);
} else if (dataMap) {
return (key: string) => dataMap.get(key);
} else if (dataDict) {
return (key: string) => dataDict[key];
} else {
return (_key: string) => {};
}
}, [rightId, updateTriggers || tableData]);
const doJoin: (data: DataShapes[T]) => DataShapes[T] = (mapData) =>
join({
shape,
mapData,
leftId,
dataAccessor,
});
return doJoin;
}