Tldraw/examples/core-example-advanced/src/shapes/arrow/ArrowUtil.ts

123 wiersze
3.1 KiB
TypeScript

import { TLBounds, Utils } from '@tldraw/core'
import { intersectBoundsLineSegment, intersectLineSegmentLineSegment } from '@tldraw/intersect'
import Vec from '@tldraw/vec'
import { nanoid } from 'nanoid'
import { CustomShapeUtil } from 'shapes/CustomShapeUtil'
import { ArrowComponent } from './ArrowComponent'
import { ArrowIndicator } from './ArrowIndicator'
import type { ArrowShape } from './ArrowShape'
type T = ArrowShape
type E = SVGSVGElement
export class ArrowUtil extends CustomShapeUtil<T, E> {
Component = ArrowComponent
Indicator = ArrowIndicator
hideResizeHandles = true
hideBounds = true
getBounds = (shape: T) => {
const bounds = Utils.getFromCache(this.boundsCache, shape, () => {
const { start, end } = shape.handles
return Utils.getBoundsFromPoints([start.point, end.point])
})
return Utils.translateBounds(bounds, shape.point)
}
/* ----------------- Custom Methods ----------------- */
canBind = false
getShape = (props: Partial<T>): T => {
return {
id: nanoid(),
type: 'arrow',
name: 'arrow',
parentId: 'page1',
point: [0, 0],
handles: {
start: {
id: 'start',
index: 1,
point: [0, 0],
},
end: {
id: 'end',
index: 2,
point: [100, 100],
},
},
childIndex: 1,
...props,
}
}
shouldRender = (prev: T, next: T) => {
return true
}
getCenter = (shape: T) => {
return Utils.getBoundsCenter(this.getBounds(shape))
}
hitTestPoint = (shape: T, point: number[]) => {
const { start, end } = shape.handles
return (
Vec.distanceToLineSegment(
Vec.add(shape.point, start.point),
Vec.add(shape.point, end.point),
point
) < 4
)
}
hitTestLineSegment = (shape: T, A: number[], B: number[]) => {
const { start, end } = shape.handles
return intersectLineSegmentLineSegment(
Vec.add(shape.point, start.point),
Vec.add(shape.point, end.point),
A,
B
).didIntersect
}
hitTestBounds = (shape: T, bounds: TLBounds) => {
const { start, end } = shape.handles
return (
Utils.boundsContain(bounds, this.getBounds(shape)) ||
intersectBoundsLineSegment(
Utils.translateBounds(bounds, Vec.neg(shape.point)),
start.point,
end.point
).length > 0
)
}
transform = (shape: T, bounds: TLBounds, initialShape: T, scale: number[]) => {
const { start, end } = initialShape.handles
const initialBounds = this.getBounds(initialShape)
const nStart = Vec.divV(start.point, [initialBounds.width, initialBounds.height])
const nEnd = Vec.divV(end.point, [initialBounds.width, initialBounds.height])
if (scale[0] < 0) {
const t = nStart[0]
nStart[0] = nEnd[0]
nEnd[0] = t
}
if (scale[1] < 0) {
const t = nStart[1]
nStart[1] = nEnd[1]
nEnd[1] = t
}
shape.point = [bounds.minX, bounds.minY]
shape.handles.start.point = Vec.mulV([bounds.width, bounds.height], nStart)
shape.handles.end.point = Vec.mulV([bounds.width, bounds.height], nEnd)
}
}