@antv/x6
Version:
JavaScript diagramming library that uses SVG and HTML for rendering
143 lines (125 loc) • 4.08 kB
text/typescript
import type { RouterDefinition } from './index'
export interface ErRouterOptions {
min?: number
offset?: number | 'center'
direction?: 'T' | 'B' | 'L' | 'R' | 'H' | 'V'
}
export const er: RouterDefinition<ErRouterOptions> = (
vertices,
options,
edgeView,
) => {
const offsetRaw = options.offset || 32
const min = options.min == null ? 16 : options.min
let offset = 0
let direction = options.direction
const sourceBBox = edgeView.sourceBBox
const targetBBox = edgeView.targetBBox
const sourcePoint = sourceBBox.getCenter()
const targetPoint = targetBBox.getCenter()
if (typeof offsetRaw === 'number') {
offset = offsetRaw
}
if (direction == null) {
let dx = targetBBox.left - sourceBBox.right
let dy = targetBBox.top - sourceBBox.bottom
if (dx >= 0 && dy >= 0) {
direction = dx >= dy ? 'L' : 'T'
} else if (dx <= 0 && dy >= 0) {
dx = sourceBBox.left - targetBBox.right
if (dx >= 0) {
direction = dx >= dy ? 'R' : 'T'
} else {
direction = 'T'
}
} else if (dx >= 0 && dy <= 0) {
dy = sourceBBox.top - targetBBox.bottom
if (dy >= 0) {
direction = dx >= dy ? 'L' : 'B'
} else {
direction = 'L'
}
} else {
dx = sourceBBox.left - targetBBox.right
dy = sourceBBox.top - targetBBox.bottom
if (dx >= 0 && dy >= 0) {
direction = dx >= dy ? 'R' : 'B'
} else if (dx <= 0 && dy >= 0) {
direction = 'B'
} else if (dx >= 0 && dy <= 0) {
direction = 'R'
} else {
direction = Math.abs(dx) > Math.abs(dy) ? 'R' : 'B'
}
}
}
if (direction === 'H') {
direction = targetPoint.x - sourcePoint.x >= 0 ? 'L' : 'R'
} else if (direction === 'V') {
direction = targetPoint.y - sourcePoint.y >= 0 ? 'T' : 'B'
}
if (offsetRaw === 'center') {
if (direction === 'L') {
offset = (targetBBox.left - sourceBBox.right) / 2
} else if (direction === 'R') {
offset = (sourceBBox.left - targetBBox.right) / 2
} else if (direction === 'T') {
offset = (targetBBox.top - sourceBBox.bottom) / 2
} else if (direction === 'B') {
offset = (sourceBBox.top - targetBBox.bottom) / 2
}
}
let coord: 'x' | 'y'
let dim: 'width' | 'height'
let factor
const horizontal = direction === 'L' || direction === 'R'
if (horizontal) {
if (targetPoint.y === sourcePoint.y) {
return [...vertices]
}
factor = direction === 'L' ? 1 : -1
coord = 'x'
dim = 'width'
} else {
if (targetPoint.x === sourcePoint.x) {
return [...vertices]
}
factor = direction === 'T' ? 1 : -1
coord = 'y'
dim = 'height'
}
const source = sourcePoint.clone()
const target = targetPoint.clone()
source[coord] += factor * (sourceBBox[dim] / 2 + offset)
target[coord] -= factor * (targetBBox[dim] / 2 + offset)
if (horizontal) {
const sourceX = source.x
const targetX = target.x
const sourceDelta = sourceBBox.width / 2 + min
const targetDelta = targetBBox.width / 2 + min
if (targetPoint.x > sourcePoint.x) {
if (targetX <= sourceX) {
source.x = Math.max(targetX, sourcePoint.x + sourceDelta)
target.x = Math.min(sourceX, targetPoint.x - targetDelta)
}
} else if (targetX >= sourceX) {
source.x = Math.min(targetX, sourcePoint.x - sourceDelta)
target.x = Math.max(sourceX, targetPoint.x + targetDelta)
}
} else {
const sourceY = source.y
const targetY = target.y
const sourceDelta = sourceBBox.height / 2 + min
const targetDelta = targetBBox.height / 2 + min
if (targetPoint.y > sourcePoint.y) {
if (targetY <= sourceY) {
source.y = Math.max(targetY, sourcePoint.y + sourceDelta)
target.y = Math.min(sourceY, targetPoint.y - targetDelta)
}
} else if (targetY >= sourceY) {
source.y = Math.min(targetY, sourcePoint.y - sourceDelta)
target.y = Math.max(sourceY, targetPoint.y + targetDelta)
}
}
return [source.toJSON(), ...vertices, target.toJSON()]
}