From ceb96201deef186718e9e79f0afc80261aabe9f0 Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 14 Oct 2021 12:29:05 +0200 Subject: [PATCH] refactor(floating-edges-example): comments and cleanup --- .../FloatingEdges/FloatingConnectionLine.tsx | 12 ++- example/src/FloatingEdges/FloatingEdge.tsx | 4 +- example/src/FloatingEdges/index.tsx | 29 +++---- example/src/FloatingEdges/style.css | 9 +++ example/src/FloatingEdges/utils.ts | 75 ++++++++++--------- 5 files changed, 74 insertions(+), 55 deletions(-) create mode 100644 example/src/FloatingEdges/style.css diff --git a/example/src/FloatingEdges/FloatingConnectionLine.tsx b/example/src/FloatingEdges/FloatingConnectionLine.tsx index f45b16dc..987af43d 100644 --- a/example/src/FloatingEdges/FloatingConnectionLine.tsx +++ b/example/src/FloatingEdges/FloatingConnectionLine.tsx @@ -1,7 +1,7 @@ import { FC } from 'react'; -import { getBezierPath, ConnectionLineComponentProps } from 'react-flow-renderer'; +import { getBezierPath, ConnectionLineComponentProps, Node } from 'react-flow-renderer'; -import { getArrow } from './utils'; +import { getEdgeParams } from './utils'; const FloatingConnectionLine: FC = ({ targetX, @@ -14,8 +14,12 @@ const FloatingConnectionLine: FC = ({ return null; } - const targetNode = { __rf: { width: 1, height: 1, position: { x: targetX, y: targetY } } }; - const { sx, sy } = getArrow(sourceNode, targetNode); + const targetNode = { + id: 'connection-target', + __rf: { width: 1, height: 1, position: { x: targetX, y: targetY } }, + } as Node; + + const { sx, sy } = getEdgeParams(sourceNode, targetNode); const d = getBezierPath({ sourceX: sx, sourceY: sy, diff --git a/example/src/FloatingEdges/FloatingEdge.tsx b/example/src/FloatingEdges/FloatingEdge.tsx index e39c318f..60ee4b93 100644 --- a/example/src/FloatingEdges/FloatingEdge.tsx +++ b/example/src/FloatingEdges/FloatingEdge.tsx @@ -1,7 +1,7 @@ import { FC, useMemo, CSSProperties } from 'react'; import { EdgeProps, getMarkerEnd, useStoreState, getBezierPath } from 'react-flow-renderer'; -import { getArrow } from './utils'; +import { getEdgeParams } from './utils'; const FloatingEdge: FC = ({ id, source, target, arrowHeadType, markerEndId, style }) => { const nodes = useStoreState((state) => state.nodes); @@ -14,7 +14,7 @@ const FloatingEdge: FC = ({ id, source, target, arrowHeadType, marker return null; } - const { sx, sy, tx, ty, sourcePos, targetPos } = getArrow(sourceNode, targetNode); + const { sx, sy, tx, ty, sourcePos, targetPos } = getEdgeParams(sourceNode, targetNode); const d = getBezierPath({ sourceX: sx, diff --git a/example/src/FloatingEdges/index.tsx b/example/src/FloatingEdges/index.tsx index 04a5960b..7bdfc7a2 100644 --- a/example/src/FloatingEdges/index.tsx +++ b/example/src/FloatingEdges/index.tsx @@ -3,8 +3,6 @@ import React, { useState } from 'react'; import ReactFlow, { removeElements, addEdge, - MiniMap, - Controls, Background, OnLoadParams, EdgeTypesType, @@ -14,6 +12,8 @@ import ReactFlow, { ArrowHeadType, } from 'react-flow-renderer'; +import './style.css'; + import FloatingEdge from './FloatingEdge'; import FloatingConnectionLine from './FloatingConnectionLine'; import { createElements } from './utils'; @@ -30,22 +30,23 @@ const NodeAsHandleFlow = () => { const [elements, setElements] = useState(initialElements); const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els)); + const onConnect = (params: Connection | Edge) => setElements((els) => addEdge({ ...params, type: 'floating', arrowHeadType: ArrowHeadType.Arrow }, els)); return ( - - - - - +
+ + + +
); }; diff --git a/example/src/FloatingEdges/style.css b/example/src/FloatingEdges/style.css new file mode 100644 index 00000000..052fedb8 --- /dev/null +++ b/example/src/FloatingEdges/style.css @@ -0,0 +1,9 @@ +.floatingedges { + flex-direction: column; + display: flex; + height: 100%; +} + +.floatingedges .react-flow__handle { + opacity: 0; +} diff --git a/example/src/FloatingEdges/utils.ts b/example/src/FloatingEdges/utils.ts index 352e7c3f..c8962b72 100644 --- a/example/src/FloatingEdges/utils.ts +++ b/example/src/FloatingEdges/utils.ts @@ -1,17 +1,23 @@ -import { Position, ArrowHeadType, Node } from 'react-flow-renderer'; +import { Position, ArrowHeadType, Node, XYPosition } from 'react-flow-renderer'; -function getNodeIntersection(source: Node, target: Node) { +// this helper function returns the intersection point +// of the line between the center of the intersectionNode and the target node +function getNodeIntersection(intersectionNode: Node, targetNode: Node): XYPosition { // https://math.stackexchange.com/questions/1724792/an-algorithm-for-finding-the-intersection-point-between-a-center-of-vision-and-a - const { width: sourceWidth, height: sourceHeight, position: sourcePosition } = source.__rf; - const targetPosition = target.__rf.position; + const { + width: intersectionNodeWidth, + height: intersectionNodeHeight, + position: intersectionNodePosition, + } = intersectionNode.__rf; + const targetPosition = targetNode.__rf.position; - const w = sourceWidth / 2; - const h = sourceHeight / 2; + const w = intersectionNodeWidth / 2; + const h = intersectionNodeHeight / 2; - const x2 = sourcePosition.x + w; - const y2 = sourcePosition.y + h; - const x1 = targetPosition.x; - const y1 = targetPosition.y; + const x2 = intersectionNodePosition.x + w; + const y2 = intersectionNodePosition.y + h; + const x1 = targetPosition.x + w; + const y1 = targetPosition.y + h; const xx1 = (x1 - x2) / (2 * w) - (y1 - y2) / (2 * h); const yy1 = (x1 - x2) / (2 * w) + (y1 - y2) / (2 * h); @@ -21,15 +27,16 @@ function getNodeIntersection(source: Node, target: Node) { const x = w * (xx3 + yy3) + x2; const y = h * (-xx3 + yy3) + y2; - return [x, y]; + return { x, y }; } -function getEdgePosition(node: Node, x: number, y: number) { +// returns the position (top,right,bottom or right) passed node compared to the intersection point +function getEdgePosition(node: Node, intersectionPoint: XYPosition) { const n = { ...node.__rf.position, ...node.__rf }; const nx = Math.round(n.x); const ny = Math.round(n.y); - const px = Math.round(x); - const py = Math.round(y); + const px = Math.round(intersectionPoint.x); + const py = Math.round(intersectionPoint.y); if (px <= nx + 1) { return Position.Left; @@ -47,19 +54,19 @@ function getEdgePosition(node: Node, x: number, y: number) { return Position.Top; } -export function getArrow(source: any, target: any) { - const [sx, sy] = getNodeIntersection(source, target); - const [tx, ty] = getNodeIntersection(target, source); +// returns the parameters (sx, sy, tx, ty, sourcePos, targetPos) you need to create an edge +export function getEdgeParams(source: Node, target: Node) { + const sourceIntersectionPoint = getNodeIntersection(source, target); + const targetIntersectionPoint = getNodeIntersection(target, source); - const sourcePos = getEdgePosition(source, sx, sy); - const targetPos = getEdgePosition(target, tx, ty); + const sourcePos = getEdgePosition(source, sourceIntersectionPoint); + const targetPos = getEdgePosition(target, targetIntersectionPoint); return { - sx, - sy, - tx, - ty, - label: null, + sx: sourceIntersectionPoint.x, + sy: sourceIntersectionPoint.y, + tx: targetIntersectionPoint.x, + ty: targetIntersectionPoint.y, sourcePos, targetPos, }; @@ -69,7 +76,7 @@ export function createElements() { const elements = []; const center = { x: window.innerWidth / 2, y: window.innerHeight / 2 }; - elements.push({ id: 'source', data: { label: 'Source', isTarget: false }, position: center }); + elements.push({ id: 'target', data: { label: 'Target' }, position: center }); for (let i = 0; i < 8; i++) { const degrees = i * (360 / 8); @@ -77,17 +84,15 @@ export function createElements() { const x = 250 * Math.cos(radians) + center.x; const y = 250 * Math.sin(radians) + center.y; - elements.push({ id: `${i}`, data: { label: 'Target', isTarget: true }, position: { x, y } }); + elements.push({ id: `${i}`, data: { label: 'Source' }, position: { x, y } }); - if (i % 2 === 0) { - elements.push({ - id: `source-${i}`, - source: 'source', - target: `${i}`, - type: 'floating', - arrowHeadType: ArrowHeadType.Arrow, - }); - } + elements.push({ + id: `edge-${i}`, + target: 'target', + source: `${i}`, + type: 'floating', + arrowHeadType: ArrowHeadType.Arrow, + }); } return elements;