fix(planner): clear the route when waypoints drop below two
Deleting waypoints down to <2 left the last computed route rendered — nothing cleared the stale geometry (recompute only runs for >=2). Add a waypoints observer that drops the computed geometry once fewer than two waypoints remain, via a new clearComputedRoute (keeps the routing profile, unlike clearRouteData). Covers all delete paths (sidebar, map, undo). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
104424d531
commit
0f57e9b9ac
3 changed files with 54 additions and 1 deletions
|
|
@ -6,6 +6,8 @@ import {
|
|||
PROFILE_KEY,
|
||||
ROAD_METADATA_KEYS,
|
||||
clearRouteData,
|
||||
clearComputedRoute,
|
||||
hasComputedRoute,
|
||||
extractNoGoAreas,
|
||||
getBaseLayer,
|
||||
getColorMode,
|
||||
|
|
@ -266,6 +268,28 @@ describe("clearRouteData", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("clearComputedRoute / hasComputedRoute", () => {
|
||||
it("detects computed geometry and clears it while keeping the profile", () => {
|
||||
const { doc, routeData } = createDoc();
|
||||
expect(hasComputedRoute(routeData)).toBe(false);
|
||||
|
||||
writeComputedRoute(doc, routeData, enrichedFixture());
|
||||
setProfile(routeData, "trekking");
|
||||
setColorMode(routeData, "surface");
|
||||
expect(hasComputedRoute(routeData)).toBe(true);
|
||||
|
||||
clearComputedRoute(doc, routeData);
|
||||
|
||||
expect(hasComputedRoute(routeData)).toBe(false);
|
||||
expect(getCoordinates(routeData)).toBeNull();
|
||||
expect(readGeojson(routeData)).toBeUndefined();
|
||||
expect(readRoadMetadata(routeData).surfaces).toEqual([]);
|
||||
// profile (and other prefs) survive — unlike clearRouteData
|
||||
expect(getProfile(routeData)).toBe("trekking");
|
||||
expect(getColorMode(routeData)).toBe("surface");
|
||||
});
|
||||
});
|
||||
|
||||
describe("extractNoGoAreas", () => {
|
||||
it("reads areas and drops degenerate ones", () => {
|
||||
const doc = new Y.Doc();
|
||||
|
|
|
|||
|
|
@ -189,7 +189,12 @@ export function setGeojson(routeData: Y.Map<unknown>, geojson: unknown): void {
|
|||
}
|
||||
|
||||
/** Removes the computed route and profile (view preferences are kept). */
|
||||
export function clearRouteData(doc: Y.Doc, routeData: Y.Map<unknown>): void {
|
||||
/**
|
||||
* Clear the computed route geometry + per-coordinate road metadata, but keep
|
||||
* the routing profile. Used when the route can no longer exist (fewer than two
|
||||
* waypoints) so the stale line stops rendering without resetting the profile.
|
||||
*/
|
||||
export function clearComputedRoute(doc: Y.Doc, routeData: Y.Map<unknown>): void {
|
||||
doc.transact(() => {
|
||||
routeData.delete("geojson");
|
||||
routeData.delete("coordinates");
|
||||
|
|
@ -198,6 +203,17 @@ export function clearRouteData(doc: Y.Doc, routeData: Y.Map<unknown>): void {
|
|||
for (const key of ROAD_METADATA_KEYS) {
|
||||
routeData.delete(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** True if the route data currently holds computed geometry. */
|
||||
export function hasComputedRoute(routeData: Y.Map<unknown>): boolean {
|
||||
return routeData.get("coordinates") !== undefined || routeData.get("geojson") !== undefined;
|
||||
}
|
||||
|
||||
export function clearRouteData(doc: Y.Doc, routeData: Y.Map<unknown>): void {
|
||||
doc.transact(() => {
|
||||
clearComputedRoute(doc, routeData);
|
||||
routeData.delete(PROFILE_KEY);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ import {
|
|||
extractNoGoAreas,
|
||||
getProfile,
|
||||
writeComputedRoute,
|
||||
clearComputedRoute,
|
||||
hasComputedRoute,
|
||||
} from "./route-data.ts";
|
||||
import { extractWaypoints } from "./waypoint-ymap.ts";
|
||||
|
||||
|
|
@ -210,11 +212,22 @@ export function useRouting(yjs: YjsState | null, sessionId: string) {
|
|||
triggerRecompute();
|
||||
};
|
||||
|
||||
// When waypoints drop below two, no route can exist — drop the stale
|
||||
// geometry so the line stops rendering. (Recompute for >=2 is triggered by
|
||||
// the add/move/delete handlers themselves.)
|
||||
const waypointsObserver = () => {
|
||||
if (getWaypointsFromYjs(yjs.waypoints).length < 2 && hasComputedRoute(yjs.routeData)) {
|
||||
clearComputedRoute(yjs.doc, yjs.routeData);
|
||||
}
|
||||
};
|
||||
|
||||
yjs.routeData.observe(profileObserver);
|
||||
yjs.noGoAreas.observeDeep(noGoObserver);
|
||||
yjs.waypoints.observeDeep(waypointsObserver);
|
||||
return () => {
|
||||
yjs.routeData.unobserve(profileObserver);
|
||||
yjs.noGoAreas.unobserveDeep(noGoObserver);
|
||||
yjs.waypoints.unobserveDeep(waypointsObserver);
|
||||
};
|
||||
}, [yjs, isHost, requestRoute]);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue