feat(workbench): expand SCADA monitoring and investigation presentation

This commit is contained in:
2026-11-07 19:50:14 +08:00
parent 0801e161ec
commit ba71e2d529
133 changed files with 6754 additions and 1438 deletions
@@ -0,0 +1,56 @@
import { Marker, type Map as MapLibreMap } from "maplibre-gl";
import type { EventGpsCoordinate } from "./event-location-coordinate";
const arrowDirections: Record<string, [number, number]> = {
ArrowLeft: [-1, 0], ArrowRight: [1, 0], ArrowUp: [0, -1], ArrowDown: [0, 1]
};
export function createEventLocationMarker({ map, element, coordinate, disabled, onChange, onDragChange }: {
map: MapLibreMap;
element: HTMLButtonElement;
coordinate: EventGpsCoordinate;
disabled: boolean;
onChange: (coordinate: EventGpsCoordinate) => void;
onDragChange: (dragging: boolean) => void;
}) {
const marker = new Marker({ element, anchor: "bottom", draggable: !disabled })
.setLngLat(coordinate)
.addTo(map);
element.setAttribute("aria-label", "事件位置标记,可拖拽调整");
element.setAttribute("title", "拖拽调整事件位置,方向键微调,Shift 加速");
element.setAttribute("aria-keyshortcuts", "ArrowUp ArrowDown ArrowLeft ArrowRight");
marker.on("dragstart", () => {
element.dataset.dragging = "true";
onDragChange(true);
});
marker.on("dragend", () => {
element.dataset.dragging = "false";
onDragChange(false);
const position = marker.getLngLat();
onChange([normalizeLongitude(position.lng), clampLatitude(position.lat)]);
});
// Custom MapLibre markers own their keyboard interaction. Move in screen
// pixels and consume arrows so adjusting the pin cannot also pan the map.
element.onkeydown = (event) => {
if (!marker.isDraggable() || event.altKey || event.ctrlKey || event.metaKey) return;
const direction = arrowDirections[event.key];
if (!direction) return;
event.preventDefault();
event.stopPropagation();
const point = map.project(marker.getLngLat());
const step = event.shiftKey ? 10 : 1;
const position = map.unproject([point.x + direction[0] * step, point.y + direction[1] * step]);
const next: EventGpsCoordinate = [normalizeLongitude(position.lng), clampLatitude(position.lat)];
marker.setLngLat(next);
onChange(next);
};
return marker;
}
export function normalizeLongitude(longitude: number) {
return ((longitude + 180) % 360 + 360) % 360 - 180;
}
export function clampLatitude(latitude: number) {
return Math.max(-90, Math.min(90, latitude));
}