- Web Worker routing — A* search runs in a background Worker thread, keeping the UI responsive during large batch routes - Worker watchdog — auto-falls back to main-thread routing on any failure - Worker held-pause — drag-pause re-routes also run in worker - stretch.js — extracted sticky-path logic, shared by main thread and worker - Profiler disk export — POST /linkrouter/write_log endpoint saves reports - Chunked worker processing — 8ms macrotask slices for cancel responsiveness - New settings: Background worker routing, Held-pause in worker
49 lines
2.0 KiB
JavaScript
49 lines
2.0 KiB
JavaScript
// stretch.js — endpoint-following "sticky" path stretch, shared by the main
|
|
// thread (drag/sync routing, fresh M.router) and the router worker (its own
|
|
// fresh OrthoRouter instance). Pure aside from the passed-in router.
|
|
|
|
import { stretchedPathCrossesUnexpectedNode } from "./router.js";
|
|
|
|
// Try to keep a previously routed path on screen by re-attaching its ends to
|
|
// the current endpoints. Returns null when the stretch would leave the
|
|
// orthogonal family or cross an unexpected node body — callers must then fall
|
|
// back to a full search (or draw nothing).
|
|
export function stretchPathPure(router, oldPts, ep) {
|
|
if (!oldPts || oldPts.length < 4) return null;
|
|
const pts = oldPts.map((p) => ({ x: p.x, y: p.y }));
|
|
const oldN = pts.length;
|
|
pts[0] = ep.out;
|
|
pts[1] = { x: ep.stubOut.x, y: ep.stubOut.y };
|
|
pts[oldN - 1] = ep.inp;
|
|
pts[oldN - 2] = { x: ep.stubIn.x, y: ep.stubIn.y };
|
|
|
|
// A formerly straight four-point connector becomes diagonal when one end
|
|
// moves vertically. Insert a temporary centre dogleg so it can remain
|
|
// sticky instead of invoking A* on every drag frame.
|
|
if (
|
|
oldN === 4 &&
|
|
Math.abs(pts[1].x - pts[2].x) > 0.6 &&
|
|
Math.abs(pts[1].y - pts[2].y) > 0.6
|
|
) {
|
|
const mx = (pts[1].x + pts[2].x) / 2;
|
|
pts.splice(2, 0, { x: mx, y: pts[1].y }, { x: mx, y: pts[2].y });
|
|
} else if (oldN >= 5) {
|
|
const n = pts.length;
|
|
const a = pts[1], b = pts[2];
|
|
if (Math.abs(oldPts[1].y - oldPts[2].y) < 0.6) b.y = a.y;
|
|
else b.x = a.x;
|
|
const y = pts[n - 2], z = pts[n - 3];
|
|
if (Math.abs(oldPts[n - 2].y - oldPts[n - 3].y) < 0.6) z.y = y.y;
|
|
else z.x = y.x;
|
|
}
|
|
for (let k = 0; k < pts.length - 1; k++) {
|
|
if (Math.abs(pts[k].x - pts[k + 1].x) > 0.6 && Math.abs(pts[k].y - pts[k + 1].y) > 0.6)
|
|
return null;
|
|
}
|
|
const raw = router.raw || [];
|
|
const sourceIndex = router._endpointRectIndex(ep.bodyOut, ep.stubOut, true);
|
|
const targetIndex = router._endpointRectIndex(ep.bodyIn, ep.stubIn, false);
|
|
if (stretchedPathCrossesUnexpectedNode(pts, raw, sourceIndex, targetIndex)) return null;
|
|
return pts;
|
|
}
|