fix: flipping and resizing arrows (#979)
* fix: flipping horizontal for arrows * fix: horizontal flip * fix return * add test for flipping arrow * visualize arc points * adding test for vertically flipping * remove arc points Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
This commit is contained in:
parent
8e55e263bf
commit
4ea39a0263
3 changed files with 86 additions and 13 deletions
|
@ -1,5 +1,5 @@
|
|||
import { TldrawTestApp, mockDocument } from '~test'
|
||||
import type { RectangleShape } from '~types'
|
||||
import { ArrowShape, RectangleShape, TDShapeType } from '~types'
|
||||
|
||||
describe('Flip command', () => {
|
||||
const app = new TldrawTestApp()
|
||||
|
@ -107,4 +107,70 @@ describe('Flip command', () => {
|
|||
expect(app.getShape<RectangleShape>('rect1').point).toStrictEqual([0, 0])
|
||||
expect(app.getShape<RectangleShape>('rect2').point).toStrictEqual([100, 100])
|
||||
})
|
||||
it('flip curved arrow horizontally', () => {
|
||||
app.createShapes({
|
||||
id: 'arrow1',
|
||||
type: TDShapeType.Arrow,
|
||||
bend: -0.5464405676717543,
|
||||
handles: {
|
||||
start: {
|
||||
bindingId: undefined,
|
||||
canBind: true,
|
||||
id: 'start',
|
||||
index: 0,
|
||||
point: [-13, 107],
|
||||
},
|
||||
end: {
|
||||
bindingId: undefined,
|
||||
canBind: true,
|
||||
id: 'end',
|
||||
index: 1,
|
||||
point: [388, 112],
|
||||
},
|
||||
bend: {
|
||||
id: 'bend',
|
||||
index: 2,
|
||||
point: [185, -0],
|
||||
},
|
||||
},
|
||||
point: [1877, 677],
|
||||
})
|
||||
app.select('arrow1')
|
||||
app.flipHorizontal()
|
||||
expect(app.getShape<ArrowShape>('arrow1').point).toStrictEqual([1864, 677.19])
|
||||
expect(app.getShape<ArrowShape>('arrow1').handles.bend.point).toStrictEqual([214.87, 219.06])
|
||||
})
|
||||
it('flip arrow vertically', () => {
|
||||
app.createShapes({
|
||||
id: 'arrow1',
|
||||
type: TDShapeType.Arrow,
|
||||
bend: -0.5464405676717543,
|
||||
handles: {
|
||||
start: {
|
||||
bindingId: undefined,
|
||||
canBind: true,
|
||||
id: 'start',
|
||||
index: 0,
|
||||
point: [-13, 107],
|
||||
},
|
||||
end: {
|
||||
bindingId: undefined,
|
||||
canBind: true,
|
||||
id: 'end',
|
||||
index: 1,
|
||||
point: [388, 112],
|
||||
},
|
||||
bend: {
|
||||
id: 'bend',
|
||||
index: 2,
|
||||
point: [185, -0],
|
||||
},
|
||||
},
|
||||
point: [1877, 677],
|
||||
})
|
||||
app.select('arrow1')
|
||||
app.flipVertical()
|
||||
expect(app.getShape<ArrowShape>('arrow1').point).toStrictEqual([1864, 677.19])
|
||||
expect(app.getShape<ArrowShape>('arrow1').handles.bend.point).toStrictEqual([186.13, -107.25])
|
||||
})
|
||||
})
|
||||
|
|
|
@ -376,7 +376,10 @@ export class ArrowUtil extends TDShapeUtil<T, E> {
|
|||
const initialShapeBounds = this.getBounds(initialShape)
|
||||
const handles: (keyof T['handles'])[] = ['start', 'end']
|
||||
const nextHandles = { ...initialShape.handles }
|
||||
|
||||
handles.forEach((handle) => {
|
||||
if (handle === 'bend') return
|
||||
|
||||
const [x, y] = nextHandles[handle].point
|
||||
const nw = x / initialShapeBounds.width
|
||||
const nh = y / initialShapeBounds.height
|
||||
|
@ -388,19 +391,22 @@ export class ArrowUtil extends TDShapeUtil<T, E> {
|
|||
],
|
||||
}
|
||||
})
|
||||
const { start, bend, end } = nextHandles
|
||||
const dist = Vec.dist(start.point, end.point)
|
||||
const midPoint = Vec.med(start.point, end.point)
|
||||
const bendDist = (dist / 2) * initialShape.bend
|
||||
const u = Vec.uni(Vec.vec(start.point, end.point))
|
||||
const point = Vec.add(midPoint, Vec.mul(Vec.per(u), bendDist))
|
||||
nextHandles['bend'] = {
|
||||
...bend,
|
||||
point: Vec.toFixed(Math.abs(bendDist) < 10 ? midPoint : point),
|
||||
}
|
||||
|
||||
// If we've flipped one of the dimensions (but not both) then invert shape.bend
|
||||
|
||||
const nextBend =
|
||||
(scaleX > 0 && scaleY < 0) || (scaleX < 0 && scaleY > 0)
|
||||
? -initialShape.bend
|
||||
: initialShape.bend
|
||||
|
||||
// Find the position of the bend handle based on the new start / end handles and the new bend
|
||||
const bendPoint = getBendPoint(nextHandles, nextBend)
|
||||
nextHandles.bend.point = bendPoint
|
||||
|
||||
return {
|
||||
point: Vec.toFixed([bounds.minX, bounds.minY]),
|
||||
handles: nextHandles,
|
||||
bend: nextBend, // does this change?
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -195,8 +195,9 @@ export function getArcPoints(start: number[], bend: number[], end: number[]) {
|
|||
const radius = circle[2]
|
||||
const startAngle = Vec.angle(center, start)
|
||||
const endAngle = Vec.angle(center, end)
|
||||
for (let i = 1 / 20; i < 1; i += 1 / 20) {
|
||||
const angle = Utils.lerpAngles(startAngle, endAngle, i)
|
||||
for (let i = 0; i < 20; i++) {
|
||||
const t = i / 19
|
||||
const angle = Utils.lerpAngles(startAngle, endAngle, t)
|
||||
points.push(Vec.nudgeAtAngle(center, angle, radius))
|
||||
}
|
||||
return points
|
||||
|
|
Loading…
Reference in a new issue