From bef6157097bd33f191af08707fc828efc21139c2 Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 17 Mar 2022 13:09:17 +0100 Subject: [PATCH] refactor(bezier): handle undirectional flows, use simple bezier for connection closes #1971 --- src/components/ConnectionLine/index.tsx | 4 +- src/components/Edges/BezierEdge.tsx | 62 ++++++++++++++++++++----- 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/src/components/ConnectionLine/index.tsx b/src/components/ConnectionLine/index.tsx index 4a4db773..7efb1aae 100644 --- a/src/components/ConnectionLine/index.tsx +++ b/src/components/ConnectionLine/index.tsx @@ -105,7 +105,9 @@ export default ({ }; if (connectionLineType === ConnectionLineType.Bezier) { - dAttr = getBezierPath(pathParams); + // @TODO: we need another getBezier function, that handles a connection line. + // Since we don't know the target position, we can't use the default bezier function here. + dAttr = getBezierPath({ ...pathParams, curvature: 0 }); } else if (connectionLineType === ConnectionLineType.Step) { dAttr = getSmoothStepPath({ ...pathParams, diff --git a/src/components/Edges/BezierEdge.tsx b/src/components/Edges/BezierEdge.tsx index 74d87372..36e31486 100644 --- a/src/components/Edges/BezierEdge.tsx +++ b/src/components/Edges/BezierEdge.tsx @@ -15,6 +15,8 @@ export interface GetBezierPathParams { centerY?: number; } +// @TODO: refactor getBezierPath function. It's too long and hard to understand. +// We should reuse the curvature handling for top/bottom and left/right. export function getBezierPath({ sourceX, sourceY, @@ -28,19 +30,36 @@ export function getBezierPath({ }: GetBezierPathParams): string { const leftAndRight = [Position.Left, Position.Right]; const hasCurvature = curvature > 0; - let cX, - cY = 0; - const [_centerX, _centerY] = getCenter({ sourceX, sourceY, targetX, targetY }); if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) { - cX = typeof centerX !== 'undefined' ? centerX : _centerX; + const cX = typeof centerX !== 'undefined' ? centerX : _centerX; const distanceX = targetX - sourceX; - const absDistanceX = Math.abs(Math.min(0, distanceX)); + const absDistanceX = Math.abs(distanceX); const amtX = (Math.sqrt(absDistanceX) / 2) * (50 * curvature); - const hx1 = hasCurvature && distanceX < 0 ? sourceX + amtX : cX; - const hx2 = hasCurvature && distanceX < 0 ? targetX - amtX : cX; + 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)) { @@ -49,14 +68,33 @@ export function getBezierPath({ return `M${sourceX},${sourceY} Q${targetX},${sourceY} ${targetX},${targetY}`; } - cY = typeof centerY !== 'undefined' ? centerY : _centerY; + const cY = typeof centerY !== 'undefined' ? centerY : _centerY; const distanceY = targetY - sourceY; - - const absDistanceY = Math.abs(Math.min(0, distanceY)); + const absDistanceY = Math.abs(distanceY); const amtY = (Math.sqrt(absDistanceY) / 2) * (50 * curvature); - const hy1 = hasCurvature && distanceY < 0 ? sourceY + amtY : cY; - const hy2 = hasCurvature && distanceY < 0 ? targetY - amtY : cY; + 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}`; }