tons of feature
This commit is contained in:
97
lib/drawingEngine.ts
Normal file
97
lib/drawingEngine.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
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);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user