feat(edges): Add & export bezierCenter function

This commit is contained in:
Braks
2022-04-04 21:42:48 +02:00
parent e9f4b5f022
commit 18758facbd
2 changed files with 83 additions and 72 deletions
+82 -71
View File
@@ -1,4 +1,4 @@
import { GetBezierPathParams, GetCenterParams, GetSmoothStepPathParams, Position } from '~/types'
import { GetBezierPathParams, GetCenterParams, GetControlWithCurvatureParams, GetSmoothStepPathParams, Position } from '~/types'
const LeftOrRight = [Position.Left, Position.Right]
@@ -36,6 +36,37 @@ export const getCenter = ({
return [centerX, centerY, xOffset, yOffset]
}
function calculateControlOffset(distance: number, curvature: number): number {
if (distance >= 0) {
return 0.5 * distance
} else {
return curvature * 25 * Math.sqrt(-distance)
}
}
function getControlWithCurvature({ pos, x1, y1, x2, y2, c }: GetControlWithCurvatureParams): [number, number] {
let ctX: number, ctY: number
switch (pos) {
case Position.Left:
ctX = x1 - calculateControlOffset(x1 - x2, c)
ctY = y1
break
case Position.Right:
ctX = x1 + calculateControlOffset(x2 - x1, c)
ctY = y1
break
case Position.Top:
ctX = x1
ctY = y1 - calculateControlOffset(y1 - y2, c)
break
case Position.Bottom:
ctX = x1
ctY = y1 + calculateControlOffset(y2 - y1, c)
break
}
return [ctX, ctY]
}
export function getBezierPath({
sourceX,
sourceY,
@@ -44,78 +75,58 @@ export function getBezierPath({
targetY,
targetPosition = Position.Top,
curvature = 0.25,
centerX,
centerY,
}: GetBezierPathParams): string {
const leftAndRight = [Position.Left, Position.Right]
const hasCurvature = curvature > 0
const [_centerX, _centerY] = getCenter({ sourceX, sourceY, targetX, targetY })
const [sourceControlX, sourceControlY] = getControlWithCurvature({
pos: sourcePosition,
x1: sourceX,
y1: sourceY,
x2: targetX,
y2: targetY,
c: curvature,
})
const [targetControlX, targetControlY] = getControlWithCurvature({
pos: targetPosition,
x1: targetX,
y1: targetY,
x2: sourceX,
y2: sourceY,
c: curvature,
})
return `M${sourceX},${sourceY} C${sourceControlX},${sourceControlY} ${targetControlX},${targetControlY} ${targetX},${targetY}`
}
if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) {
const cX = typeof centerX !== 'undefined' ? centerX : _centerX
const distanceX = targetX - sourceX
const absDistanceX = Math.abs(distanceX)
const amtX = (Math.sqrt(absDistanceX) / 2) * (50 * curvature)
let hx1 = cX
let hx2 = cX
if (hasCurvature) {
const sourceAndTargetRight = sourcePosition === Position.Right && targetPosition === Position.Right
const sourceAndTargetLeft = sourcePosition === Position.Left && targetPosition === Position.Left
hx1 = sourceX + amtX
hx2 = targetX - amtX
if (sourceAndTargetLeft) {
hx1 = sourceX - amtX
} else if (sourceAndTargetRight) {
hx2 = targetX + amtX
} else if (sourcePosition === Position.Left && targetX <= sourceX) {
hx1 = cX
hx2 = cX
} else if (sourcePosition === Position.Left && targetX > sourceX) {
hx1 = sourceX - amtX
hx2 = targetX + amtX
}
}
return `M${sourceX},${sourceY} C${hx1},${sourceY} ${hx2},${targetY}, ${targetX},${targetY}`
} else if (leftAndRight.includes(targetPosition)) {
return `M${sourceX},${sourceY} Q${sourceX},${targetY} ${targetX},${targetY}`
} else if (leftAndRight.includes(sourcePosition)) {
return `M${sourceX},${sourceY} Q${targetX},${sourceY} ${targetX},${targetY}`
}
const cY = typeof centerY !== 'undefined' ? centerY : _centerY
const distanceY = targetY - sourceY
const absDistanceY = Math.abs(distanceY)
const amtY = (Math.sqrt(absDistanceY) / 2) * (50 * curvature)
let hy1 = cY
let hy2 = cY
if (hasCurvature) {
hy1 = sourceY + amtY
hy2 = targetY - amtY
const sourceAndTargetTop = sourcePosition === Position.Top && targetPosition === Position.Top
const sourceAndTargetBottom = sourcePosition === Position.Bottom && targetPosition === Position.Bottom
if (sourceAndTargetTop) {
hy1 = targetY - amtY
} else if (sourceAndTargetBottom) {
hy2 = targetY + amtY
} else if (sourcePosition === Position.Top && targetY <= sourceY) {
hy1 = cY
hy2 = cY
} else if (sourcePosition === Position.Top && targetY > sourceY) {
hy1 = sourceY - amtY
hy2 = targetY + amtY
}
}
return `M${sourceX},${sourceY} C${sourceX},${hy1} ${targetX},${hy2} ${targetX},${targetY}`
export function getBezierCenter({
sourceX,
sourceY,
sourcePosition = Position.Bottom,
targetX,
targetY,
targetPosition = Position.Top,
curvature = 0.25,
}: GetBezierPathParams): [number, number, number, number] {
const [sourceControlX, sourceControlY] = getControlWithCurvature({
pos: sourcePosition,
x1: sourceX,
y1: sourceY,
x2: targetX,
y2: targetY,
c: curvature,
})
const [targetControlX, targetControlY] = getControlWithCurvature({
pos: targetPosition,
x1: targetX,
y1: targetY,
x2: sourceX,
y2: sourceY,
c: curvature,
})
// cubic bezier t=0.5 mid point, not the actual mid point, but easy to calculate
// https://stackoverflow.com/questions/67516101/how-to-find-distance-mid-point-of-bezier-curve
const centerX = sourceX * 0.125 + sourceControlX * 0.375 + targetControlX * 0.375 + targetX * 0.125
const centerY = sourceY * 0.125 + sourceControlY * 0.375 + targetControlY * 0.375 + targetY * 0.125
const xOffset = Math.abs(centerX - sourceX)
const yOffset = Math.abs(centerY - sourceY)
return [centerX, centerY, xOffset, yOffset]
}
// These are some helper methods for drawing the round corners
+1 -1
View File
@@ -1,6 +1,6 @@
export { default as VueFlow } from './container/VueFlow/VueFlow.vue'
export { default as Handle } from './components/Handle/Handle.vue'
export { getBezierPath, getSmoothStepPath, getCenter as getEdgeCenter } from './components/Edges/utils'
export { getBezierPath, getSmoothStepPath, getCenter as getEdgeCenter, getBezierCenter } from './components/Edges/utils'
export {
isNode,