Repository navigation
feat: elbow (orthogonal) arrows — Straight | Elbow arrow type - #111
Merged
Merged
Conversation
Adds right-angle connectors like eraser.io. The arrow's connector generalises from a straight line to an orthogonally-routed polyline, chosen via a new Arrow-type toggle (Straight | Elbow, default straight); it composes with binding — a bound elbow arrow re-routes its right-angle path edge-to-edge as boxes move. - arrowEndpoints: elbowRoute (mid-bend Z), layoutElbowPolyline (pin left/top to pathOffset so points render at exact group-local coords), polyline-aware localEndpoints + applyEndpointsLocal (head aims along the last segment), exported sceneEndpoints. - shapeLabel: isArrow/getArrowParts accept a line OR polyline connector; new isElbowArrow. - arrow.js: buildArrowGroup builds the polyline connector for elbow and re-lays it in group-local space; new rebuildArrow centralises rebuilds (panel + resize) preserving heads/type/label/bindings and handling both connectors. - toolStyle: arrowType default + ARROW_TYPE_OPTIONS; PropertiesPanel: Arrow-type control + setArrowType (rebuild selected arrow); canvas.currentArrowType. - binding: endpoint helper delegates to sceneEndpoints (elbow-safe). - arrowResizeHandler routes through rebuildArrow. - Tests: elbowRoute geometry + isElbowArrow (79 total). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Deploying whiteboard with
|
| Latest commit: |
bc13abc
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://b7f1c42f.whiteboard-988.pages.dev |
| Branch Preview URL: | https://feat-elbow-arrows.whiteboard-988.pages.dev |
- The highlight is now an additional border layer ON the target's exact outline (no padding), shape-aware: an ellipse target gets an ellipse outline, a rounded rect matches its corner radius — instead of a padded rounded box. - Trigger distance BIND_MARGIN 24 -> 8, so the shape highlights/binds when the endpoint is on the border, not while it's still ~24px away. - (Draw already highlights BOTH source and destination; verified with the exact overlay.) Icons remain limited by their own transparent bbox padding. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…udged off Two binding glitches: - The arrowhead's centre was placed at the endpoint, so its tip vertex overshot by half the head length and poked inside a bound shape. Back the centre off along the incoming segment (headCenterFor) so the visible tip lands exactly on the endpoint — for straight + elbow, live preview + final. - Moving/nudging a bound arrow dragged its bound end off into empty space (it "went to a different position"). Reroute the arrow on object:modified so bound ends snap back onto their shapes; the free end keeps the drag. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The re-glue-on-move handler also fired for endpoint drags (object:modified carries action "arrowEndpoint"), and it ran BEFORE arrow:endpoint:up — so it snapped a just-dragged-off endpoint back onto the shape, and the up handler then re-detected the shape and rebound it. Net effect: a bound end could never be unbound. Skip the reroute for endpoint-drag modifications; the endpoint drag already owns its own (un)binding via arrow:endpoint:up. Whole-arrow moves (action "drag") still re-glue as before. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ect move Three binding/arrow glitches from the video: 1. Line poked past the arrowhead tip. The connector ran all the way to the tip vertex, where the triangle narrows to a point, so the line's width showed through. The connector now stops at the head CENTRE (hidden under the head); the head's tip vertex becomes the logical endpoint (localEndpoints reads it), so controls/binding still use the true tip. Applies to straight + elbow and the live draw preview. 2. Moving a bound arrow snapped it back to the shape. A whole-arrow move now re-evaluates each bound end where it lands: still over its shape -> stay glued (a tiny nudge won't float); dragged off -> unbind and stay put; dropped on another shape -> rebind. So an arrow can be moved away instead of springing back. 3. Arrows didn't follow a multi-select drag. onShapeChange ignored activeSelection; now it fans out to every selected shape. And a shape inside an activeSelection reports selection-RELATIVE coords, so sceneBBox transforms the bbox by the group matrix to recover absolute scene coords — otherwise the re-routed arrow jumped to the origin. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…k gap Dragging a bound arrow's body let the arrowhead follow the cursor into the shape, then snapped it back to the border on release — leaving a gap between the cursor and the arrowhead. Now the bound end is re-glued to its shape's border LIVE on every object:moving frame, so the head stays on the shape as you drag (the free end follows) and there's no jump on drop. To keep the live re-glue from fighting fabric's own translate of the dragged group, setArrowEndpoints/rerouteArrow take a refit flag: mid-drag we reposition only the children (refit=false); bounds are re-fitted once on drop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
borderPoint clipped the centre->target ray to the shape's bounding box, which is exact for rectangles but for a diamond/hexagon lands in the corner gap between the bbox and the slanted edge — so the arrowhead floated outside the shape. Polygons now use a ray-polygon intersection against their actual edges (group- aware, so it also works mid multi-select drag), falling back to the bbox clip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
The eraser.io look you referenced: right-angle connectors. Stacked on #110 (binding) so bound elbow arrows compose.
What changed
lineto an orthogonally-routedpolyline:elbowRoute— a clean mid-bend Z (routes along the dominant axis first, right angles at each bend; collapses to straight when aligned).layoutElbowPolyline— pins the polyline'sleft/topto itspathOffsetso points render at exact group-local coords (the fabric.Polyline positioning gotcha, de-risked in-browser first).applyEndpointsLocal/localEndpoints/sceneEndpointsare now connector-agnostic; the head aims along the last route segment.isArrow/getArrowPartsaccept a line or polyline; newisElbowArrow.rebuildArrowcentralises every arrow rebuild (panel head/type changes + resize handler), preserving heads / straight-vs-elbow / label / bindings and handling both connector kinds.Test plan
elbowRoutegeometry (H-then-V-then-H, mid-y bend, straight collapse, all segments axis-aligned);isElbowArrowtrue/false; existing arrow/endpoint/binding suites unchanged.Follow-ups (deferred)
Stack
master → #104 → #106 → #108 → #105 (binding) → this.🤖 Generated with Claude Code