feat(workbench): integrate runtime data and map tooling
This commit is contained in:
@@ -8,7 +8,6 @@ import {
|
||||
} from "./supply-style-expressions";
|
||||
|
||||
export const SCADA_SOURCE_ID = "scada";
|
||||
export const SCADA_HIT_LAYER_ID = "scada-hit";
|
||||
|
||||
export const SCADA_ICON_PATHS = {
|
||||
flow: "/map/scada-flow.png",
|
||||
@@ -29,6 +28,27 @@ export const SCADA_ICON_EXPRESSION: ExpressionSpecification = [
|
||||
SCADA_IMAGE_IDS.pressure
|
||||
];
|
||||
|
||||
export const SCADA_LAYER_CONTROL_ITEMS = [
|
||||
{
|
||||
id: "scada-pressure",
|
||||
label: "压力监测点",
|
||||
description: "83 个压力监测点",
|
||||
deviceType: "pressure",
|
||||
imageId: SCADA_IMAGE_IDS.pressure,
|
||||
color: MAP_STYLE_TOKENS.supply.scadaPressure
|
||||
},
|
||||
{
|
||||
id: "scada-flow",
|
||||
label: "流量监测点",
|
||||
description: "35 个流量监测点",
|
||||
deviceType: "pipe_flow",
|
||||
imageId: SCADA_IMAGE_IDS.flow,
|
||||
color: MAP_STYLE_TOKENS.supply.scadaFlow
|
||||
}
|
||||
] as const;
|
||||
|
||||
export type ScadaLayerControlId = (typeof SCADA_LAYER_CONTROL_ITEMS)[number]["id"];
|
||||
|
||||
const stateOpacity = (state: "hovered" | "selected"): ExpressionSpecification => [
|
||||
"case",
|
||||
state === "selected"
|
||||
@@ -38,12 +58,6 @@ const stateOpacity = (state: "hovered" | "selected"): ExpressionSpecification =>
|
||||
0
|
||||
];
|
||||
|
||||
const scadaColor: ExpressionSpecification = [
|
||||
"match", ["downcase", ["to-string", ["coalesce", ["get", "device_type"], ""]]],
|
||||
"pipe_flow", MAP_STYLE_TOKENS.supply.scadaFlow,
|
||||
MAP_STYLE_TOKENS.supply.scadaPressure
|
||||
];
|
||||
|
||||
type Layer = NonNullable<StyleSpecification["layers"]>[number];
|
||||
|
||||
export type ScadaImageRegistrationResult = {
|
||||
@@ -51,74 +65,164 @@ export type ScadaImageRegistrationResult = {
|
||||
failedImageIds: string[];
|
||||
};
|
||||
|
||||
const scadaCasingLayer: Layer = {
|
||||
id: "scada-casing", type: "circle", source: SCADA_SOURCE_ID, minzoom: SUPPLY_LAYER_VISUALS.scada.minzoom,
|
||||
paint: {
|
||||
"circle-radius": SUPPLY_LAYER_VISUALS.scada.haloRadius,
|
||||
"circle-color": MAP_STYLE_TOKENS.canvas.casing,
|
||||
"circle-opacity": 0.94
|
||||
}
|
||||
};
|
||||
|
||||
const scadaFillLayer: Layer = {
|
||||
id: "scada-fill", type: "circle", source: SCADA_SOURCE_ID, minzoom: SUPPLY_LAYER_VISUALS.scada.minzoom,
|
||||
paint: {
|
||||
"circle-radius": SUPPLY_LAYER_VISUALS.scada.radius,
|
||||
"circle-color": createSupplyStateColor(scadaColor),
|
||||
"circle-opacity": supplyFacilityOpacityExpression
|
||||
}
|
||||
};
|
||||
|
||||
const scadaSymbolLayer: Layer = {
|
||||
id: "scada-symbol", type: "symbol", source: SCADA_SOURCE_ID, minzoom: SUPPLY_LAYER_VISUALS.scada.minzoom,
|
||||
layout: { "icon-image": SCADA_ICON_EXPRESSION, "icon-size": SUPPLY_LAYER_VISUALS.scada.iconSize, "icon-allow-overlap": true, "icon-ignore-placement": true },
|
||||
paint: { "icon-opacity": supplyIconOpacityExpression }
|
||||
};
|
||||
|
||||
const scadaFallbackLayer: Layer = {
|
||||
id: "scada-fallback", type: "circle", source: SCADA_SOURCE_ID, minzoom: SUPPLY_LAYER_VISUALS.scada.minzoom,
|
||||
paint: {
|
||||
"circle-radius": ["interpolate", ["linear"], ["zoom"], 9, 1.7, 12, 2.1, 16, 2.7, 20, 3.4, 24, 4.2],
|
||||
"circle-color": MAP_STYLE_TOKENS.canvas.casing,
|
||||
"circle-opacity": supplyIconOpacityExpression
|
||||
}
|
||||
};
|
||||
|
||||
export const scadaInteractionLayers: Layer[] = [
|
||||
{ id: "scada-hover", type: "circle", source: SCADA_SOURCE_ID, minzoom: SUPPLY_LAYER_VISUALS.scada.minzoom, paint: { "circle-radius": SUPPLY_LAYER_VISUALS.scada.hoverRadius, "circle-color": MAP_STYLE_TOKENS.canvas.transparent, "circle-stroke-color": scadaColor, "circle-stroke-width": 2, "circle-opacity": stateOpacity("hovered"), "circle-stroke-opacity": stateOpacity("hovered") } },
|
||||
{ id: "scada-selected-outer", type: "circle", source: SCADA_SOURCE_ID, minzoom: SUPPLY_LAYER_VISUALS.scada.minzoom, paint: { "circle-radius": SUPPLY_LAYER_VISUALS.scada.selectedRadius, "circle-color": MAP_STYLE_TOKENS.canvas.transparent, "circle-stroke-color": MAP_STYLE_TOKENS.canvas.casing, "circle-stroke-width": 5, "circle-opacity": stateOpacity("selected"), "circle-stroke-opacity": stateOpacity("selected") } },
|
||||
{ id: "scada-selected", type: "circle", source: SCADA_SOURCE_ID, minzoom: SUPPLY_LAYER_VISUALS.scada.minzoom, paint: { "circle-radius": SUPPLY_LAYER_VISUALS.scada.selectedRadius, "circle-color": MAP_STYLE_TOKENS.canvas.transparent, "circle-stroke-color": MAP_STYLE_TOKENS.state.selected, "circle-stroke-width": 2.5, "circle-opacity": stateOpacity("selected"), "circle-stroke-opacity": stateOpacity("selected") } }
|
||||
const typeFilter = (deviceType: string): ExpressionSpecification => [
|
||||
"==",
|
||||
["downcase", ["to-string", ["coalesce", ["get", "device_type"], ""]]],
|
||||
deviceType
|
||||
];
|
||||
|
||||
const scadaHitLayer: Layer = {
|
||||
id: SCADA_HIT_LAYER_ID, type: "circle", source: SCADA_SOURCE_ID, minzoom: SUPPLY_LAYER_VISUALS.scada.minzoom,
|
||||
paint: { "circle-radius": SUPPLY_LAYER_VISUALS.scada.hitRadius, "circle-color": MAP_STYLE_TOKENS.canvas.transparent, "circle-opacity": 0 }
|
||||
};
|
||||
function createScadaLayers(definition: (typeof SCADA_LAYER_CONTROL_ITEMS)[number]) {
|
||||
const filter = typeFilter(definition.deviceType);
|
||||
const color = createSupplyStateColor(definition.color);
|
||||
const business: Layer[] = [
|
||||
{
|
||||
id: `${definition.id}-casing`,
|
||||
type: "circle",
|
||||
source: SCADA_SOURCE_ID,
|
||||
filter,
|
||||
minzoom: SUPPLY_LAYER_VISUALS.scada.minzoom,
|
||||
paint: {
|
||||
"circle-radius": SUPPLY_LAYER_VISUALS.scada.haloRadius,
|
||||
"circle-color": MAP_STYLE_TOKENS.canvas.casing,
|
||||
"circle-opacity": 0.94
|
||||
}
|
||||
},
|
||||
{
|
||||
id: `${definition.id}-fill`,
|
||||
type: "circle",
|
||||
source: SCADA_SOURCE_ID,
|
||||
filter,
|
||||
minzoom: SUPPLY_LAYER_VISUALS.scada.minzoom,
|
||||
paint: {
|
||||
"circle-radius": SUPPLY_LAYER_VISUALS.scada.radius,
|
||||
"circle-color": color,
|
||||
"circle-opacity": supplyFacilityOpacityExpression
|
||||
}
|
||||
},
|
||||
{
|
||||
id: `${definition.id}-symbol`,
|
||||
type: "symbol",
|
||||
source: SCADA_SOURCE_ID,
|
||||
filter,
|
||||
minzoom: SUPPLY_LAYER_VISUALS.scada.minzoom,
|
||||
layout: {
|
||||
"icon-image": definition.imageId,
|
||||
"icon-size": SUPPLY_LAYER_VISUALS.scada.iconSize,
|
||||
"icon-allow-overlap": true,
|
||||
"icon-ignore-placement": true
|
||||
},
|
||||
paint: { "icon-opacity": supplyIconOpacityExpression }
|
||||
}
|
||||
];
|
||||
const fallback: Layer[] = [
|
||||
...business.slice(0, 2),
|
||||
{
|
||||
id: `${definition.id}-fallback`,
|
||||
type: "circle",
|
||||
source: SCADA_SOURCE_ID,
|
||||
filter,
|
||||
minzoom: SUPPLY_LAYER_VISUALS.scada.minzoom,
|
||||
paint: {
|
||||
"circle-radius": ["interpolate", ["linear"], ["zoom"], 9, 1.7, 12, 2.1, 16, 2.7, 20, 3.4, 24, 4.2],
|
||||
"circle-color": MAP_STYLE_TOKENS.canvas.casing,
|
||||
"circle-opacity": supplyIconOpacityExpression
|
||||
}
|
||||
}
|
||||
];
|
||||
const interaction: Layer[] = [
|
||||
{
|
||||
id: `${definition.id}-hover`,
|
||||
type: "circle",
|
||||
source: SCADA_SOURCE_ID,
|
||||
filter,
|
||||
minzoom: SUPPLY_LAYER_VISUALS.scada.minzoom,
|
||||
paint: {
|
||||
"circle-radius": SUPPLY_LAYER_VISUALS.scada.hoverRadius,
|
||||
"circle-color": MAP_STYLE_TOKENS.canvas.transparent,
|
||||
"circle-stroke-color": definition.color,
|
||||
"circle-stroke-width": 2,
|
||||
"circle-opacity": stateOpacity("hovered"),
|
||||
"circle-stroke-opacity": stateOpacity("hovered")
|
||||
}
|
||||
},
|
||||
{
|
||||
id: `${definition.id}-selected-outer`,
|
||||
type: "circle",
|
||||
source: SCADA_SOURCE_ID,
|
||||
filter,
|
||||
minzoom: SUPPLY_LAYER_VISUALS.scada.minzoom,
|
||||
paint: {
|
||||
"circle-radius": SUPPLY_LAYER_VISUALS.scada.selectedRadius,
|
||||
"circle-color": MAP_STYLE_TOKENS.canvas.transparent,
|
||||
"circle-stroke-color": MAP_STYLE_TOKENS.canvas.casing,
|
||||
"circle-stroke-width": 5,
|
||||
"circle-opacity": stateOpacity("selected"),
|
||||
"circle-stroke-opacity": stateOpacity("selected")
|
||||
}
|
||||
},
|
||||
{
|
||||
id: `${definition.id}-selected`,
|
||||
type: "circle",
|
||||
source: SCADA_SOURCE_ID,
|
||||
filter,
|
||||
minzoom: SUPPLY_LAYER_VISUALS.scada.minzoom,
|
||||
paint: {
|
||||
"circle-radius": SUPPLY_LAYER_VISUALS.scada.selectedRadius,
|
||||
"circle-color": MAP_STYLE_TOKENS.canvas.transparent,
|
||||
"circle-stroke-color": MAP_STYLE_TOKENS.state.selected,
|
||||
"circle-stroke-width": 2.5,
|
||||
"circle-opacity": stateOpacity("selected"),
|
||||
"circle-stroke-opacity": stateOpacity("selected")
|
||||
}
|
||||
}
|
||||
];
|
||||
const hit: Layer = {
|
||||
id: `${definition.id}-hit`,
|
||||
type: "circle",
|
||||
source: SCADA_SOURCE_ID,
|
||||
filter,
|
||||
minzoom: SUPPLY_LAYER_VISUALS.scada.minzoom,
|
||||
paint: {
|
||||
"circle-radius": SUPPLY_LAYER_VISUALS.scada.hitRadius,
|
||||
"circle-color": MAP_STYLE_TOKENS.canvas.transparent,
|
||||
"circle-opacity": 0
|
||||
}
|
||||
};
|
||||
return { business, fallback, interaction, hit };
|
||||
}
|
||||
|
||||
export const scadaBusinessLayers: Layer[] = [
|
||||
scadaCasingLayer,
|
||||
scadaFillLayer,
|
||||
scadaSymbolLayer
|
||||
];
|
||||
const groups = SCADA_LAYER_CONTROL_ITEMS.map((definition) => ({
|
||||
definition,
|
||||
layers: createScadaLayers(definition)
|
||||
}));
|
||||
|
||||
export const scadaFallbackBusinessLayers: Layer[] = [
|
||||
scadaCasingLayer,
|
||||
scadaFillLayer,
|
||||
scadaFallbackLayer
|
||||
];
|
||||
export const scadaBusinessLayers = groups.flatMap((group) => group.layers.business);
|
||||
export const scadaFallbackBusinessLayers = groups.flatMap((group) => group.layers.fallback);
|
||||
export const scadaInteractionLayers = groups.flatMap((group) => group.layers.interaction);
|
||||
export const scadaHitLayers = groups.map((group) => group.layers.hit);
|
||||
export const SCADA_HIT_LAYER_IDS = scadaHitLayers.map((layer) => layer.id);
|
||||
export const SCADA_HIT_LAYER_ID = SCADA_HIT_LAYER_IDS[0];
|
||||
|
||||
export const scadaHitLayers: Layer[] = [scadaHitLayer];
|
||||
export const SCADA_LAYER_GROUPS = Object.fromEntries(groups.map(({ definition, layers }) => [
|
||||
definition.id,
|
||||
[
|
||||
...layers.business.map((layer) => layer.id),
|
||||
...layers.fallback.map((layer) => layer.id),
|
||||
...layers.interaction.map((layer) => layer.id),
|
||||
layers.hit.id
|
||||
]
|
||||
])) as Record<ScadaLayerControlId, string[]>;
|
||||
|
||||
export const scadaLayers: Layer[] = [
|
||||
export const scadaLayers = [
|
||||
...scadaBusinessLayers,
|
||||
...scadaInteractionLayers,
|
||||
scadaHitLayer
|
||||
...scadaHitLayers
|
||||
];
|
||||
|
||||
export const scadaFallbackLayers: Layer[] = [
|
||||
export const scadaFallbackLayers = [
|
||||
...scadaFallbackBusinessLayers,
|
||||
...scadaInteractionLayers,
|
||||
scadaHitLayer
|
||||
...scadaHitLayers
|
||||
];
|
||||
|
||||
export async function registerScadaImages(
|
||||
|
||||
Reference in New Issue
Block a user