Files
90-RED 3474927aee v1.3.0 — Web Worker routing, profiler disk export, stretch extraction
- 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
2026-07-19 06:36:24 +08:00

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;
}