maplibre-gl-indoor
Version:
A MapLibre plugin to visualize multi-level buildings
87 lines (78 loc) • 2.24 kB
text/typescript
import type { BBox, FeatureCollection, Geometry } from "geojson";
import bbox from "@turf/bbox";
import type { LevelsRange } from "./Types";
/**
* Extract level from feature
*
* @returns {LevelsRange | null} the level or the range of level.
* @param level
*/
export function extractLevelRangeFromFeature(
level: string,
): LevelsRange | null {
const splitLevel: LevelsRange[] = level
.split(";")
.map(parseLevelRange)
.filter((r) => r !== null);
if (!splitLevel.length) return null;
return {
max: Math.max(...splitLevel.map((l) => l.max)),
min: Math.min(...splitLevel.map((l) => l.min)),
};
}
/**
* Extract levels range and bounds from geojson
*
* @param {FeatureCollection<Geometry>} geojson the geojson
* @returns {Object} the levels range and bounds.
*/
export function extractLevelsRangeAndBounds(
geojson: FeatureCollection<Geometry>,
): {
bounds: BBox;
levelsRange: LevelsRange;
} {
if (geojson.type !== "FeatureCollection") {
throw new Error(
geojson.type +
" is not allowed as a top level collection, please use FeatureCollection instead.",
);
}
const levelRanges: LevelsRange[] = geojson.features
.filter(
(feat) => !!feat.properties && typeof feat.properties.level === "string",
)
.map((feat) => extractLevelRangeFromFeature(feat.properties?.level ?? ""))
.filter((r) => r !== null);
if (levelRanges.length == 0) {
console.debug(geojson);
throw new Error(
"the FeatureCollection does not contain a single level. " +
"Cannot compute the range of levels to display",
);
}
return {
bounds: bbox(geojson),
levelsRange: {
max: Math.max(...levelRanges.map((l) => l.max)),
min: Math.min(...levelRanges.map((l) => l.min)),
},
};
}
/**
* Extract level from feature
*
* @returns {LevelsRange | null} the level or the range of level.
* @param range e.g. "-1~-2"
*/
export function parseLevelRange(range: string): LevelsRange | null {
const splitRange = range.split("~");
const parsedRange = {
max: parseFloat(splitRange[1]),
min: parseFloat(splitRange[0]),
};
if (isNaN(parsedRange.min) || isNaN(parsedRange.max)) {
return null;
}
return parsedRange;
}