Files
History-client/lib/drawingEngine.ts
2026-04-04 22:24:36 +07:00

98 lines
2.4 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",
geometry: {
type: "Polygon",
coordinates: [closed],
},
},
],
});
}
function onClick(e: maplibregl.MapLayerMouseEvent) {
if (getMode() !== "draw") return;
coords.push([e.lngLat.lng, e.lngLat.lat]);
update(coords);
}
function onMove(e: maplibregl.MapLayerMouseEvent) {
if (getMode() !== "draw" || coords.length === 0) return;
const preview = [...coords, [e.lngLat.lng, e.lngLat.lat]];
update(preview);
}
/**
* Finalize polygon, emit geometry to caller, reset preview.
*/
function finishDrawing() {
if (getMode() !== "draw" || coords.length < 3) return;
const geometry = {
type: "Polygon",
coordinates: [closePolygon(coords)],
};
onComplete(geometry);
coords = [];
map.getSource("draw-preview").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);
};
}