138 lines
3.8 KiB
TypeScript
138 lines
3.8 KiB
TypeScript
import { Map as OlMap } from "ol";
|
|
import WebGLVectorTileLayer from "ol/layer/WebGLVectorTile";
|
|
import VectorTileSource from "ol/source/VectorTile";
|
|
import { FlatStyleLike } from "ol/style/flat";
|
|
|
|
import { config } from "@/config/config";
|
|
import {
|
|
VectorTileStyleSession,
|
|
versionedPropertyCase,
|
|
} from "@components/olmap/core/vectorTileStyleSession";
|
|
import { getAreaColor } from "./utils";
|
|
|
|
const JUNCTION_LAYER_VALUE = "junctions";
|
|
const RENDER_OWNER_KEY = "junction-area-render-owner";
|
|
|
|
export type JunctionAreaRenderPayload = {
|
|
nodeAreaMap: Record<string, string>;
|
|
areaIds?: string[];
|
|
areaColors?: Record<string, string>;
|
|
};
|
|
|
|
type ApplyJunctionAreaRenderOptions = {
|
|
propertyKey?: string;
|
|
};
|
|
|
|
const DEFAULT_PROPERTY_KEY = "junction_area_render_index";
|
|
|
|
const getJunctionLayer = (map: OlMap) =>
|
|
map
|
|
.getAllLayers()
|
|
.find(
|
|
(layer) =>
|
|
layer instanceof WebGLVectorTileLayer &&
|
|
layer.get("value") === JUNCTION_LAYER_VALUE,
|
|
) as WebGLVectorTileLayer | undefined;
|
|
|
|
export const applyJunctionAreaRender = (
|
|
map: OlMap,
|
|
payload: JunctionAreaRenderPayload,
|
|
options: ApplyJunctionAreaRenderOptions = {},
|
|
) => {
|
|
const propertyKey = options.propertyKey ?? DEFAULT_PROPERTY_KEY;
|
|
const junctionLayer = getJunctionLayer(map);
|
|
if (!junctionLayer) {
|
|
return () => {};
|
|
}
|
|
|
|
const source = junctionLayer.getSource() as VectorTileSource | null;
|
|
if (!source) {
|
|
return () => {};
|
|
}
|
|
|
|
const ownerId = `${propertyKey}-${Date.now().toString(36)}-${Math.random()
|
|
.toString(36)
|
|
.slice(2, 8)}`;
|
|
|
|
const normalizedNodeAreaMap = Object.fromEntries(
|
|
Object.entries(payload.nodeAreaMap ?? {}).map(([nodeId, areaId]) => [
|
|
String(nodeId),
|
|
String(areaId),
|
|
]),
|
|
);
|
|
|
|
const areaIds = (
|
|
payload.areaIds?.length
|
|
? payload.areaIds
|
|
: Array.from(new Set(Object.values(normalizedNodeAreaMap)))
|
|
)
|
|
.map(String)
|
|
.filter(Boolean);
|
|
|
|
if (Object.keys(normalizedNodeAreaMap).length === 0 || areaIds.length === 0) {
|
|
junctionLayer.setStyle(config.MAP_DEFAULT_STYLE as FlatStyleLike);
|
|
return () => {};
|
|
}
|
|
|
|
const areaIdToIndex = new Map<string, number>();
|
|
areaIds.forEach((areaId, index) => {
|
|
areaIdToIndex.set(areaId, index + 1);
|
|
});
|
|
|
|
const nodeAreaIndexMap = new Map<string, number>();
|
|
Object.entries(normalizedNodeAreaMap).forEach(([nodeId, areaId]) => {
|
|
const areaIndex = areaIdToIndex.get(areaId);
|
|
if (areaIndex !== undefined) {
|
|
nodeAreaIndexMap.set(nodeId, areaIndex);
|
|
}
|
|
});
|
|
|
|
const fillCases: any[] = [];
|
|
areaIds.forEach((areaId, index) => {
|
|
fillCases.push(
|
|
["==", ["get", propertyKey], index + 1],
|
|
payload.areaColors?.[areaId] ?? getAreaColor(areaId),
|
|
);
|
|
});
|
|
|
|
const defaultFillColor = String(config.MAP_DEFAULT_STYLE["circle-fill-color"]);
|
|
const defaultStrokeColor = String(
|
|
config.MAP_DEFAULT_STYLE["circle-stroke-color"],
|
|
);
|
|
|
|
junctionLayer.set(RENDER_OWNER_KEY, ownerId);
|
|
const session = new VectorTileStyleSession({
|
|
layer: junctionLayer,
|
|
source,
|
|
propertyKey,
|
|
defaultStyle: config.MAP_DEFAULT_STYLE as FlatStyleLike,
|
|
buildStyle: (statePropertyKey, versionKey, version) =>
|
|
({
|
|
...config.MAP_DEFAULT_STYLE,
|
|
"circle-fill-color": versionedPropertyCase(
|
|
statePropertyKey,
|
|
versionKey,
|
|
version,
|
|
fillCases,
|
|
defaultFillColor,
|
|
),
|
|
"circle-stroke-color": versionedPropertyCase(
|
|
statePropertyKey,
|
|
versionKey,
|
|
version,
|
|
fillCases,
|
|
defaultStrokeColor,
|
|
),
|
|
}) as FlatStyleLike,
|
|
});
|
|
session.commit(nodeAreaIndexMap);
|
|
|
|
return () => {
|
|
session.dispose();
|
|
if (junctionLayer.get(RENDER_OWNER_KEY) === ownerId) {
|
|
junctionLayer.unset(RENDER_OWNER_KEY, true);
|
|
junctionLayer.setStyle(config.MAP_DEFAULT_STYLE as FlatStyleLike);
|
|
}
|
|
};
|
|
};
|