refactor(edges): siplify edge path / label position handling, repair edge labels

This commit is contained in:
moklick
2022-09-27 14:17:02 +02:00
parent aef8b477c2
commit e634e7296a
12 changed files with 182 additions and 213 deletions
@@ -77,10 +77,6 @@ const edges: Edge[] = [
id: 'e1-2', id: 'e1-2',
source: '1', source: '1',
target: '2', target: '2',
type: 'smoothstep',
markerEnd: {
type: MarkerType.ArrowClosed,
},
pathOptions: { pathOptions: {
offset: 30, offset: 30,
}, },
@@ -90,10 +86,6 @@ const edges: Edge[] = [
id: 'e3-4', id: 'e3-4',
source: '3', source: '3',
target: '4', target: '4',
type: 'smoothstep',
markerEnd: {
type: MarkerType.ArrowClosed,
},
pathOptions: { pathOptions: {
borderRadius: 2, borderRadius: 2,
}, },
@@ -104,24 +96,21 @@ const edges: Edge[] = [
id: 'e4-5', id: 'e4-5',
source: '5', source: '5',
target: '6', target: '6',
type: 'smoothstep',
markerEnd: {
type: MarkerType.ArrowClosed,
},
}, },
{ {
id: 'e7-8', id: 'e7-8',
source: '7', source: '7',
target: '8', target: '8',
type: 'smoothstep',
markerEnd: {
type: MarkerType.ArrowClosed,
},
}, },
]; ];
const defaultEdgeOptions = { const defaultEdgeOptions = {
label: 'Edge Label',
type: 'default',
markerEnd: {
type: MarkerType.ArrowClosed,
},
style: { style: {
strokeWidth: 1, strokeWidth: 1,
}, },
@@ -1,4 +1,4 @@
import React, { FC } from 'react'; import { FC } from 'react';
import { EdgeProps, getBezierPath } from 'reactflow'; import { EdgeProps, getBezierPath } from 'reactflow';
const CustomEdge: FC<EdgeProps> = ({ const CustomEdge: FC<EdgeProps> = ({
@@ -11,7 +11,7 @@ const CustomEdge: FC<EdgeProps> = ({
targetPosition, targetPosition,
data, data,
}) => { }) => {
const edgePath = getBezierPath({ const [edgePath] = getBezierPath({
sourceX, sourceX,
sourceY, sourceY,
sourcePosition, sourcePosition,
@@ -1,5 +1,5 @@
import React, { FC } from 'react'; import { FC } from 'react';
import { EdgeProps, getBezierPath, EdgeText, getBezierEdgeCenter } from 'reactflow'; import { EdgeProps, getBezierPath, EdgeText } from 'reactflow';
const CustomEdge: FC<EdgeProps> = ({ const CustomEdge: FC<EdgeProps> = ({
id, id,
@@ -11,7 +11,7 @@ const CustomEdge: FC<EdgeProps> = ({
targetPosition, targetPosition,
data, data,
}) => { }) => {
const edgePath = getBezierPath({ const [edgePath, labelX, labelY] = getBezierPath({
sourceX, sourceX,
sourceY, sourceY,
sourcePosition, sourcePosition,
@@ -19,19 +19,13 @@ const CustomEdge: FC<EdgeProps> = ({
targetY, targetY,
targetPosition, targetPosition,
}); });
const [centerX, centerY] = getBezierEdgeCenter({
sourceX,
sourceY,
targetX,
targetY,
});
return ( return (
<> <>
<path id={id} className="react-flow__edge-path" d={edgePath} /> <path id={id} className="react-flow__edge-path" d={edgePath} />
<EdgeText <EdgeText
x={centerX} x={labelX}
y={centerY} y={labelY}
label={data.text} label={data.text}
labelStyle={{ fill: 'white' }} labelStyle={{ fill: 'white' }}
labelShowBg labelShowBg
@@ -97,16 +97,16 @@ const ConnectionLine = ({
if (connectionLineType === ConnectionLineType.Bezier) { if (connectionLineType === ConnectionLineType.Bezier) {
// we assume the destination position is opposite to the source position // we assume the destination position is opposite to the source position
dAttr = getBezierPath(pathParams); [dAttr] = getBezierPath(pathParams);
} else if (connectionLineType === ConnectionLineType.Step) { } else if (connectionLineType === ConnectionLineType.Step) {
dAttr = getSmoothStepPath({ [dAttr] = getSmoothStepPath({
...pathParams, ...pathParams,
borderRadius: 0, borderRadius: 0,
}); });
} else if (connectionLineType === ConnectionLineType.SmoothStep) { } else if (connectionLineType === ConnectionLineType.SmoothStep) {
dAttr = getSmoothStepPath(pathParams); [dAttr] = getSmoothStepPath(pathParams);
} else if (connectionLineType === ConnectionLineType.SimpleBezier) { } else if (connectionLineType === ConnectionLineType.SimpleBezier) {
dAttr = getSimpleBezierPath(pathParams); [dAttr] = getSimpleBezierPath(pathParams);
} else { } else {
dAttr = `M${fromX},${fromY} ${toX},${toY}`; dAttr = `M${fromX},${fromY} ${toX},${toY}`;
} }
@@ -3,8 +3,8 @@ import { BaseEdgeProps } from '../../types';
const BaseEdge = ({ const BaseEdge = ({
path, path,
centerX, labelX,
centerY, labelY,
label, label,
labelStyle, labelStyle,
labelShowBg, labelShowBg,
@@ -29,8 +29,8 @@ const BaseEdge = ({
{interactionWidth && <path d={path} fill="none" strokeOpacity={0} strokeWidth={interactionWidth} />} {interactionWidth && <path d={path} fill="none" strokeOpacity={0} strokeWidth={interactionWidth} />}
{label ? ( {label ? (
<EdgeText <EdgeText
x={centerX} x={labelX}
y={centerY} y={labelY}
label={label} label={label}
labelStyle={labelStyle} labelStyle={labelStyle}
labelShowBg={labelShowBg} labelShowBg={labelShowBg}
@@ -1,6 +1,7 @@
import { memo } from 'react'; import { memo } from 'react';
import { BezierEdgeProps, Position } from '../../types'; import { BezierEdgeProps, Position } from '../../types';
import BaseEdge from './BaseEdge'; import BaseEdge from './BaseEdge';
import { getBezierEdgeCenter } from './utils';
export interface GetBezierPathParams { export interface GetBezierPathParams {
sourceX: number; sourceX: number;
@@ -68,7 +69,7 @@ export function getBezierPath({
targetY, targetY,
targetPosition = Position.Top, targetPosition = Position.Top,
curvature = 0.25, curvature = 0.25,
}: GetBezierPathParams): string { }: GetBezierPathParams): [string, number, number, number, number] {
const [sourceControlX, sourceControlY] = getControlWithCurvature({ const [sourceControlX, sourceControlY] = getControlWithCurvature({
pos: sourcePosition, pos: sourcePosition,
x1: sourceX, x1: sourceX,
@@ -85,45 +86,24 @@ export function getBezierPath({
y2: sourceY, y2: sourceY,
c: curvature, c: curvature,
}); });
return `M${sourceX},${sourceY} C${sourceControlX},${sourceControlY} ${targetControlX},${targetControlY} ${targetX},${targetY}`; const [centerX, centerY, offsetX, offsetY] = getBezierEdgeCenter({
} sourceX,
sourceY,
targetX,
targetY,
sourceControlX,
sourceControlY,
targetControlX,
targetControlY,
});
// @TODO: this function will recalculate the control points return [
// one option is to let getXXXPath() return center points `M${sourceX},${sourceY} C${sourceControlX},${sourceControlY} ${targetControlX},${targetControlY} ${targetX},${targetY}`,
// but will introduce breaking changes centerX,
// the getCenter() of other types of edges might need to change, too centerY,
export function getBezierCenter({ offsetX,
sourceX, offsetY,
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];
} }
const BezierEdge = memo( const BezierEdge = memo(
@@ -146,7 +126,7 @@ const BezierEdge = memo(
pathOptions, pathOptions,
interactionWidth, interactionWidth,
}: BezierEdgeProps) => { }: BezierEdgeProps) => {
const params = { const [path, labelX, labelY] = getBezierPath({
sourceX, sourceX,
sourceY, sourceY,
sourcePosition, sourcePosition,
@@ -154,15 +134,13 @@ const BezierEdge = memo(
targetY, targetY,
targetPosition, targetPosition,
curvature: pathOptions?.curvature, curvature: pathOptions?.curvature,
}; });
const path = getBezierPath(params);
const [centerX, centerY] = getBezierCenter(params);
return ( return (
<BaseEdge <BaseEdge
path={path} path={path}
centerX={centerX} labelX={labelX}
centerY={centerY} labelY={labelY}
label={label} label={label}
labelStyle={labelStyle} labelStyle={labelStyle}
labelShowBg={labelShowBg} labelShowBg={labelShowBg}
@@ -1,6 +1,7 @@
import { memo } from 'react'; import { memo } from 'react';
import { EdgeProps, Position } from '../../types'; import { EdgeProps, Position } from '../../types';
import BaseEdge from './BaseEdge'; import BaseEdge from './BaseEdge';
import { getBezierEdgeCenter } from './utils';
export interface GetSimpleBezierPathParams { export interface GetSimpleBezierPathParams {
sourceX: number; sourceX: number;
@@ -47,7 +48,7 @@ export function getSimpleBezierPath({
targetX, targetX,
targetY, targetY,
targetPosition = Position.Top, targetPosition = Position.Top,
}: GetSimpleBezierPathParams): string { }: GetSimpleBezierPathParams): [string, number, number, number, number] {
const [sourceControlX, sourceControlY] = getControl({ const [sourceControlX, sourceControlY] = getControl({
pos: sourcePosition, pos: sourcePosition,
x1: sourceX, x1: sourceX,
@@ -62,42 +63,24 @@ export function getSimpleBezierPath({
x2: sourceX, x2: sourceX,
y2: sourceY, y2: sourceY,
}); });
return `M${sourceX},${sourceY} C${sourceControlX},${sourceControlY} ${targetControlX},${targetControlY} ${targetX},${targetY}`; const [centerX, centerY, offsetX, offsetY] = getBezierEdgeCenter({
} sourceX,
sourceY,
targetX,
targetY,
sourceControlX,
sourceControlY,
targetControlX,
targetControlY,
});
// @TODO: this function will recalculate the control points return [
// one option is to let getXXXPath() return center points `M${sourceX},${sourceY} C${sourceControlX},${sourceControlY} ${targetControlX},${targetControlY} ${targetX},${targetY}`,
// but will introduce breaking changes centerX,
// the getCenter() of other types of edges might need to change, too centerY,
export function getSimpleBezierCenter({ offsetX,
sourceX, offsetY,
sourceY, ];
sourcePosition = Position.Bottom,
targetX,
targetY,
targetPosition = Position.Top,
}: GetSimpleBezierPathParams): [number, number, number, number] {
const [sourceControlX, sourceControlY] = getControl({
pos: sourcePosition,
x1: sourceX,
y1: sourceY,
x2: targetX,
y2: targetY,
});
const [targetControlX, targetControlY] = getControl({
pos: targetPosition,
x1: targetX,
y1: targetY,
x2: sourceX,
y2: sourceY,
});
// 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];
} }
const SimpleBezierEdge = memo( const SimpleBezierEdge = memo(
@@ -119,22 +102,20 @@ const SimpleBezierEdge = memo(
markerStart, markerStart,
interactionWidth, interactionWidth,
}: EdgeProps) => { }: EdgeProps) => {
const params = { const [path, labelX, labelY] = getSimpleBezierPath({
sourceX, sourceX,
sourceY, sourceY,
sourcePosition, sourcePosition,
targetX, targetX,
targetY, targetY,
targetPosition, targetPosition,
}; });
const path = getSimpleBezierPath(params);
const [centerX, centerY] = getSimpleBezierCenter(params);
return ( return (
<BaseEdge <BaseEdge
path={path} path={path}
centerX={centerX} labelX={labelX}
centerY={centerY} labelY={labelY}
label={label} label={label}
labelStyle={labelStyle} labelStyle={labelStyle}
labelShowBg={labelShowBg} labelShowBg={labelShowBg}
@@ -1,8 +1,8 @@
import { memo } from 'react'; import { memo } from 'react';
import { getCenter } from './utils';
import { SmoothStepEdgeProps, Position, XYPosition } from '../../types'; import { SmoothStepEdgeProps, Position, XYPosition } from '../../types';
import BaseEdge from './BaseEdge'; import BaseEdge from './BaseEdge';
import { getSimpleEdgeCenter } from './utils';
export interface GetSmoothStepPathParams { export interface GetSmoothStepPathParams {
sourceX: number; sourceX: number;
@@ -55,9 +55,9 @@ function getPoints({
sourcePosition: Position; sourcePosition: Position;
target: XYPosition; target: XYPosition;
targetPosition: Position; targetPosition: Position;
center: XYPosition; center: Partial<XYPosition>;
offset: number; offset: number;
}): XYPosition[] { }): [XYPosition[], number, number, number, number] {
const sourceDir = handleDirections[sourcePosition]; const sourceDir = handleDirections[sourcePosition];
const targetDir = handleDirections[targetPosition]; const targetDir = handleDirections[targetPosition];
const sourceGapped: XYPosition = { x: source.x + sourceDir.x * offset, y: source.y + sourceDir.y * offset }; const sourceGapped: XYPosition = { x: source.x + sourceDir.x * offset, y: source.y + sourceDir.y * offset };
@@ -71,22 +71,31 @@ function getPoints({
const currDir = dir[dirAccessor]; const currDir = dir[dirAccessor];
let points: XYPosition[] = []; let points: XYPosition[] = [];
let centerX, centerY;
const [defaultCenterX, defaultCenterY, defaultOffsetX, defaultOffsetY] = getSimpleEdgeCenter({
sourceX: source.x,
sourceY: source.y,
targetX: target.x,
targetY: target.y,
});
// opposite handle positions, default case // opposite handle positions, default case
if (sourceDir[dirAccessor] * targetDir[dirAccessor] === -1) { if (sourceDir[dirAccessor] * targetDir[dirAccessor] === -1) {
centerX = center.x || defaultCenterX;
centerY = center.y || defaultCenterY;
// ---> // --->
// | // |
// >--- // >---
const verticalSplit: XYPosition[] = [ const verticalSplit: XYPosition[] = [
{ x: center.x, y: sourceGapped.y }, { x: centerX, y: sourceGapped.y },
{ x: center.x, y: targetGapped.y }, { x: centerX, y: targetGapped.y },
]; ];
// | // |
// --- // ---
// | // |
const horizontalSplit: XYPosition[] = [ const horizontalSplit: XYPosition[] = [
{ x: sourceGapped.x, y: center.y }, { x: sourceGapped.x, y: centerY },
{ x: targetGapped.x, y: center.y }, { x: targetGapped.x, y: centerY },
]; ];
if (sourceDir[dirAccessor] === currDir) { if (sourceDir[dirAccessor] === currDir) {
@@ -119,9 +128,14 @@ function getPoints({
points = dirAccessor === 'x' ? sourceTarget : targetSource; points = dirAccessor === 'x' ? sourceTarget : targetSource;
} }
} }
centerX = points[0].x;
centerY = points[0].y;
} }
return [source, sourceGapped, ...points, targetGapped, target]; const pathPoints = [source, sourceGapped, ...points, targetGapped, target];
return [pathPoints, centerX, centerY, defaultOffsetX, defaultOffsetY];
} }
function getBend(a: XYPosition, b: XYPosition, c: XYPosition, size: number): string { function getBend(a: XYPosition, b: XYPosition, c: XYPosition, size: number): string {
@@ -156,21 +170,17 @@ export function getSmoothStepPath({
centerX, centerX,
centerY, centerY,
offset = 20, offset = 20,
}: GetSmoothStepPathParams): string { }: GetSmoothStepPathParams): [string, number, number, number, number] {
const [_centerX, _centerY] = getCenter({ sourceX, sourceY, targetX, targetY }); const [points, labelX, labelY, offsetX, offsetY] = getPoints({
const cX = typeof centerX !== 'undefined' ? centerX : _centerX;
const cY = typeof centerY !== 'undefined' ? centerY : _centerY;
const points = getPoints({
source: { x: sourceX, y: sourceY }, source: { x: sourceX, y: sourceY },
sourcePosition, sourcePosition,
target: { x: targetX, y: targetY }, target: { x: targetX, y: targetY },
targetPosition, targetPosition,
center: { x: cX, y: cY }, center: { x: centerX, y: centerY },
offset, offset,
}); });
return points.reduce<string>((res, p, i) => { const path = points.reduce<string>((res, p, i) => {
let segment = ''; let segment = '';
if (i > 0 && i < points.length - 1) { if (i > 0 && i < points.length - 1) {
@@ -183,6 +193,8 @@ export function getSmoothStepPath({
return res; return res;
}, ''); }, '');
return [path, labelX, labelY, offsetX, offsetY];
} }
const SmoothStepEdge = memo( const SmoothStepEdge = memo(
@@ -205,9 +217,7 @@ const SmoothStepEdge = memo(
pathOptions, pathOptions,
interactionWidth, interactionWidth,
}: SmoothStepEdgeProps) => { }: SmoothStepEdgeProps) => {
const [centerX, centerY] = getCenter({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition }); const [path, labelX, labelY] = getSmoothStepPath({
const path = getSmoothStepPath({
sourceX, sourceX,
sourceY, sourceY,
sourcePosition, sourcePosition,
@@ -221,8 +231,8 @@ const SmoothStepEdge = memo(
return ( return (
<BaseEdge <BaseEdge
path={path} path={path}
centerX={centerX} labelX={labelX}
centerY={centerY} labelY={labelY}
label={label} label={label}
labelStyle={labelStyle} labelStyle={labelStyle}
labelShowBg={labelShowBg} labelShowBg={labelShowBg}
@@ -2,6 +2,30 @@ import { memo } from 'react';
import BaseEdge from './BaseEdge'; import BaseEdge from './BaseEdge';
import { EdgeProps } from '../../types'; import { EdgeProps } from '../../types';
import { getSimpleEdgeCenter } from './utils';
export type GetStraightPathParams = {
sourceX: number;
sourceY: number;
targetX: number;
targetY: number;
};
export function getStraightPath({
sourceX,
sourceY,
targetX,
targetY,
}: GetStraightPathParams): [string, number, number, number, number] {
const [centerX, centerY, offsetX, offsetY] = getSimpleEdgeCenter({
sourceX,
sourceY,
targetX,
targetY,
});
return [`M ${sourceX},${sourceY}L ${targetX},${targetY}`, centerX, centerY, offsetX, offsetY];
}
const StraightEdge = memo( const StraightEdge = memo(
({ ({
@@ -20,17 +44,13 @@ const StraightEdge = memo(
markerStart, markerStart,
interactionWidth, interactionWidth,
}: EdgeProps) => { }: EdgeProps) => {
const yOffset = Math.abs(targetY - sourceY) / 2; const [path, labelX, labelY] = getStraightPath({ sourceX, sourceY, targetX, targetY });
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
const xOffset = Math.abs(targetX - sourceX) / 2;
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
return ( return (
<BaseEdge <BaseEdge
path={`M ${sourceX},${sourceY}L ${targetX},${targetY}`} path={path}
centerX={centerX} labelX={labelX}
centerY={centerY} labelY={labelY}
label={label} label={label}
labelStyle={labelStyle} labelStyle={labelStyle}
labelShowBg={labelShowBg} labelShowBg={labelShowBg}
+51 -46
View File
@@ -1,7 +1,7 @@
import { MouseEvent as ReactMouseEvent } from 'react'; import { MouseEvent as ReactMouseEvent } from 'react';
import { StoreApi } from 'zustand'; import { StoreApi } from 'zustand';
import { Edge, MarkerType, Position, ReactFlowState } from '../../types'; import { Edge, MarkerType, ReactFlowState } from '../../types';
export const getMarkerEnd = (markerType?: MarkerType, markerEndId?: string): string => { export const getMarkerEnd = (markerType?: MarkerType, markerEndId?: string): string => {
if (typeof markerEndId !== 'undefined' && markerEndId) { if (typeof markerEndId !== 'undefined' && markerEndId) {
@@ -11,51 +11,6 @@ export const getMarkerEnd = (markerType?: MarkerType, markerEndId?: string): str
return typeof markerType !== 'undefined' ? `url(#react-flow__${markerType})` : 'none'; return typeof markerType !== 'undefined' ? `url(#react-flow__${markerType})` : 'none';
}; };
export interface GetCenterParams {
sourceX: number;
sourceY: number;
targetX: number;
targetY: number;
sourcePosition?: Position;
targetPosition?: Position;
}
const LeftOrRight = [Position.Left, Position.Right];
export const getCenter = ({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition = Position.Bottom,
targetPosition = Position.Top,
}: GetCenterParams): [number, number, number, number] => {
const sourceIsLeftOrRight = LeftOrRight.includes(sourcePosition);
const targetIsLeftOrRight = LeftOrRight.includes(targetPosition);
// we expect flows to be horizontal or vertical (all handles left or right respectively top or bottom)
// a mixed edge is when one the source is on the left and the target is on the top for example.
const mixedEdge = (sourceIsLeftOrRight && !targetIsLeftOrRight) || (targetIsLeftOrRight && !sourceIsLeftOrRight);
if (mixedEdge) {
const xOffset = sourceIsLeftOrRight ? Math.abs(targetX - sourceX) : 0;
const centerX = sourceX > targetX ? sourceX - xOffset : sourceX + xOffset;
const yOffset = sourceIsLeftOrRight ? 0 : Math.abs(targetY - sourceY);
const centerY = sourceY < targetY ? sourceY + yOffset : sourceY - yOffset;
return [centerX, centerY, xOffset, yOffset];
}
const xOffset = Math.abs(targetX - sourceX) / 2;
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
const yOffset = Math.abs(targetY - sourceY) / 2;
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
return [centerX, centerY, xOffset, yOffset];
};
export function getMouseHandler( export function getMouseHandler(
id: string, id: string,
getState: StoreApi<ReactFlowState>['getState'], getState: StoreApi<ReactFlowState>['getState'],
@@ -71,3 +26,53 @@ export function getMouseHandler(
} }
}; };
} }
// this is used for straight edges and simple smoothstep edges (LTR, RTL, BTT, TTB)
export function getSimpleEdgeCenter({
sourceX,
sourceY,
targetX,
targetY,
}: {
sourceX: number;
sourceY: number;
targetX: number;
targetY: number;
}): [number, number, number, number] {
const xOffset = Math.abs(targetX - sourceX) / 2;
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
const yOffset = Math.abs(targetY - sourceY) / 2;
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
return [centerX, centerY, xOffset, yOffset];
}
export function getBezierEdgeCenter({
sourceX,
sourceY,
targetX,
targetY,
sourceControlX,
sourceControlY,
targetControlX,
targetControlY,
}: {
sourceX: number;
sourceY: number;
targetX: number;
targetY: number;
sourceControlX: number;
sourceControlY: number;
targetControlX: number;
targetControlY: number;
}): [number, number, number, number] {
// 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 offsetX = Math.abs(centerX - sourceX);
const offsetY = Math.abs(centerY - sourceY);
return [centerX, centerY, offsetX, offsetY];
}
+4 -12
View File
@@ -1,18 +1,10 @@
export { default as ReactFlow } from './container/ReactFlow'; export { default as ReactFlow } from './container/ReactFlow';
export { default as Handle } from './components/Handle'; export { default as Handle } from './components/Handle';
export { default as EdgeText } from './components/Edges/EdgeText'; export { default as EdgeText } from './components/Edges/EdgeText';
export { default as StraightEdge } from './components/Edges/StraightEdge'; export { default as StraightEdge, getStraightPath } from './components/Edges/StraightEdge';
export { default as StepEdge } from './components/Edges/StepEdge'; export { default as StepEdge } from './components/Edges/StepEdge';
export { export { default as BezierEdge, getBezierPath } from './components/Edges/BezierEdge';
default as BezierEdge, export { default as SimpleBezierEdge, getSimpleBezierPath } from './components/Edges/SimpleBezierEdge';
getBezierPath,
getBezierCenter as getBezierEdgeCenter,
} from './components/Edges/BezierEdge';
export {
default as SimpleBezierEdge,
getSimpleBezierPath,
getSimpleBezierCenter as getSimpleBezierEdgeCenter,
} from './components/Edges/SimpleBezierEdge';
export { default as SmoothStepEdge, getSmoothStepPath } from './components/Edges/SmoothStepEdge'; export { default as SmoothStepEdge, getSmoothStepPath } from './components/Edges/SmoothStepEdge';
export { default as BaseEdge } from './components/Edges/BaseEdge'; export { default as BaseEdge } from './components/Edges/BaseEdge';
@@ -29,7 +21,7 @@ export {
getRectOfNodes, getRectOfNodes,
} from './utils/graph'; } from './utils/graph';
export { applyNodeChanges, applyEdgeChanges } from './utils/changes'; export { applyNodeChanges, applyEdgeChanges } from './utils/changes';
export { getMarkerEnd, getCenter as getEdgeCenter } from './components/Edges/utils'; export { getMarkerEnd } from './components/Edges/utils';
export { default as ReactFlowProvider } from './components/ReactFlowProvider'; export { default as ReactFlowProvider } from './components/ReactFlowProvider';
export { default as Panel } from './components/Panel'; export { default as Panel } from './components/Panel';
+2 -2
View File
@@ -104,8 +104,8 @@ export type BaseEdgeProps = Pick<
| 'markerEnd' | 'markerEnd'
| 'interactionWidth' | 'interactionWidth'
> & { > & {
centerX: number; labelX: number;
centerY: number; labelY: number;
path: string; path: string;
}; };