import { memo } from 'react'; import BaseEdge from './BaseEdge'; import { getBezierEdgeCenter } from './utils'; import { Position } from '../../types'; import type { BezierEdgeProps } from '../../types'; export interface GetBezierPathParams { sourceX: number; sourceY: number; sourcePosition?: Position; targetX: number; targetY: number; targetPosition?: Position; curvature?: number; } interface GetControlWithCurvatureParams { pos: Position; x1: number; y1: number; x2: number; y2: number; c: number; } function calculateControlOffset(distance: number, curvature: number): number { if (distance >= 0) { return 0.5 * distance; } return curvature * 25 * Math.sqrt(-distance); } function getControlWithCurvature({ pos, x1, y1, x2, y2, c }: GetControlWithCurvatureParams): [number, number] { switch (pos) { case Position.Left: return [x1 - calculateControlOffset(x1 - x2, c), y1]; case Position.Right: return [x1 + calculateControlOffset(x2 - x1, c), y1]; case Position.Top: return [x1, y1 - calculateControlOffset(y1 - y2, c)]; case Position.Bottom: return [x1, y1 + calculateControlOffset(y2 - y1, c)]; } } export function getBezierPath({ sourceX, sourceY, sourcePosition = Position.Bottom, targetX, targetY, targetPosition = Position.Top, curvature = 0.25, }: GetBezierPathParams): [path: string, labelX: number, labelY: number, offsetX: number, offsetY: 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, }); const [labelX, labelY, offsetX, offsetY] = getBezierEdgeCenter({ sourceX, sourceY, targetX, targetY, sourceControlX, sourceControlY, targetControlX, targetControlY, }); return [ `M${sourceX},${sourceY} C${sourceControlX},${sourceControlY} ${targetControlX},${targetControlY} ${targetX},${targetY}`, labelX, labelY, offsetX, offsetY, ]; } const BezierEdge = memo( ({ sourceX, sourceY, targetX, targetY, sourcePosition = Position.Bottom, targetPosition = Position.Top, label, labelStyle, labelShowBg, labelBgStyle, labelBgPadding, labelBgBorderRadius, style, markerEnd, markerStart, pathOptions, interactionWidth, }: BezierEdgeProps) => { const [path, labelX, labelY] = getBezierPath({ sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition, curvature: pathOptions?.curvature, }); return ( ); } ); BezierEdge.displayName = 'BezierEdge'; export default BezierEdge;