draw path | draw area | localstorage layer state | add entities property parallel | timeline bar

This commit is contained in:
taDuc
2026-04-08 20:03:16 +07:00
parent 5ac5c4c0af
commit 4969c8cc57
15 changed files with 2056 additions and 74 deletions

View File

@@ -1,13 +1,21 @@
import maplibregl from "maplibre-gl";
type ModeGetter = () => "idle" | "draw" | "select" | "add-point";
type ModeGetter = () => "idle" | "draw" | "select" | "add-point" | "add-path" | "add-circle";
export function initSelect(
map: maplibregl.Map,
getMode: ModeGetter,
onDelete: (id: string | number) => void,
onEdit: (feature: maplibregl.MapGeoJSONFeature) => void
onEdit: (feature: maplibregl.MapGeoJSONFeature) => void,
onSelectId?: (id: string | number | null) => void
) {
const SELECTABLE_LAYERS = [
"countries-fill",
"countries-line",
"routes-line",
"places-circle",
"places-symbol",
] as const;
const selectedIds = new Set<number | string>();
let contextMenu: HTMLDivElement | null = null;
let docClickHandler: ((ev: MouseEvent) => void) | null = null;
@@ -21,6 +29,7 @@ export function initSelect(
map.setFeatureState({ source: "countries", id }, { selected: false });
});
selectedIds.clear();
onSelectId?.(null);
}
/**
@@ -38,18 +47,20 @@ export function initSelect(
// Alt + click on an already selected feature removes it from the selection
map.setFeatureState({ source: "countries", id }, { selected: false });
selectedIds.delete(id);
onSelectId?.(selectedIds.size === 1 ? Array.from(selectedIds)[0] : null);
return;
}
map.setFeatureState({ source: "countries", id }, { selected: true });
selectedIds.add(id);
onSelectId?.(selectedIds.size === 1 ? id : null);
}
function onClick(e: maplibregl.MapLayerMouseEvent) {
if (getMode() !== "select") return;
const features = map.queryRenderedFeatures(e.point, {
layers: ["countries-fill"],
layers: [...SELECTABLE_LAYERS],
}) as maplibregl.MapGeoJSONFeature[];
if (!features.length) {
@@ -70,7 +81,7 @@ export function initSelect(
e.preventDefault(); // block browser menu
const features = map.queryRenderedFeatures(e.point, {
layers: ["countries-fill"],
layers: [...SELECTABLE_LAYERS],
}) as maplibregl.MapGeoJSONFeature[];
if (!features.length) return;
@@ -96,7 +107,7 @@ export function initSelect(
if (getMode() !== "select") return;
const features = map.queryRenderedFeatures(e.point, {
layers: ["countries-fill"],
layers: [...SELECTABLE_LAYERS],
});
map.getCanvas().style.cursor = features.length ? "pointer" : "";
@@ -164,7 +175,7 @@ export function initSelect(
const selectedCount = selectedIds.size || 1;
if (selectedCount === 1) {
if (selectedCount === 1 && clickedFeature.geometry?.type === "Polygon") {
const single = clickedFeature;
menu.appendChild(createItem("Chỉnh sửa", () => onEdit(single)));
}