arrows ignore locked shapes (#745)

This commit is contained in:
Steve Ruiz 2022-06-25 12:48:41 +01:00 committed by GitHub
parent 70e3c8bd45
commit 6183c41c18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 93 additions and 51 deletions

View file

@ -54,6 +54,18 @@ describe('Arrow session', () => {
}) })
describe('arrow binding', () => { describe('arrow binding', () => {
it('ignores locked shapes', () => {
const app = new TldrawTestApp()
.loadDocument(restoreDoc)
.select('target1')
.toggleLocked() // set target 1 to locked
.select('arrow1')
.movePointer([200, 200])
.startSession(SessionType.Arrow, 'arrow1', 'start')
.movePointer([50, 50])
expect(app.bindings.length).toBe(0)
})
it('points to the center', () => { it('points to the center', () => {
const app = new TldrawTestApp() const app = new TldrawTestApp()
.loadDocument(restoreDoc) .loadDocument(restoreDoc)
@ -228,7 +240,6 @@ describe('When creating with an arrow session', () => {
) )
.selectTool(TDShapeType.Arrow) .selectTool(TDShapeType.Arrow)
.pointShape('rect1', { x: 251, y: 251 }) .pointShape('rect1', { x: 251, y: 251 })
.movePointer([350, 350])
.movePointer([450, 450]) .movePointer([450, 450])
.completeSession() .completeSession()
@ -240,6 +251,33 @@ describe('When creating with an arrow session', () => {
expect(app.bindings.length).toBe(2) expect(app.bindings.length).toBe(2)
}) })
it('Does not creat a start binding inside of a locked shape', () => {
const app = new TldrawTestApp()
.selectAll()
.delete()
.createShapes(
{
type: TDShapeType.Rectangle,
id: 'rect1',
point: [200, 200],
size: [100, 100],
isLocked: true,
},
{ type: TDShapeType.Rectangle, id: 'rect2', point: [400, 400], size: [100, 100] }
)
.selectTool(TDShapeType.Arrow)
.pointShape('rect1', { x: 251, y: 251 })
.movePointer([450, 450])
.completeSession()
const arrow = app.shapes.find((shape) => shape.type === TDShapeType.Arrow) as ArrowShape
expect(arrow).toBeTruthy()
expect(arrow.handles.start.bindingId).toBe(undefined)
expect(arrow.handles.end.bindingId).toBeTruthy()
expect(app.bindings.length).toBe(1)
})
it('Creates a start binding if started in dead center', () => { it('Creates a start binding if started in dead center', () => {
const app = new TldrawTestApp() const app = new TldrawTestApp()
.selectAll() .selectAll()
@ -396,43 +434,43 @@ describe('When creating arrows inside of other shapes...', () => {
}) })
}) })
describe('When holding alt and dragging a handle', () => { // describe('When holding alt and dragging a handle', () => {
it('Applies a delta to both handles', () => { // it('Applies a delta to both handles', () => {
const app = new TldrawTestApp() // const app = new TldrawTestApp()
.selectAll() // .selectAll()
.delete() // .delete()
.createShapes({ type: TDShapeType.Arrow, id: 'arrow1', point: [0, 0] }) // .createShapes({ type: TDShapeType.Arrow, id: 'arrow1', point: [0, 0] })
.select('arrow1') // .select('arrow1')
.movePointer([0, 0]) // .movePointer([0, 0])
.startSession(SessionType.Arrow, 'arrow1', 'start') // .startSession(SessionType.Arrow, 'arrow1', 'start')
.movePointer([-10, -10]) // .movePointer([-10, -10])
// Without alt... // // Without alt...
expect(app.getShape('arrow1')).toMatchObject({ // expect(app.getShape('arrow1')).toMatchObject({
point: [-10, -10], // point: [-10, -10],
handles: { // handles: {
start: { // start: {
point: [0, 0], // point: [0, 0],
}, // },
end: { // end: {
point: [11, 11], // point: [11, 11],
}, // },
}, // },
}) // })
// With alt... // // With alt...
app.movePointer({ x: -10, y: -10, altKey: true }) // app.movePointer({ x: -10, y: -10, altKey: true })
expect(app.getShape('arrow1')).toMatchObject({ // expect(app.getShape('arrow1')).toMatchObject({
point: [-10, -10], // point: [-10, -10],
handles: { // handles: {
start: { // start: {
point: [0, 0], // point: [0, 0],
}, // },
end: { // end: {
point: [21, 21], // delta is applied to both handles // point: [21, 21], // delta is applied to both handles
}, // },
}, // },
}) // })
}) // })
}) // })

View file

@ -68,8 +68,10 @@ export class ArrowSession extends BaseSession {
// bindable shape under the pointer. // bindable shape under the pointer.
this.startBindingShapeId = this.bindableShapeIds this.startBindingShapeId = this.bindableShapeIds
.map((id) => page.shapes[id]) .map((id) => page.shapes[id])
.filter((shape) => .filter(
Utils.pointInBounds(originPoint, TLDR.getShapeUtil(shape).getBounds(shape)) (shape) =>
!shape.isLocked &&
Utils.pointInBounds(originPoint, TLDR.getShapeUtil(shape).getBounds(shape))
) )
.sort((a, b) => { .sort((a, b) => {
// TODO - We should be smarter here, what's the right logic? // TODO - We should be smarter here, what's the right logic?
@ -144,19 +146,19 @@ export class ArrowSession extends BaseSession {
}, },
} }
if (altKey) { // if (altKey) {
// If the user is holding alt key, apply the inverse delta // // If the user is holding alt key, apply the inverse delta
// to the oppoosite handle. // // to the oppoosite handle.
const oppositeHandleId = handleId === 'start' ? 'end' : 'start' // const oppositeHandleId = handleId === 'start' ? 'end' : 'start'
const nextPoint = Vec.sub(handles[oppositeHandleId].point, delta) // const nextPoint = Vec.sub(handles[oppositeHandleId].point, delta)
handleChanges[oppositeHandleId] = { // handleChanges[oppositeHandleId] = {
...handles[oppositeHandleId], // ...handles[oppositeHandleId],
point: showGrid ? Vec.snap(nextPoint, currentGrid) : Vec.toFixed(nextPoint), // point: showGrid ? Vec.snap(nextPoint, currentGrid) : Vec.toFixed(nextPoint),
bindingId: undefined, // bindingId: undefined,
} // }
} // }
const utils = shapeUtils[TDShapeType.Arrow] const utils = shapeUtils[TDShapeType.Arrow]
const handleChange = utils.onHandleChange?.(initialShape, handleChanges) const handleChange = utils.onHandleChange?.(initialShape, handleChanges)
@ -269,6 +271,7 @@ export class ArrowSession extends BaseSession {
.map((id) => this.app.page.shapes[id]) .map((id) => this.app.page.shapes[id])
.sort((a, b) => b.childIndex - a.childIndex) .sort((a, b) => b.childIndex - a.childIndex)
.filter((shape) => { .filter((shape) => {
if (shape.isLocked) return false
const utils = TLDR.getShapeUtil(shape) const utils = TLDR.getShapeUtil(shape)
return ![startPoint, endPoint].every((point) => utils.hitTestPoint(shape, point)) return ![startPoint, endPoint].every((point) => utils.hitTestPoint(shape, point))
}) })
@ -288,6 +291,7 @@ export class ArrowSession extends BaseSession {
if (draggedBinding) break if (draggedBinding) break
} }
} }
if (draggedBinding) { if (draggedBinding) {
// Create the dragged point binding // Create the dragged point binding
this.didBind = true this.didBind = true