Commit d5ec5a4
authored
fix(arrows): prevent NaN propagation from zero-length labeled arrows (tldraw#8329)
When arrow endpoints overlap exactly (same position), the arrow has zero
length. If that arrow has a label, NaN values propagate through geometry
→ spatial index → culling, causing all shapes on the canvas to
disappear. Easiest to reproduce with "always snap" on, but can happen in
any scenario where endpoints coincide.
The root cause is `interpolateAlongEdge` computing `invLerp(0, 0, 0)` →
`0/0` → NaN when two vertices are identical. This NaN flows into label
positioning, arrow bounds, page bounds, and ultimately corrupts the
R-tree spatial index, breaking viewport culling for every shape.
This PR fixes the issue at the source and adds defense-in-depth:
- Guard `interpolateAlongEdge` to return the vertex directly when
segment length is 0
- Guard `uninterpolateAlongEdge` to return 0 when total length is 0
- Skip label geometry computation when the arrow is invalid (`isValid
=== false`), since the arrow component already returns null in that case
- Reject NaN bounds from the spatial index R-tree to prevent tree
corruption
### Before
https://github.com/user-attachments/assets/fdac33de-2d06-44f6-9012-edd275d6387f
### After
https://github.com/user-attachments/assets/5d387565-d829-4cd5-93e6-063ce0c9435b
### Change type
- [x] `bugfix`
### Test plan
1. Enable "always snap" in user preferences
2. Create an arrow and add a label to it
3. Drag one endpoint to overlap the other (snap to same grid point)
4. Verify other shapes on canvas remain visible
### Release notes
- Fix all shapes disappearing when a labeled arrow has zero length (e.g.
when both endpoints overlap)
### Code changes
| Section | LOC change |
| ---------- | ---------- |
| Core code | +7 / -4 |1 parent f1cd46b commit d5ec5a4
3 files changed
Lines changed: 7 additions & 6 deletions
File tree
- packages
- editor/src/lib
- editor/managers/SpatialIndexManager
- primitives/geometry
- tldraw/src/lib/shapes/arrow
Lines changed: 4 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
74 | 74 | | |
75 | 75 | | |
76 | 76 | | |
77 | | - | |
| 77 | + | |
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
| |||
101 | 101 | | |
102 | 102 | | |
103 | 103 | | |
104 | | - | |
| 104 | + | |
105 | 105 | | |
106 | 106 | | |
107 | 107 | | |
| |||
125 | 125 | | |
126 | 126 | | |
127 | 127 | | |
128 | | - | |
| 128 | + | |
129 | 129 | | |
130 | 130 | | |
131 | 131 | | |
| |||
145 | 145 | | |
146 | 146 | | |
147 | 147 | | |
148 | | - | |
| 148 | + | |
149 | 149 | | |
150 | 150 | | |
151 | 151 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
191 | 191 | | |
192 | 192 | | |
193 | 193 | | |
| 194 | + | |
194 | 195 | | |
195 | 196 | | |
196 | 197 | | |
| |||
241 | 242 | | |
242 | 243 | | |
243 | 244 | | |
244 | | - | |
| 245 | + | |
245 | 246 | | |
246 | 247 | | |
247 | 248 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
221 | 221 | | |
222 | 222 | | |
223 | 223 | | |
224 | | - | |
| 224 | + | |
225 | 225 | | |
226 | 226 | | |
227 | 227 | | |
| |||
0 commit comments