[fix] Hit testing against zero width / height lines (#2060)

This PR fixes a bug where certain hit tests would always miss straight
lines.

### Change Type

- [x] `patch` — Bug fix

### Test Plan

1. Create a straight line.
2. Try to bind an arrow to it.

- [x] Unit Tests

### Release Notes

- [fix] Bug where arrows would not bind to straight lines
This commit is contained in:
Steve Ruiz 2023-10-10 16:58:02 +01:00 committed by GitHub
parent 8015a7e3d8
commit e77005e507
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 4 deletions

View file

@ -4319,9 +4319,21 @@ export class Editor extends EventEmitter<TLEventMap> {
distance = minDistance
} else {
distance = geometry.bounds.containsPoint(pointInShapeSpace, margin)
? geometry.distanceToPoint(pointInShapeSpace, hitInside)
: Infinity
// If the margin is zero and the geometry has a very small width or height,
// then check the actual distance. This is to prevent a bug where straight
// lines would never pass the broad phase (point-in-bounds) check.
if (margin === 0 && (geometry.bounds.w < 1 || geometry.bounds.h < 1)) {
distance = geometry.distanceToPoint(pointInShapeSpace, hitInside)
} else {
// Broad phase
if (geometry.bounds.containsPoint(pointInShapeSpace, margin)) {
// Narrow phase (actual distance)
distance = geometry.distanceToPoint(pointInShapeSpace, hitInside)
} else {
// Failed the broad phase, geddafugaotta'ere!
distance = Infinity
}
}
}
if (geometry.isClosed) {

View file

@ -1,4 +1,4 @@
import { Vec2d, createShapeId } from '@tldraw/editor'
import { TLArrowShape, Vec2d, createShapeId } from '@tldraw/editor'
import { TestEditor } from '../../../test/TestEditor'
let editor: TestEditor
@ -523,5 +523,29 @@ describe('line bug', () => {
.keyUp('Shift')
expect(editor.currentPageShapes.length).toBe(2)
const arrow = editor.currentPageShapes[1] as TLArrowShape
expect(arrow.props.end.type).toBe('binding')
})
it('works as expected when binding to a straight horizontal line', () => {
editor.selectAll().deleteShapes(editor.selectedShapeIds)
expect(editor.currentPageShapes.length).toBe(0)
editor
.setCurrentTool('line')
.pointerMove(0, 0)
.pointerDown()
.pointerMove(0, 100)
.pointerUp()
.setCurrentTool('arrow')
.pointerMove(50, 50)
.pointerDown()
.pointerMove(0, 50)
.pointerUp()
expect(editor.currentPageShapes.length).toBe(2)
const arrow = editor.currentPageShapes[1] as TLArrowShape
expect(arrow.props.end.type).toBe('binding')
})
})