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

@@ -15,7 +15,11 @@ export type FeatureProperties = {
id: string | number;
time_start?: number | null;
time_end?: number | null;
kind?: string | null;
entity_id?: string | null;
entity_ids?: string[];
entity_name?: string | null;
entity_names?: string[];
entity_type_id?: string | null;
};
export type Feature = {
@@ -95,20 +99,22 @@ function isSameUndo(a: UndoAction | undefined, b: UndoAction) {
if (!a) return false;
if (a.type !== b.type) return false;
switch (a.type) {
case "create":
return a.id === (b as UndoAction & { id: typeof a.id }).id;
case "create": {
const next = b as Extract<UndoAction, { type: "create" }>;
return a.id === next.id;
}
case "delete": {
const bb = b as UndoAction & { feature: Feature };
const next = b as Extract<UndoAction, { type: "delete" }>;
return (
a.feature?.properties?.id === bb.feature?.properties?.id &&
geometryEquals(a.feature?.geometry, bb.feature?.geometry)
a.feature.properties.id === next.feature.properties.id &&
geometryEquals(a.feature.geometry, next.feature.geometry)
);
}
case "update": {
const bb = b as UndoAction & { prevGeometry: Geometry };
const next = b as Extract<UndoAction, { type: "update" }>;
return (
a.id === bb.id &&
geometryEquals(a.prevGeometry, bb.prevGeometry)
a.id === next.id &&
geometryEquals(a.prevGeometry, next.prevGeometry)
);
}
default:
@@ -180,6 +186,27 @@ export function useEditorState(initialData: FeatureCollection) {
pushUndo({ type: "create", id: featureClone.properties.id });
}
/**
* Patch non-geometry properties on a feature (used for entity/time metadata).
*/
function patchFeatureProperties(
id: FeatureProperties["id"],
patch: Partial<FeatureProperties>
) {
const idx = draftRef.current.features.findIndex((f) => f.properties.id === id);
if (idx === -1) return;
const nextFeatures = [...draftRef.current.features];
nextFeatures[idx] = {
...nextFeatures[idx],
properties: {
...nextFeatures[idx].properties,
...deepClone(patch),
},
};
commitDraft({ ...draftRef.current, features: nextFeatures });
}
/**
* Update geometry of an existing feature and record change.
*/
@@ -281,16 +308,22 @@ export function useEditorState(initialData: FeatureCollection) {
setBaselineVersion((v) => v + 1);
}
function hasPersistedFeature(id: FeatureProperties["id"]) {
return initialMapRef.current.has(id);
}
return {
draft,
changes,
undoStack,
changeCount,
createFeature,
patchFeatureProperties,
updateFeature,
deleteFeature,
undo,
buildPayload,
clearChanges,
hasPersistedFeature,
};
}