Files
History-user/src/uhm/lib/map/styles/shared/styleBuilders.ts
T

200 lines
5.8 KiB
TypeScript

import maplibregl, { LayerSpecification } from "maplibre-gl";
const TYPE_MATCH_EXPR: maplibregl.ExpressionSpecification = ["coalesce", ["get", "type"], ["get", "entity_type_id"], ""];
const SELECTED_EXPR: maplibregl.ExpressionSpecification = ["boolean", ["feature-state", "selected"], false];
const SELECTED_COLOR = "#22c55e";
type ZoomStops = {
z1: number;
z4: number;
z6: number;
};
type LineGeotypeStyle = {
typeId: string;
color: string;
strokeColor?: string;
opacity?: number;
width?: ZoomStops;
dasharray?: number[];
arrow?: boolean;
arrowOpacity?: number;
arrowOutlineColor?: string;
arrowOutlineWidth?: ZoomStops;
};
type PolygonGeotypeStyle = {
typeId: string;
fillColor: string;
strokeColor: string;
fillOpacity: number;
strokeWidth?: ZoomStops;
dasharray?: number[];
};
const DEFAULT_LINE_WIDTH: ZoomStops = { z1: 2.2, z4: 3.2, z6: 4.2 };
const DEFAULT_ARROW_OUTLINE_WIDTH: ZoomStops = { z1: 0.45, z4: 0.8, z6: 1.2 };
const DEFAULT_POLYGON_STROKE_WIDTH: ZoomStops = { z1: 1.4, z4: 2, z6: 2.8 };
const LINE_GEOMETRY_FILTER: maplibregl.ExpressionSpecification = [
"any",
["==", ["geometry-type"], "LineString"],
["==", ["geometry-type"], "MultiLineString"],
];
const POLYGON_GEOMETRY_FILTER: maplibregl.ExpressionSpecification = [
"any",
["==", ["geometry-type"], "Polygon"],
["==", ["geometry-type"], "MultiPolygon"],
];
export function buildLineGeotypeLayers(
sourceId: string,
pathArrowSourceId: string | undefined,
style: LineGeotypeStyle
): LayerSpecification[] {
const lineLayer: LayerSpecification = {
id: `${style.typeId}-line`,
type: "line",
source: sourceId,
filter: lineFilter(style.typeId),
layout: {
"line-cap": "round",
"line-join": "round",
},
paint: {
"line-color": statusColor(style.color),
"line-width": widthStops(style.width ?? DEFAULT_LINE_WIDTH),
"line-opacity": style.opacity ?? 0.9,
...(style.dasharray ? { "line-dasharray": style.dasharray } : {}),
},
};
const hitLayer: LayerSpecification = {
id: `${style.typeId}-hit`,
type: "line",
source: sourceId,
filter: lineFilter(style.typeId),
layout: {
"line-cap": "round",
"line-join": "round",
},
paint: {
"line-color": "#ffffff",
"line-width": widthStops({ z1: 12, z4: 18, z6: 24 }),
"line-opacity": 0,
},
};
if (style.arrow === false || !pathArrowSourceId) {
return [lineLayer, hitLayer];
}
return [
lineLayer,
hitLayer,
{
id: `${style.typeId}-path-arrow-fill`,
type: "fill",
source: pathArrowSourceId,
filter: ["==", TYPE_MATCH_EXPR, style.typeId],
paint: {
"fill-color": statusFillColor(style.color),
"fill-opacity": [
"case",
SELECTED_EXPR,
0.92,
style.arrowOpacity ?? 0.82,
],
},
},
{
id: `${style.typeId}-path-arrow-line`,
type: "line",
source: pathArrowSourceId,
filter: ["==", TYPE_MATCH_EXPR, style.typeId],
layout: {
"line-cap": "round",
"line-join": "round",
},
paint: {
"line-color": statusStroke(style.arrowOutlineColor ?? style.strokeColor ?? "#0f172a"),
"line-width": widthStops(style.arrowOutlineWidth ?? DEFAULT_ARROW_OUTLINE_WIDTH),
"line-opacity": 0.9,
},
},
];
}
export function buildPolygonGeotypeLayers(
sourceId: string,
style: PolygonGeotypeStyle
): LayerSpecification[] {
return [
{
id: `${style.typeId}-fill`,
type: "fill",
source: sourceId,
filter: polygonFilter(style.typeId),
paint: {
"fill-color": statusFillColor(style.fillColor),
"fill-opacity": [
"case",
SELECTED_EXPR,
0.58,
style.fillOpacity,
],
},
},
{
id: `${style.typeId}-line`,
type: "line",
source: sourceId,
filter: polygonFilter(style.typeId),
layout: {
"line-cap": "round",
"line-join": "round",
},
paint: {
"line-color": statusStroke(style.strokeColor),
"line-width": widthStops(style.strokeWidth ?? DEFAULT_POLYGON_STROKE_WIDTH),
"line-opacity": 0.95,
...(style.dasharray ? { "line-dasharray": style.dasharray } : {}),
},
},
];
}
function statusColor(normalColor: string): maplibregl.ExpressionSpecification {
return [
"case",
SELECTED_EXPR,
SELECTED_COLOR,
normalColor,
];
}
function statusStroke(normalColor: string): maplibregl.ExpressionSpecification {
return [
"case",
SELECTED_EXPR,
SELECTED_COLOR,
normalColor,
];
}
function statusFillColor(normalColor: string): string {
return normalColor;
}
function lineFilter(typeId: string): maplibregl.ExpressionSpecification {
return ["all", LINE_GEOMETRY_FILTER, ["==", TYPE_MATCH_EXPR, typeId]];
}
function polygonFilter(typeId: string): maplibregl.ExpressionSpecification {
return ["all", POLYGON_GEOMETRY_FILTER, ["==", TYPE_MATCH_EXPR, typeId]];
}
function widthStops(stops: ZoomStops): maplibregl.ExpressionSpecification {
return ["interpolate", ["linear"], ["zoom"], 1, stops.z1, 4, stops.z4, 6, stops.z6];
}