Fix an issue with arrow creation. (#2004)

Fixes an issue with creating arrows. Currently we create an arrow that
has both `start` and `end` handles set to the same point. This causes
`NaN` issues in some of our functions / svg rendering. After this change
we only create the arrow after we start dragging, which ensures the
start and the end handle won't have the same coordinates. This probably
feels the best way to approach it: arrow of length 0 doesn't really make
sense.

Resolves [#2005](https://github.com/tldraw/tldraw/issues/2005)

Before


https://github.com/tldraw/tldraw/assets/2523721/6e83c17e-21bd-4e0a-826b-02fad9c21ec6



After


https://github.com/tldraw/tldraw/assets/2523721/29359936-b673-4583-89c8-6d1728ab338c



### Change Type

- [x] `patch` — Bug fix
- [ ] `minor` — New feature
- [ ] `major` — Breaking change
- [ ] `dependencies` — Changes to package dependencies[^1]
- [ ] `documentation` — Changes to the documentation only[^2]
- [ ] `tests` — Changes to any test code only[^2]
- [ ] `internal` — Any other changes that don't affect the published
package[^2]
- [ ] I don't know

[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version

### Test Plan

1. Create an arrow.
2. You should not see any errors in the console.

---------

Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
This commit is contained in:
Mitja Bezenšek 2023-10-03 16:21:07 +02:00 committed by GitHub
parent 4260f499c6
commit f7b325c48c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 25 additions and 6 deletions

View file

@ -227,7 +227,8 @@ export function getCurvedArrowInfo(
)
}
if (Vec2d.Dist(tA, tB) < MIN_ARROW_LENGTH) {
const distAB = Vec2d.Dist(tA, tB)
if (distAB < MIN_ARROW_LENGTH) {
if (offsetA !== 0 && offsetB !== 0) {
offsetA *= -1.5
offsetB *= -1.5
@ -235,6 +236,11 @@ export function getCurvedArrowInfo(
offsetA *= -2
} else if (offsetB !== 0) {
offsetB *= -2
} else {
if (distAB < 10) {
if (startShapeInfo) offsetA = -(10 - distAB)
else if (endShapeInfo) offsetB = -(10 - distAB)
}
}
}

View file

@ -106,7 +106,8 @@ export function getStraightArrowInfo(editor: Editor, shape: TLArrowShape): TLArr
const tA = a.clone().add(u.clone().mul(offsetA * (didFlip ? -1 : 1)))
const tB = b.clone().sub(u.clone().mul(offsetB * (didFlip ? -1 : 1)))
if (Vec2d.Dist(tA, tB) < MIN_ARROW_LENGTH) {
const distAB = Vec2d.Dist(tA, tB)
if (distAB < MIN_ARROW_LENGTH) {
if (offsetA !== 0 && offsetB !== 0) {
offsetA *= -1.5
offsetB *= -1.5
@ -114,6 +115,11 @@ export function getStraightArrowInfo(editor: Editor, shape: TLArrowShape): TLArr
offsetA *= -2
} else if (offsetB !== 0) {
offsetB *= -2
} else {
if (distAB < 10) {
if (startShapeInfo) offsetA = -(10 - distAB)
else if (endShapeInfo) offsetB = -(10 - distAB)
}
}
}

View file

@ -349,7 +349,7 @@ describe('When pointing an end shape', () => {
y: 0,
props: {
start: { type: 'point', x: 0, y: 0 },
end: { type: 'point', x: 0, y: 0 },
end: { type: 'point', x: 2, y: 0 },
},
})

View file

@ -55,6 +55,8 @@ import { ArrowTextLabel } from './components/ArrowTextLabel'
let globalRenderIndex = 0
export const ARROW_END_OFFSET = 0.1
/** @public */
export class ArrowShapeUtil extends ShapeUtil<TLArrowShape> {
static override type = 'arrow' as const
@ -78,7 +80,7 @@ export class ArrowShapeUtil extends ShapeUtil<TLArrowShape> {
labelColor: 'black',
bend: 0,
start: { type: 'point', x: 0, y: 0 },
end: { type: 'point', x: 0, y: 0 },
end: { type: 'point', x: 2, y: 0 },
arrowheadStart: 'none',
arrowheadEnd: 'arrow',
text: '',

View file

@ -127,12 +127,17 @@ export class Pointing extends StateNode {
const handles = this.editor.getShapeHandles(shape)
if (!handles) throw Error(`expected handles for arrow`)
const shapeWithOutEndOffset = {
...shape,
props: { ...shape.props, end: { ...shape.props.end, x: 0, y: 0 } },
}
// end update
{
const util = this.editor.getShapeUtil<TLArrowShape>('arrow')
const point = this.editor.getPointInShapeSpace(shape, this.editor.inputs.currentPagePoint)
const endHandle = handles.find((h) => h.id === 'end')!
const change = util.onHandleChange?.(shape, {
const change = util.onHandleChange?.(shapeWithOutEndOffset, {
handle: { ...endHandle, x: point.x, y: point.y },
isPrecise: false, // sure about that?
})
@ -150,7 +155,7 @@ export class Pointing extends StateNode {
{
const util = this.editor.getShapeUtil<TLArrowShape>('arrow')
const startHandle = handles.find((h) => h.id === 'start')!
const change = util.onHandleChange?.(shape, {
const change = util.onHandleChange?.(shapeWithOutEndOffset, {
handle: { ...startHandle, x: 0, y: 0 },
isPrecise: this.didTimeout, // sure about that?
})