@antv/x6
Version:
JavaScript diagramming library that uses SVG and HTML for rendering
73 lines (61 loc) • 1.89 kB
text/typescript
import { Ellipse, type Rectangle } from '../../geometry'
import type { PortLayoutCommonArgs, PortLayoutDefinition } from './index'
import { toResult } from './util'
export interface EllipseArgs extends PortLayoutCommonArgs {
start?: number
step?: number
compensateRotate?: boolean
/**
* delta radius
*/
dr?: number
}
export const ellipse: PortLayoutDefinition<EllipseArgs> = (
portsPositionArgs,
elemBBox,
groupPositionArgs,
) => {
const startAngle = groupPositionArgs.start || 0
const stepAngle = groupPositionArgs.step || 20
return ellipseLayout(
portsPositionArgs,
elemBBox,
startAngle,
(index, count) => (index + 0.5 - count / 2) * stepAngle,
)
}
export const ellipseSpread: PortLayoutDefinition<EllipseArgs> = (
portsPositionArgs,
elemBBox,
groupPositionArgs,
) => {
const startAngle = groupPositionArgs.start || 0
const stepAngle = groupPositionArgs.step || 360 / portsPositionArgs.length
return ellipseLayout(portsPositionArgs, elemBBox, startAngle, (index) => {
return index * stepAngle
})
}
function ellipseLayout(
portsPositionArgs: EllipseArgs[],
elemBBox: Rectangle,
startAngle: number,
stepFn: (index: number, count: number) => number,
) {
const center = elemBBox.getCenter()
const start = elemBBox.getTopCenter()
const ratio = elemBBox.width / elemBBox.height
const ellipse = Ellipse.fromRect(elemBBox)
const count = portsPositionArgs.length
return portsPositionArgs.map((item, index) => {
const angle = startAngle + stepFn(index, count)
const p = start.clone().rotate(-angle, center).scale(ratio, 1, center)
const theta = item.compensateRotate ? -ellipse.tangentTheta(p) : 0
if (item.dx || item.dy) {
p.translate(item.dx || 0, item.dy || 0)
}
if (item.dr) {
p.move(center, item.dr)
}
return toResult(p.round(), theta, item)
})
}