diff --git a/src/components/Edges/utils.ts b/src/components/Edges/utils.ts index 6ec2acef..de75a9ee 100644 --- a/src/components/Edges/utils.ts +++ b/src/components/Edges/utils.ts @@ -43,40 +43,93 @@ export function getBezierPath({ targetX, targetY, targetPosition = Position.Top, + curvature = 0.25, centerX, centerY, }: GetBezierPathParams): string { - const [_centerX, _centerY] = getCenter({ sourceX, sourceY, targetX, targetY }) const leftAndRight = [Position.Left, Position.Right] - - const cX = typeof centerX !== 'undefined' ? centerX : _centerX - const cY = typeof centerY !== 'undefined' ? centerY : _centerY - - let path = `M${sourceX},${sourceY} C${sourceX},${cY} ${targetX},${cY} ${targetX},${targetY}` + const hasCurvature = curvature > 0 + const [_centerX, _centerY] = getCenter({ sourceX, sourceY, targetX, targetY }) if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) { - path = `M${sourceX},${sourceY} C${cX},${sourceY} ${cX},${targetY} ${targetX},${targetY}` + 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)) { - path = `M${sourceX},${sourceY} Q${sourceX},${targetY} ${sourceX},${targetY} ${targetX},${targetY}` + return `M${sourceX},${sourceY} Q${sourceX},${targetY} ${targetX},${targetY}` } else if (leftAndRight.includes(sourcePosition)) { - path = `M${sourceX},${sourceY} Q${targetX},${sourceY} ${targetX},${sourceY} ${targetX},${targetY}` + return `M${sourceX},${sourceY} Q${targetX},${sourceY} ${targetX},${targetY}` } - return path + 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}` } // These are some helper methods for drawing the round corners // The name indicates the direction of the path. "bottomLeftCorner" goes // from bottom to the left and "leftBottomCorner" goes from left to the bottom. // We have to consider the direction of the paths because of the animated lines. -export const bottomLeftCorner = (x: number, y: number, size: number): string => `L ${x},${y - size}Q ${x},${y} ${x + size},${y}` -export const leftBottomCorner = (x: number, y: number, size: number): string => `L ${x + size},${y}Q ${x},${y} ${x},${y - size}` -export const bottomRightCorner = (x: number, y: number, size: number): string => `L ${x},${y - size}Q ${x},${y} ${x - size},${y}` -export const rightBottomCorner = (x: number, y: number, size: number): string => `L ${x - size},${y}Q ${x},${y} ${x},${y - size}` -export const leftTopCorner = (x: number, y: number, size: number): string => `L ${x + size},${y}Q ${x},${y} ${x},${y + size}` -export const topLeftCorner = (x: number, y: number, size: number): string => `L ${x},${y + size}Q ${x},${y} ${x + size},${y}` -export const topRightCorner = (x: number, y: number, size: number): string => `L ${x},${y + size}Q ${x},${y} ${x - size},${y}` -export const rightTopCorner = (x: number, y: number, size: number): string => `L ${x - size},${y}Q ${x},${y} ${x},${y + size}` +const bottomLeftCorner = (x: number, y: number, size: number): string => `L ${x},${y - size}Q ${x},${y} ${x + size},${y}` +const leftBottomCorner = (x: number, y: number, size: number): string => `L ${x + size},${y}Q ${x},${y} ${x},${y - size}` +const bottomRightCorner = (x: number, y: number, size: number): string => `L ${x},${y - size}Q ${x},${y} ${x - size},${y}` +const rightBottomCorner = (x: number, y: number, size: number): string => `L ${x - size},${y}Q ${x},${y} ${x},${y - size}` +const leftTopCorner = (x: number, y: number, size: number): string => `L ${x + size},${y}Q ${x},${y} ${x},${y + size}` +const topLeftCorner = (x: number, y: number, size: number): string => `L ${x},${y + size}Q ${x},${y} ${x + size},${y}` +const topRightCorner = (x: number, y: number, size: number): string => `L ${x},${y + size}Q ${x},${y} ${x - size},${y}` +const rightTopCorner = (x: number, y: number, size: number): string => `L ${x - size},${y}Q ${x},${y} ${x},${y + size}` export function getSmoothStepPath({ sourceX, @@ -112,7 +165,11 @@ export function getSmoothStepPath({ if (sourceX <= targetX) { firstCornerPath = sourceY <= targetY ? rightTopCorner(cX, sourceY, cornerSize) : rightBottomCorner(cX, sourceY, cornerSize) secondCornerPath = sourceY <= targetY ? bottomLeftCorner(cX, targetY, cornerSize) : topLeftCorner(cX, targetY, cornerSize) - } else if (sourcePosition === Position.Right && targetPosition === Position.Left) { + } else if ( + (sourcePosition === Position.Right && targetPosition === Position.Left) || + (sourcePosition === Position.Left && targetPosition === Position.Right) || + (sourcePosition === Position.Left && targetPosition === Position.Left) + ) { // and sourceX > targetX firstCornerPath = sourceY <= targetY ? leftTopCorner(cX, sourceY, cornerSize) : leftBottomCorner(cX, sourceY, cornerSize) secondCornerPath = sourceY <= targetY ? bottomRightCorner(cX, targetY, cornerSize) : topRightCorner(cX, targetY, cornerSize) diff --git a/src/types/edge.ts b/src/types/edge.ts index 4e09c38f..3ee8a284 100644 --- a/src/types/edge.ts +++ b/src/types/edge.ts @@ -181,6 +181,7 @@ export interface GetBezierPathParams { targetX: number targetY: number targetPosition?: Position + curvature?: number centerX?: number centerY?: number }