Files
History-client/lib/drawingEngine.ts
2026-04-07 23:32:38 +07:00

102 lines
2.6 KiB
TypeScript

import maplibregl from "maplibre-gl";
import { Geometry } from "@/lib/useEditorState";
type ModeGetter = () => "idle" | "draw" | "select" | "add-point";
export function initDrawing(
map: maplibregl.Map,
getMode: ModeGetter,
onComplete: (geometry: Geometry) => void
) {
let coords: [number, number][] = [];
/**
* Close polygon ring if not closed.
*/
function closePolygon(c: [number, number][]) {
if (c.length < 3) return c;
const first = c[0];
const last = c[c.length - 1];
if (first[0] !== last[0] || first[1] !== last[1]) {
return [...c, first];
}
return c;
}
/**
* Update preview layer while drawing.
*/
function update(c: [number, number][]) {
const closed = closePolygon(c);
(map.getSource("draw-preview") as maplibregl.GeoJSONSource)?.setData({
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: {},
geometry: {
type: "Polygon",
coordinates: [closed],
},
},
],
});
}
function onClick(e: maplibregl.MapLayerMouseEvent) {
if (getMode() !== "draw") return;
coords.push([e.lngLat.lng, e.lngLat.lat] as [number, number]);
update(coords);
}
function onMove(e: maplibregl.MapLayerMouseEvent) {
if (getMode() !== "draw" || coords.length === 0) return;
const preview: [number, number][] = [
...coords,
[e.lngLat.lng, e.lngLat.lat] as [number, number],
];
update(preview);
}
/**
* Finalize polygon, emit geometry to caller, reset preview.
*/
function finishDrawing() {
if (getMode() !== "draw" || coords.length < 3) return;
const geometry: Geometry = {
type: "Polygon",
coordinates: [closePolygon(coords)],
};
onComplete(geometry);
coords = [];
(map.getSource("draw-preview") as maplibregl.GeoJSONSource | undefined)?.setData({
type: "FeatureCollection",
features: [],
});
}
function onKeyDown(e: KeyboardEvent) {
if (e.key === "Enter") {
finishDrawing();
}
}
map.on("click", onClick);
map.on("mousemove", onMove);
document.addEventListener("keydown", onKeyDown);
return () => {
map.off("click", onClick);
map.off("mousemove", onMove);
document.removeEventListener("keydown", onKeyDown);
};
}