fix(edges): align arrow markers with the stroke they terminate - #75
Open
Ken-vdE wants to merge 2 commits into
Open
fix(edges): align arrow markers with the stroke they terminate#75Ken-vdE wants to merge 2 commits into
Ken-vdE wants to merge 2 commits into
Conversation
added 2 commits
August 24, 2026 11:43
Arrowheads pointed somewhere the edge did not, and the stroke poked out of the triangle's side. Two independent causes, both about the path tangent an `orient="auto"` SVG marker reads at its vertex. 1. `getBezierPath` whips into the target handle's normal over the final few pixels: on a real template edge the tangent turns 42 degrees within the last 12px. The marker takes the exact endpoint tangent, and `refX` puts the tip on the endpoint, so the whole triangle sits over curve running a different way. Reserve a straight lead as long as the arrow marker at both endpoints, so the stroke stops where the arrowhead begins and both share one direction. The leads are tangent-continuous with the curve because `getBezierPath` already leaves and enters along the same handle normals. Skipped on edges shorter than 48px. 2. `buildCurvedPath` anchors smooth splines by duplicating the first and last point, which makes d3 emit zero-length commands and cubics whose control points collapse onto the endpoint. The tangent is then zero and browsers fall back to 0 degrees, so ELK-routed and manual-waypoint edges pointed right no matter which way they ran. `normalizeMarkerTangents` strips the degenerate commands and restores a readable tangent; a fully collapsed cubic traces its own chord, so it becomes a `lineTo`. Endpoints are untouched and `basis` output now matches d3's un-anchored tail.
- move test-only tangent readers to a testHelpers module - rebuild plain bezier when the lead splice finds no cubic, so the fallback path still touches the real handles - correct ARROW_LEAD_PX comment: marker lengths vary, 12 approximates
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Arrowheads pointed somewhere the edge did not, and the stroke poked out of the triangle's side. Two independent causes, both about the path tangent an
orient="auto"SVG marker reads at its vertex.getBezierPathwhips into the target handle's normal over the final few pixels: on a real template edge the tangent turns 42 degrees within the last 12px. The marker takes the exact endpoint tangent, andrefXputs the tip on the endpoint, so the whole triangle sits over curve running a different way. Reserve a straight lead as long as the arrow marker at both endpoints, so the stroke stops where the arrowhead begins and both share one direction. The leads are tangent-continuous with the curve becausegetBezierPathalready leaves and enters along the same handle normals. Skipped on edges shorter than 48px.buildCurvedPathanchors smooth splines by duplicating the first and last point, which makes d3 emit zero-length commands and cubics whose control points collapse onto the endpoint. The tangent is then zero and browsers fall back to 0 degrees, so ELK-routed and manual-waypoint edges pointed right no matter which way they ran.normalizeMarkerTangentsstrips the degenerate commands and restores a readable tangent; a fully collapsed cubic traces its own chord, so it becomes alineTo. Endpoints are untouched andbasisoutput now matches d3's un-anchored tail.Before


After