From 84adeeda1d148394d159798e0e32969f7cf098cd Mon Sep 17 00:00:00 2001 From: xiaoyu Date: Tue, 26 Oct 2021 17:57:10 +0800 Subject: [PATCH] fix: only render edges with visible source or target --- package.json | 2 +- src/container/EdgeRenderer/index.tsx | 17 ++++-- src/utils/graph.ts | 80 ++++++++++++++++++++-------- 3 files changed, 70 insertions(+), 29 deletions(-) diff --git a/package.json b/package.json index d4f573b4b..2b4ef89cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-flow-renderer", - "version": "9.6.9", + "version": "9.6.10", "engines": { "node": ">=12" }, diff --git a/src/container/EdgeRenderer/index.tsx b/src/container/EdgeRenderer/index.tsx index 1fd7f7662..d0375457c 100644 --- a/src/container/EdgeRenderer/index.tsx +++ b/src/container/EdgeRenderer/index.tsx @@ -2,7 +2,7 @@ import React, { memo, CSSProperties, useCallback } from 'react'; import { useStoreState } from '../../store/hooks'; import ConnectionLine from '../../components/ConnectionLine/index'; -import { isEdge } from '../../utils/graph'; +import { getNodeInside, isEdge } from '../../utils/graph'; import MarkerDefinitions from './MarkerDefinitions'; import { getEdgePositions, getHandle, isEdgeVisible, getSourceTargetNodes } from './utils'; import { @@ -76,12 +76,12 @@ const Edge = ({ ); if (!sourceNode) { - console.warn(`couldn't create edge for source id: ${edge.source}; edge id: ${edge.id}`); + // console.warn(`couldn't create edge for source id: ${edge.source}; edge id: ${edge.id}`); return null; } if (!targetNode) { - console.warn(`couldn't create edge for target id: ${edge.target}; edge id: ${edge.id}`); + // console.warn(`couldn't create edge for target id: ${edge.target}; edge id: ${edge.id}`); return null; } @@ -104,12 +104,12 @@ const Edge = ({ const targetPosition = targetHandle ? targetHandle.position : Position.Top; if (!sourceHandle) { - console.warn(`couldn't create edge for source handle id: ${sourceHandleId}; edge id: ${edge.id}`); + // console.warn(`couldn't create edge for source handle id: ${sourceHandleId}; edge id: ${edge.id}`); return null; } if (!targetHandle) { - console.warn(`couldn't create edge for target handle id: ${targetHandleId}; edge id: ${edge.id}`); + // console.warn(`couldn't create edge for target handle id: ${targetHandleId}; edge id: ${edge.id}`); return null; } @@ -122,6 +122,13 @@ const Edge = ({ targetPosition ); + const sourceNodeVisible = getNodeInside(sourceNode, { x: 0, y: 0, width, height }, transform, true) + const targetNodeVisible = getNodeInside(targetNode, { x: 0, y: 0, width, height }, transform, true) + + if (!sourceNodeVisible && !targetNodeVisible) { + return null; + } + const isVisible = onlyRenderVisibleElements ? isEdgeVisible({ sourcePos: { x: sourceX, y: sourceY }, diff --git a/src/utils/graph.ts b/src/utils/graph.ts index 39708d728..5a160830d 100644 --- a/src/utils/graph.ts +++ b/src/utils/graph.ts @@ -153,7 +153,7 @@ export const parseNode = (node: Node, nodeExtent: NodeExtent): Node => { type: node.type || 'default', __rf: { position: clampPosition(node.position, nodeExtent), - width: node.style?.width || null, + width: node.style?.width || null, height: node.style?.height || null, handleBounds: {}, isDragging: false, @@ -212,6 +212,51 @@ export const graphPosToZoomedPos = ({ x, y }: XYPosition, [tx, ty, tScale]: Tran y: y * tScale + ty, }); +export const getNodeInside = ( + node: Node, + rect: Rect, + [tx, ty, tScale]: Transform = [0, 0, 1], + partially: boolean = false, + // set excludeNonSelectableNodes if you want to pay attention to the nodes "selectable" attribute + excludeNonSelectableNodes: boolean = false, + rBox?: Box, +): boolean => { + let _rBox = rBox; + if (!_rBox) { + _rBox = rectToBox({ + x: (rect.x - tx) / tScale, + y: (rect.y - ty) / tScale, + width: rect.width / tScale, + height: rect.height / tScale, + }); + } + + + const { selectable = true, __rf: { position, width, height, isDragging } } = node; + + if (excludeNonSelectableNodes && !selectable) { + return false; + } + + const nBox = rectToBox({ ...position, width, height }); + const xOverlap = Math.max(0, Math.min(_rBox.x2, nBox.x2) - Math.max(_rBox.x, nBox.x)); + const yOverlap = Math.max(0, Math.min(_rBox.y2, nBox.y2) - Math.max(_rBox.y, nBox.y)); + const overlappingArea = Math.ceil(xOverlap * yOverlap); + + if (width === null || height === null || isDragging) { + // nodes are initialized with width and height = null + return true; + } + + if (partially) { + return overlappingArea > 0; + } + + const area = width * height; + + return overlappingArea >= area; +}; + export const getNodesInside = ( nodes: Node[], rect: Rect, @@ -227,30 +272,19 @@ export const getNodesInside = ( height: rect.height / tScale, }); - return nodes.filter(({ selectable = true, __rf: { position, width, height, isDragging } }) => { - if (excludeNonSelectableNodes && !selectable) { - return false; - } - - const nBox = rectToBox({ ...position, width, height }); - const xOverlap = Math.max(0, Math.min(rBox.x2, nBox.x2) - Math.max(rBox.x, nBox.x)); - const yOverlap = Math.max(0, Math.min(rBox.y2, nBox.y2) - Math.max(rBox.y, nBox.y)); - const overlappingArea = Math.ceil(xOverlap * yOverlap); - - if (width === null || height === null || isDragging) { - // nodes are initialized with width and height = null - return true; - } - - if (partially) { - return overlappingArea > 0; - } + return nodes + .filter(node => + getNodeInside( + node, + rect, + [tx, ty, tScale], + partially, + excludeNonSelectableNodes, + rBox + )); +}; - const area = width * height; - return overlappingArea >= area; - }); -}; export const getConnectedEdges = (nodes: Node[], edges: Edge[]): Edge[] => { const nodeIds = nodes.map((node) => node.id);