kopia lustrzana https://github.com/Tldraw/Tldraw
improves indicators (roll into arrow shape)
rodzic
6aa58c7966
commit
ffc180fa1c
|
@ -40,8 +40,8 @@ export class Svg {
|
||||||
r,
|
r,
|
||||||
r,
|
r,
|
||||||
0,
|
0,
|
||||||
Utils.getSweep(C, A, B) > 0 ? '1' : '0',
|
|
||||||
0,
|
0,
|
||||||
|
Utils.getArcLength(C, r, A, B) > 0 ? '1' : '0',
|
||||||
B[0],
|
B[0],
|
||||||
B[1],
|
B[1],
|
||||||
].join(' ')
|
].join(' ')
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
Intersect,
|
Intersect,
|
||||||
TLHandle,
|
TLHandle,
|
||||||
TLPointerInfo,
|
TLPointerInfo,
|
||||||
|
Svg,
|
||||||
} from '@tldraw/core'
|
} from '@tldraw/core'
|
||||||
import getStroke from 'perfect-freehand'
|
import getStroke from 'perfect-freehand'
|
||||||
import { defaultStyle, getPerfectDashProps, getShapeStyle } from '~shape/shape-styles'
|
import { defaultStyle, getPerfectDashProps, getShapeStyle } from '~shape/shape-styles'
|
||||||
|
@ -235,57 +236,88 @@ export class Arrow extends TLDrawShapeUtil<ArrowShape> {
|
||||||
|
|
||||||
renderIndicator(shape: ArrowShape) {
|
renderIndicator(shape: ArrowShape) {
|
||||||
const {
|
const {
|
||||||
handles: { start, end },
|
decorations,
|
||||||
bend,
|
handles: { start, end, bend: _bend },
|
||||||
style,
|
style,
|
||||||
} = shape
|
} = shape
|
||||||
|
|
||||||
const path = Utils.getFromCache(this.simplePathCache, shape, () =>
|
const { strokeWidth } = getShapeStyle(style, false)
|
||||||
getArrowArcPath(start, end, getCtp(shape), bend)
|
|
||||||
)
|
|
||||||
const styles = getShapeStyle(style, false)
|
|
||||||
|
|
||||||
const { strokeWidth } = styles
|
|
||||||
|
|
||||||
const arrowDist = Vec.dist(start.point, end.point)
|
const arrowDist = Vec.dist(start.point, end.point)
|
||||||
|
|
||||||
const arrowHeadlength = Math.min(arrowDist / 3, strokeWidth * 8)
|
const arrowHeadlength = Math.min(arrowDist / 3, strokeWidth * 8)
|
||||||
|
|
||||||
let insetStart: number[]
|
const aw = arrowHeadlength / 2
|
||||||
let insetEnd: number[]
|
|
||||||
|
|
||||||
if (bend === 0) {
|
const path: (string | number)[] = []
|
||||||
insetStart = Vec.nudge(start.point, end.point, arrowHeadlength)
|
|
||||||
insetEnd = Vec.nudge(end.point, start.point, arrowHeadlength)
|
const isStraightLine = Vec.dist(_bend.point, Vec.round(Vec.med(start.point, end.point))) < 1
|
||||||
|
|
||||||
|
if (isStraightLine) {
|
||||||
|
path.push(Svg.moveTo(start.point), Svg.lineTo(end.point))
|
||||||
|
|
||||||
|
if (decorations?.start) {
|
||||||
|
const point = start.point
|
||||||
|
const ints = Intersect.circle.lineSegment(start.point, aw, start.point, end.point).points
|
||||||
|
const int = ints[0]
|
||||||
|
|
||||||
|
path.push(
|
||||||
|
Svg.moveTo(Vec.nudge(Vec.rotWith(int, point, Math.PI / 6), point, -aw)),
|
||||||
|
Svg.lineTo(start.point),
|
||||||
|
Svg.lineTo(Vec.nudge(Vec.rotWith(int, point, -Math.PI / 6), point, -aw))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decorations?.end) {
|
||||||
|
const point = end.point
|
||||||
|
const ints = Intersect.circle.lineSegment(end.point, aw, start.point, end.point).points
|
||||||
|
const int = ints[0]
|
||||||
|
|
||||||
|
path.push(
|
||||||
|
Svg.moveTo(Vec.nudge(Vec.rotWith(int, point, Math.PI / 6), point, -aw)),
|
||||||
|
Svg.lineTo(end.point),
|
||||||
|
Svg.lineTo(Vec.nudge(Vec.rotWith(int, point, -Math.PI / 6), point, -aw))
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const circle = getCtp(shape)
|
const circle = getCtp(shape)
|
||||||
|
|
||||||
const arcLength = Utils.getArcLength(
|
|
||||||
[circle[0], circle[1]],
|
|
||||||
circle[2],
|
|
||||||
start.point,
|
|
||||||
end.point
|
|
||||||
)
|
|
||||||
|
|
||||||
const center = [circle[0], circle[1]]
|
const center = [circle[0], circle[1]]
|
||||||
const radius = circle[2]
|
const radius = circle[2]
|
||||||
const sa = Vec.angle(center, start.point)
|
const sweep = Utils.getArcLength(center, radius, start.point, end.point) > 0
|
||||||
const ea = Vec.angle(center, end.point)
|
|
||||||
const t = arrowHeadlength / Math.abs(arcLength)
|
|
||||||
|
|
||||||
insetStart = Vec.nudgeAtAngle(center, Utils.lerpAngles(sa, ea, t), radius)
|
path.push(
|
||||||
insetEnd = Vec.nudgeAtAngle(center, Utils.lerpAngles(ea, sa, t), radius)
|
Svg.moveTo(start.point),
|
||||||
|
`A ${radius} ${radius} 0 0 ${sweep ? '1' : '0'} ${end.point}`
|
||||||
|
)
|
||||||
|
|
||||||
|
if (decorations?.start) {
|
||||||
|
const point = start.point
|
||||||
|
const ints = Intersect.circle.circle(center, radius, point, aw).points
|
||||||
|
const int = sweep ? ints[0] : ints[1]
|
||||||
|
|
||||||
|
path.push(
|
||||||
|
Svg.moveTo(Vec.nudge(Vec.rotWith(int, point, Math.PI / 6), point, -aw)),
|
||||||
|
Svg.lineTo(start.point),
|
||||||
|
Svg.lineTo(Vec.nudge(Vec.rotWith(int, point, -Math.PI / 6), point, -aw))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decorations?.end) {
|
||||||
|
const point = end.point
|
||||||
|
const ints = Intersect.circle.circle(center, radius, point, aw).points
|
||||||
|
const int = sweep ? ints[1] : ints[0]
|
||||||
|
|
||||||
|
path.push(
|
||||||
|
Svg.moveTo(Vec.nudge(Vec.rotWith(int, point, Math.PI / 6), point, -aw)),
|
||||||
|
Svg.lineTo(end.point),
|
||||||
|
Svg.lineTo(Vec.nudge(Vec.rotWith(int, point, -Math.PI / 6), point, -aw))
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g>
|
<g>
|
||||||
<path d={path} />
|
<path d={path.join()} />
|
||||||
{shape.decorations?.start === Decoration.Arrow && (
|
|
||||||
<path d={getArrowHeadPath(shape, start.point, insetStart)} />
|
|
||||||
)}
|
|
||||||
{shape.decorations?.end === Decoration.Arrow && (
|
|
||||||
<path d={getArrowHeadPath(shape, end.point, insetEnd)} />
|
|
||||||
)}
|
|
||||||
</g>
|
</g>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue