Plan-graph round 13 (owner): arrowheads point again — no zero-length final segment

Round-12 regression: manually repeating the mouth point as a control
point made d3 emit a degenerate final path command (a zero-length L).
orient="auto" derives the marker angle from the direction of the LAST
path segment; a zero-length segment has none, so every head fell back
to 0° — pointing right. Fix: drop the manual repeat — curveBasis already
repeats the endpoint internally, so controls ending [Q, M] keep the
exact end tangent (the approach direction) AND a real final segment
(the straight Q→M stub). Left a comment in edgePathD so this never
regresses again.
This commit is contained in:
amosblomqvist
2026-09-14 07:56:01 +03:00
parent 847caf48d3
commit d7790f895e
+8 -5
View File
@@ -248,13 +248,16 @@ export function edgePathD(points: Array<{ x: number; y: number }>): string {
// The mouth: tip overhang + the docking gap back from the border. // The mouth: tip overhang + the docking gap back from the border.
const back = HEAD_TIP_OVERHANG + DOCK_GAP; const back = HEAD_TIP_OVERHANG + DOCK_GAP;
const M = { x: last.x - ux * back, y: last.y - uy * back }; const M = { x: last.x - ux * back, y: last.y - uy * back };
// From Q every control point lies on the approach line — the basis // From Q the control points lie on the approach line — the basis
// spline renders Q→M perfectly straight (a B-spline span with // spline renders Q→M perfectly straight (a B-spline span with
// collinear control points IS the line), and the repeated M makes // collinear control points IS the line), and curveBasis's internal
// the end tangent exactly the approach direction, so the head // endpoint repetition makes the end tangent exactly the approach
// squares onto its shaft. // direction. NOTE: do NOT repeat M manually — a duplicated final
// control point renders a zero-length last segment, and
// orient="auto" on a zero-length segment falls back to 0° (every
// head pointing right — the round-12 regression, fixed round 13).
const Q = { x: M.x - ux * STRAIGHT_RUN, y: M.y - uy * STRAIGHT_RUN }; const Q = { x: M.x - ux * STRAIGHT_RUN, y: M.y - uy * STRAIGHT_RUN };
pts.splice(pts.length - 1, 1, Q, M, M); pts.splice(pts.length - 1, 1, Q, M);
} }
return edgeLine(pts) ?? ""; return edgeLine(pts) ?? "";
} }