sanity
Version:
Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches
154 lines (142 loc) • 4.71 kB
text/typescript
import {
ARROW_MARGIN_X,
ARROW_MARGIN_Y,
ARROW_SIZE,
ARROW_THRESHOLD,
CORNER_RADIUS,
} from '../constants'
import {type ConnectorLine} from './types'
export function arrowPath(x: number, y: number, dir: number): string {
return [
`M ${x - ARROW_SIZE} ${y - ARROW_SIZE * dir} `,
`L ${x} ${y}`,
`L ${x + ARROW_SIZE} ${y - ARROW_SIZE * dir}`,
].join('')
}
function moveTo(x: number, y: number) {
return `M${x} ${y}`
}
function lineTo(x: number, y: number) {
return `L${x} ${y}`
}
function join(strings: string[], delim = '') {
return strings.join(delim)
}
function quadCurve(x1: number, y1: number, x: number, y: number) {
return `Q${x1} ${y1} ${x} ${y}`
}
export function generateConnectorPath(line: ConnectorLine): string {
const {from, to} = line
const {left: fromX, top: fromY} = from
const {left: toX, top: toY} = to
const cmds: string[] = []
// Calculate maximum corner radius
const r1 = Math.min(CORNER_RADIUS, Math.abs(fromY - toY) / 2)
// FROM
if (from.isAbove) {
cmds.push(
moveTo(fromX + ARROW_MARGIN_X, fromY - ARROW_THRESHOLD + ARROW_MARGIN_Y),
lineTo(fromX + ARROW_MARGIN_X, fromY - CORNER_RADIUS),
quadCurve(fromX + ARROW_MARGIN_X, fromY, fromX + ARROW_MARGIN_X + CORNER_RADIUS, fromY),
)
} else if (from.isBelow) {
cmds.push(
moveTo(fromX + ARROW_MARGIN_X, fromY + ARROW_THRESHOLD - ARROW_MARGIN_Y),
lineTo(fromX + ARROW_MARGIN_X, fromY + CORNER_RADIUS),
quadCurve(fromX + ARROW_MARGIN_X, fromY, fromX + ARROW_MARGIN_X + CORNER_RADIUS, fromY),
)
} else {
cmds.push(moveTo(fromX, fromY))
}
// TO
if (to.isAbove) {
if (fromY < to.bounds.top) {
cmds.push(
lineTo(to.bounds.left - 8 - r1, fromY),
quadCurve(to.bounds.left - 8, fromY, to.bounds.left - 8, fromY + r1),
lineTo(to.bounds.left - 8, toY - r1),
quadCurve(to.bounds.left - 8, toY, to.bounds.left - 8 + r1, toY),
lineTo(to.bounds.left + ARROW_MARGIN_X - CORNER_RADIUS, toY),
quadCurve(
to.bounds.left + ARROW_MARGIN_X,
toY,
to.bounds.left + ARROW_MARGIN_X,
toY - CORNER_RADIUS,
),
lineTo(to.bounds.left + ARROW_MARGIN_X, toY - ARROW_THRESHOLD + ARROW_MARGIN_Y),
)
} else {
cmds.push(
lineTo(to.bounds.left + ARROW_MARGIN_X - CORNER_RADIUS, fromY),
quadCurve(
to.bounds.left + ARROW_MARGIN_X,
fromY,
to.bounds.left + ARROW_MARGIN_X,
fromY - CORNER_RADIUS,
),
lineTo(to.bounds.left + ARROW_MARGIN_X, toY - ARROW_THRESHOLD + ARROW_MARGIN_Y),
)
}
} else if (to.isBelow) {
if (fromY > to.bounds.top + to.bounds.height) {
// curl around
cmds.push(
lineTo(to.bounds.left - ARROW_MARGIN_X - r1, fromY),
quadCurve(
to.bounds.left - ARROW_MARGIN_X,
fromY,
to.bounds.left - ARROW_MARGIN_X,
fromY - r1,
),
lineTo(to.bounds.left - ARROW_MARGIN_X, toY + r1),
quadCurve(to.bounds.left - ARROW_MARGIN_X, toY, to.bounds.left - ARROW_MARGIN_X + r1, toY),
lineTo(to.bounds.left + ARROW_MARGIN_X - CORNER_RADIUS, toY),
quadCurve(
to.bounds.left + ARROW_MARGIN_X,
toY,
to.bounds.left + ARROW_MARGIN_X,
toY + CORNER_RADIUS,
),
lineTo(to.bounds.left + ARROW_MARGIN_X, toY + ARROW_THRESHOLD - ARROW_MARGIN_Y),
)
} else {
cmds.push(
lineTo(to.bounds.left + ARROW_MARGIN_X - CORNER_RADIUS, fromY),
quadCurve(
to.bounds.left + ARROW_MARGIN_X,
fromY,
to.bounds.left + ARROW_MARGIN_X,
fromY + CORNER_RADIUS,
),
lineTo(to.bounds.left + ARROW_MARGIN_X, toY + ARROW_THRESHOLD - ARROW_MARGIN_Y),
)
}
} else if (fromY < toY) {
cmds.push(
lineTo(to.bounds.left + ARROW_MARGIN_X - r1, fromY),
quadCurve(
to.bounds.left + ARROW_MARGIN_X,
fromY,
to.bounds.left + ARROW_MARGIN_X,
fromY + r1,
),
lineTo(to.bounds.left + ARROW_MARGIN_X, toY - r1),
quadCurve(to.bounds.left + ARROW_MARGIN_X, toY, to.bounds.left + ARROW_MARGIN_X + r1, toY),
lineTo(toX, toY),
)
} else {
cmds.push(
lineTo(to.bounds.left + ARROW_MARGIN_X - r1, fromY),
quadCurve(
to.bounds.left + ARROW_MARGIN_X,
fromY,
to.bounds.left + ARROW_MARGIN_X,
fromY - r1,
),
lineTo(to.bounds.left + ARROW_MARGIN_X, toY + r1),
quadCurve(to.bounds.left + ARROW_MARGIN_X, toY, to.bounds.left + ARROW_MARGIN_X + r1, toY),
lineTo(toX, toY),
)
}
return join(cmds)
}