fix line bugs (#1936)
closes #1913 Some lines aren't rendering: <img width="500" alt="shapes" src="https://github.com/tldraw/tldraw/assets/98838967/bd01bb0f-a967-46ce-9056-a81421224931"> When we begin drawing a line it's nice for the user to be able to see a dot, so we put down two points. The end point for a new line was set to the same position as the first point, which was causing a bunch of divide by zero errors. Offsetting it slightly fixes that. Now when two handles are too close together we extend the second one instead of drawing a third. This will probably only ever happen with the first two points of a line. ### 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. Select the Line tool and set spline to line and dash to draw 2. Click around the canvas 3. You should now be able to actually see a line 4. Now set spline to cubic and dash to solid 5. shift click around the canvas 6. You should be able to see a line! ### Release Notes - This PR patches a couple of bugs which led to straight draw lines and beziered dash lines not rendering on the canvas Before & After: <image width="250" src="https://github.com/tldraw/tldraw/assets/98838967/e0ca7d54-506f-4014-b65a-6b61a98e3665" /> <image width="250" src="https://github.com/tldraw/tldraw/assets/98838967/90c9fa12-1bcb-430d-80c7-97e1faacea16" /> --------- Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
This commit is contained in:
parent
a176522c57
commit
73e61727cc
4 changed files with 40 additions and 26 deletions
|
@ -146,7 +146,7 @@ describe('When extending the line with the shift-key in tool-lock mode', () => {
|
|||
const line = editor.currentPageShapes[editor.currentPageShapes.length - 1]
|
||||
assert(editor.isShapeOfType<TLLineShape>(line, 'line'))
|
||||
const handles = Object.values(line.props.handles)
|
||||
expect(handles.length).toBe(3)
|
||||
expect(handles.length).toBe(2)
|
||||
})
|
||||
|
||||
it('extends a line by shift-click dragging', () => {
|
||||
|
|
|
@ -65,8 +65,8 @@ export class LineShapeUtil extends ShapeUtil<TLLineShape> {
|
|||
canBind: false,
|
||||
canSnap: true,
|
||||
index: 'a2',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x: 0.1,
|
||||
y: 0.1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -243,11 +243,9 @@ export class LineShapeUtil extends ShapeUtil<TLLineShape> {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Cubic style spline
|
||||
if (shape.props.spline === 'cubic') {
|
||||
const splinePath = getSvgPathForLineGeometry(spline)
|
||||
|
||||
if (dash === 'solid') {
|
||||
return (
|
||||
<SVGContainer id={shape.id}>
|
||||
|
|
|
@ -14,6 +14,8 @@ import {
|
|||
structuredClone,
|
||||
} from '@tldraw/editor'
|
||||
|
||||
const MINIMUM_DISTANCE_BETWEEN_SHIFT_CLICKED_HANDLES = 2
|
||||
|
||||
export class Pointing extends StateNode {
|
||||
static override id = 'pointing'
|
||||
|
||||
|
@ -27,9 +29,11 @@ export class Pointing extends StateNode {
|
|||
|
||||
this.markId = undefined
|
||||
|
||||
// Previously created line shape that we might be extending
|
||||
const shape = info.shapeId && this.editor.getShape<TLLineShape>(info.shapeId)
|
||||
|
||||
if (shape && inputs.shiftKey) {
|
||||
// Extending a previous shape
|
||||
this.markId = `creating:${shape.id}`
|
||||
this.editor.mark(this.markId)
|
||||
this.shape = shape
|
||||
|
@ -39,6 +43,7 @@ export class Pointing extends StateNode {
|
|||
|
||||
const vertexHandles = handles.filter((h) => h.type === 'vertex').sort(sortByIndex)
|
||||
const endHandle = vertexHandles[vertexHandles.length - 1]
|
||||
const prevEndHandle = vertexHandles[vertexHandles.length - 2]
|
||||
|
||||
const shapePagePoint = Matrix2d.applyToPoint(
|
||||
this.editor.getShapeParentTransform(this.shape)!,
|
||||
|
@ -47,24 +52,31 @@ export class Pointing extends StateNode {
|
|||
|
||||
let nextEndHandleIndex: string, nextEndHandleId: string, nextEndHandle: TLHandle
|
||||
|
||||
if (vertexHandles.length === 2 && vertexHandles[1].x === 1 && vertexHandles[1].y === 1) {
|
||||
nextEndHandleIndex = vertexHandles[1].index
|
||||
nextEndHandleId = vertexHandles[1].id
|
||||
const nextPoint = Vec2d.Sub(currentPagePoint, shapePagePoint)
|
||||
|
||||
if (
|
||||
Vec2d.Dist(endHandle, prevEndHandle) < MINIMUM_DISTANCE_BETWEEN_SHIFT_CLICKED_HANDLES ||
|
||||
Vec2d.Dist(nextPoint, endHandle) < MINIMUM_DISTANCE_BETWEEN_SHIFT_CLICKED_HANDLES
|
||||
) {
|
||||
// If the end handle is too close to the previous end handle, we'll just extend the previous end handle
|
||||
nextEndHandleIndex = endHandle.index
|
||||
nextEndHandleId = endHandle.id
|
||||
nextEndHandle = {
|
||||
...vertexHandles[1],
|
||||
x: currentPagePoint.x - shapePagePoint.x,
|
||||
y: currentPagePoint.y - shapePagePoint.y,
|
||||
...endHandle,
|
||||
x: nextPoint.x + 0.1,
|
||||
y: nextPoint.y + 0.1,
|
||||
}
|
||||
} else {
|
||||
// Otherwise, we'll create a new end handle
|
||||
nextEndHandleIndex = getIndexAbove(endHandle.index)
|
||||
nextEndHandleId = 'handle:' + nextEndHandleIndex
|
||||
nextEndHandle = {
|
||||
x: currentPagePoint.x - shapePagePoint.x,
|
||||
y: currentPagePoint.y - shapePagePoint.y,
|
||||
index: nextEndHandleIndex,
|
||||
canBind: false,
|
||||
type: 'vertex',
|
||||
id: nextEndHandleId,
|
||||
type: 'vertex',
|
||||
index: nextEndHandleIndex,
|
||||
x: nextPoint.x + 0.1,
|
||||
y: nextPoint.y + 0.1,
|
||||
canBind: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,15 +118,17 @@ export class Pointing extends StateNode {
|
|||
|
||||
if (this.editor.inputs.isDragging) {
|
||||
const handles = this.editor.getShapeHandles(this.shape)
|
||||
console
|
||||
if (!handles) {
|
||||
if (this.markId) this.editor.bailToMark(this.markId)
|
||||
throw Error('No handles found')
|
||||
}
|
||||
|
||||
const lastHandle = last(handles)!
|
||||
this.editor.setCurrentTool('select.dragging_handle', {
|
||||
shape: this.shape,
|
||||
isCreating: true,
|
||||
handle: last(handles)!,
|
||||
// remove the offset that we added to the handle when we created it
|
||||
handle: { ...lastHandle, x: lastHandle.x - 0.1, y: lastHandle.y - 0.1 },
|
||||
onInteractionEnd: 'line',
|
||||
})
|
||||
}
|
||||
|
|
|
@ -110,19 +110,21 @@ export const Toolbar = memo(function Toolbar() {
|
|||
<div className="tlui-toolbar">
|
||||
<div className="tlui-toolbar__inner">
|
||||
<div className="tlui-toolbar__left">
|
||||
{!isReadonly && breakpoint < 6 && !editor.isInAny('hand', 'zoom') && (
|
||||
{!isReadonly && (
|
||||
<div
|
||||
className={classNames('tlui-toolbar__extras', {
|
||||
'tlui-toolbar__extras__hidden': !showExtraActions,
|
||||
})}
|
||||
>
|
||||
<div className="tlui-toolbar__extras__controls">
|
||||
<UndoButton />
|
||||
<RedoButton />
|
||||
<TrashButton />
|
||||
<DuplicateButton />
|
||||
<ActionsMenu />
|
||||
</div>
|
||||
{breakpoint < 6 && !editor.isInAny('hand', 'zoom') && (
|
||||
<div className="tlui-toolbar__extras__controls">
|
||||
<UndoButton />
|
||||
<RedoButton />
|
||||
<TrashButton />
|
||||
<DuplicateButton />
|
||||
<ActionsMenu />
|
||||
</div>
|
||||
)}
|
||||
<ToggleToolLockedButton activeToolId={activeToolId} />
|
||||
</div>
|
||||
)}
|
||||
|
|
Loading…
Reference in a new issue