From bc5d1df10e24b55e4d1a91ab79e6aa9fcd417dec Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 14 Mar 2022 16:27:44 +0100 Subject: [PATCH] refactor(edges): add BaseEdge --- example/src/Edges/index.tsx | 2 +- src/components/ConnectionLine/index.tsx | 5 +- src/components/Edges/BaseEdge.tsx | 39 ++++++++ src/components/Edges/BezierEdge.tsx | 58 ++++++------ src/components/Edges/SimpleBezierEdge.tsx | 103 ++-------------------- src/components/Edges/SmoothStepEdge.tsx | 29 +++--- src/components/Edges/StraightEdge.tsx | 28 +++--- src/index.ts | 3 +- src/types/edges.ts | 19 +++- 9 files changed, 124 insertions(+), 162 deletions(-) create mode 100644 src/components/Edges/BaseEdge.tsx diff --git a/example/src/Edges/index.tsx b/example/src/Edges/index.tsx index d527ae45..35d6aaa4 100644 --- a/example/src/Edges/index.tsx +++ b/example/src/Edges/index.tsx @@ -25,7 +25,7 @@ const initialNodes: Node[] = [ { id: '1', type: 'input', data: { label: 'Input 1' }, position: { x: 250, y: 0 } }, { id: '2', data: { label: 'Node 2' }, position: { x: 150, y: 100 } }, { id: '2a', data: { label: 'Node 2a' }, position: { x: 0, y: 180 } }, - { id: '2b', data: { label: 'Node 2b' }, position: { x: -80, y: 100 }, targetPosition: Position.Left }, + { id: '2b', data: { label: 'Node 2b' }, position: { x: -40, y: 300 } }, { id: '3', data: { label: 'Node 3' }, position: { x: 250, y: 200 } }, { id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 300 } }, { id: '3a', data: { label: 'Node 3a' }, position: { x: 150, y: 300 } }, diff --git a/src/components/ConnectionLine/index.tsx b/src/components/ConnectionLine/index.tsx index 0654a4b4..4a4db773 100644 --- a/src/components/ConnectionLine/index.tsx +++ b/src/components/ConnectionLine/index.tsx @@ -2,7 +2,7 @@ import React, { useRef, CSSProperties } from 'react'; import shallow from 'zustand/shallow'; import { useStore } from '../../store'; -import { getBezierPath } from '../Edges/SimpleBezierEdge'; +import { getBezierPath } from '../Edges/BezierEdge'; import { getSmoothStepPath } from '../Edges/SmoothStepEdge'; import { HandleElement, @@ -13,6 +13,7 @@ import { ReactFlowState, Position, } from '../../types'; +import { getSimpleBezierPath } from '../Edges/SimpleBezierEdge'; interface ConnectionLineProps { connectionNodeId: string; @@ -112,6 +113,8 @@ export default ({ }); } else if (connectionLineType === ConnectionLineType.SmoothStep) { dAttr = getSmoothStepPath(pathParams); + } else if (connectionLineType === ConnectionLineType.SimpleBezier) { + dAttr = getSimpleBezierPath(pathParams); } else { dAttr = `M${sourceX},${sourceY} ${targetX},${targetY}`; } diff --git a/src/components/Edges/BaseEdge.tsx b/src/components/Edges/BaseEdge.tsx new file mode 100644 index 00000000..19d0ab37 --- /dev/null +++ b/src/components/Edges/BaseEdge.tsx @@ -0,0 +1,39 @@ +import React from 'react'; + +import EdgeText from './EdgeText'; +import { BaseEdgeProps } from '../../types'; + +export default ({ + path, + centerX, + centerY, + label, + labelStyle, + labelShowBg, + labelBgStyle, + labelBgPadding, + labelBgBorderRadius, + style, + markerEnd, + markerStart, +}: BaseEdgeProps) => { + const text = label ? ( + + ) : null; + + return ( + <> + + {text} + + ); +}; diff --git a/src/components/Edges/BezierEdge.tsx b/src/components/Edges/BezierEdge.tsx index 9daf07bb..b3ab9047 100644 --- a/src/components/Edges/BezierEdge.tsx +++ b/src/components/Edges/BezierEdge.tsx @@ -1,9 +1,10 @@ import React, { memo } from 'react'; -import { EdgeProps, Position } from '../../types'; -import EdgeText from './EdgeText'; -import { getCenter } from './utils'; -interface GetBezierPathParams { +import BaseEdge from './BaseEdge'; +import { getCenter } from './utils'; +import { EdgeProps, Position } from '../../types'; + +export interface GetBezierPathParams { sourceX: number; sourceY: number; sourcePosition?: Position; @@ -11,6 +12,8 @@ interface GetBezierPathParams { targetY: number; targetPosition?: Position; curvature?: number; + centerX?: number; + centerY?: number; } export function getBezierPath({ @@ -21,14 +24,24 @@ export function getBezierPath({ targetY, targetPosition = Position.Top, curvature = 0.5, + centerX, + centerY, }: GetBezierPathParams): string { const leftAndRight = [Position.Left, Position.Right]; + const hasCurvature = curvature > 0; + let cX, + cY = 0; + + if (!hasCurvature) { + const [_centerX, _centerY] = getCenter({ sourceX, sourceY, targetX, targetY }); + cX = typeof centerX !== 'undefined' ? centerX : _centerX; + cY = typeof centerY !== 'undefined' ? centerY : _centerY; + } - // Distance between the source and target const distanceX = sourceX - targetX; const distanceY = sourceY - targetY; - // // A scalar value to fix the curve size getting larger + // A scalar value to fix the curve size getting larger const scalarX = Math.min(curvature, Math.max(0, distanceX / 10000)); const scalarY = Math.min(curvature, Math.max(0, distanceY / 10000)); @@ -38,10 +51,14 @@ export function getBezierPath({ const hy1 = sourceY + Math.abs(targetY - sourceY) * (curvature - scalarY); const hy2 = targetY - Math.abs(targetY - sourceY) * (curvature - scalarY); - let path = `M${sourceX},${sourceY} C${sourceX},${hy1} ${targetX},${hy2} ${targetX},${targetY}`; + let path = hasCurvature + ? `M${sourceX},${sourceY} C${sourceX},${hy1} ${targetX},${hy2} ${targetX},${targetY}` + : `M${sourceX},${sourceY} C${sourceX},${cY} ${targetX},${cY} ${targetX},${targetY}`; if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) { - path = `M${sourceX},${sourceY} C${hx1},${sourceY} ${hx2},${targetY}, ${targetX},${targetY}`; + path = hasCurvature + ? `M${sourceX},${sourceY} C${hx1},${sourceY} ${hx2},${targetY}, ${targetX},${targetY}` + : `M${sourceX},${sourceY} C${cX},${sourceY} ${cX},${targetY} ${targetX},${targetY}`; } else if (leftAndRight.includes(targetPosition)) { path = `M${sourceX},${sourceY} Q${sourceX},${targetY} ${targetX},${targetY}`; } else if (leftAndRight.includes(sourcePosition)) { @@ -81,30 +98,21 @@ export default memo( curvature, }); - const text = label ? ( - - ) : null; - - return ( - <> - - {text} - ); } ); diff --git a/src/components/Edges/SimpleBezierEdge.tsx b/src/components/Edges/SimpleBezierEdge.tsx index 7edb5a42..1bc671c9 100644 --- a/src/components/Edges/SimpleBezierEdge.tsx +++ b/src/components/Edges/SimpleBezierEdge.tsx @@ -1,101 +1,12 @@ import React, { memo } from 'react'; -import EdgeText from './EdgeText'; -import { getCenter } from './utils'; -import { EdgeProps, Position } from '../../types'; +import BezierEdge, { getBezierPath, GetBezierPathParams } from './BezierEdge'; +import { EdgeProps } from '../../types'; -interface GetBezierPathParams { - sourceX: number; - sourceY: number; - sourcePosition?: Position; - targetX: number; - targetY: number; - targetPosition?: Position; - centerX?: number; - centerY?: number; +export function getSimpleBezierPath(props: GetBezierPathParams): string { + return getBezierPath({ ...props, curvature: 0 }); } -export function getBezierPath({ - sourceX, - sourceY, - sourcePosition = Position.Bottom, - targetX, - targetY, - targetPosition = Position.Top, - 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}`; - - if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) { - path = `M${sourceX},${sourceY} C${cX},${sourceY} ${cX},${targetY} ${targetX},${targetY}`; - } else if (leftAndRight.includes(targetPosition)) { - path = `M${sourceX},${sourceY} Q${sourceX},${targetY} ${targetX},${targetY}`; - } else if (leftAndRight.includes(sourcePosition)) { - path = `M${sourceX},${sourceY} Q${targetX},${sourceY} ${targetX},${targetY}`; - } - - return path; -} - -export default memo( - ({ - sourceX, - sourceY, - targetX, - targetY, - sourcePosition = Position.Bottom, - targetPosition = Position.Top, - label, - labelStyle, - labelShowBg, - labelBgStyle, - labelBgPadding, - labelBgBorderRadius, - style, - markerEnd, - markerStart, - }: EdgeProps) => { - const [centerX, centerY] = getCenter({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition }); - const path = getBezierPath({ - sourceX, - sourceY, - sourcePosition, - targetX, - targetY, - targetPosition, - }); - - const text = label ? ( - - ) : null; - - return ( - <> - - {text} - - ); - } -); +export default memo((props: EdgeProps) => { + return ; +}); diff --git a/src/components/Edges/SmoothStepEdge.tsx b/src/components/Edges/SmoothStepEdge.tsx index 0736683a..4eb1ba6b 100644 --- a/src/components/Edges/SmoothStepEdge.tsx +++ b/src/components/Edges/SmoothStepEdge.tsx @@ -1,8 +1,8 @@ import React, { memo } from 'react'; -import EdgeText from './EdgeText'; import { getCenter } from './utils'; import { EdgeSmoothStepProps, Position } from '../../types'; +import BaseEdge from './BaseEdge'; // These are some helper methods for drawing the round corners // The name indicates the direction of the path. "bottomLeftCorner" goes @@ -21,7 +21,7 @@ const topLeftCorner = (x: number, y: number, size: number): string => `L ${x},${ 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}`; -interface GetSmoothStepPathParams { +export interface GetSmoothStepPathParams { sourceX: number; sourceY: number; sourcePosition?: Position; @@ -146,30 +146,21 @@ export default memo( borderRadius, }); - const text = label ? ( - - ) : null; - - return ( - <> - - {text} - ); } ); diff --git a/src/components/Edges/StraightEdge.tsx b/src/components/Edges/StraightEdge.tsx index b7f0fac1..45357615 100644 --- a/src/components/Edges/StraightEdge.tsx +++ b/src/components/Edges/StraightEdge.tsx @@ -1,6 +1,6 @@ import React, { memo } from 'react'; -import EdgeText from './EdgeText'; +import BaseEdge from './BaseEdge'; import { EdgeProps } from '../../types'; export default memo( @@ -24,31 +24,23 @@ export default memo( const xOffset = Math.abs(targetX - sourceX) / 2; const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset; + const path = `M ${sourceX},${sourceY}L ${targetX},${targetY}`; - const text = label ? ( - - ) : null; - - return ( - <> - - {text} - ); } ); diff --git a/src/index.ts b/src/index.ts index 03a8a0ef..826673c7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,7 +6,8 @@ export { default as Handle } from './components/Handle'; export { default as EdgeText } from './components/Edges/EdgeText'; export { default as StraightEdge } from './components/Edges/StraightEdge'; export { default as StepEdge } from './components/Edges/StepEdge'; -export { default as BezierEdge, getBezierPath } from './components/Edges/SimpleBezierEdge'; +export { default as BezierEdge, getBezierPath } from './components/Edges/BezierEdge'; +export { default as SimpleBezierEdge, getSimpleBezierPath } from './components/Edges/SimpleBezierEdge'; export { default as SmoothStepEdge, getSmoothStepPath } from './components/Edges/SmoothStepEdge'; export * from './additional-components'; diff --git a/src/types/edges.ts b/src/types/edges.ts index 48757d7f..2f83eac7 100644 --- a/src/types/edges.ts +++ b/src/types/edges.ts @@ -4,7 +4,6 @@ import { HandleElement } from './handles'; import { Node } from './nodes'; import { Position } from './utils'; - // interface for the user edge items export interface Edge { id: string; @@ -65,6 +64,23 @@ export interface EdgeProps { curvature?: number; } +export type BaseEdgeProps = Pick< + EdgeProps, + | 'label' + | 'labelStyle' + | 'labelShowBg' + | 'labelBgStyle' + | 'labelBgPadding' + | 'labelBgBorderRadius' + | 'style' + | 'markerStart' + | 'markerEnd' +> & { + centerX: number; + centerY: number; + path: string; +}; + export type EdgeMouseHandler = (event: React.MouseEvent, edge: Edge) => void; export interface WrapEdgeProps { @@ -127,6 +143,7 @@ export enum ConnectionLineType { Straight = 'straight', Step = 'step', SmoothStep = 'smoothstep', + SimpleBezier = 'simplebezier', } export type ConnectionLineComponentProps = {