diff --git a/src/container/EdgeRenderer/index.tsx b/src/container/EdgeRenderer/index.tsx index 6e913f72..e7383e6b 100644 --- a/src/container/EdgeRenderer/index.tsx +++ b/src/container/EdgeRenderer/index.tsx @@ -4,17 +4,8 @@ import { useStoreState } from '../../store/hooks'; import ConnectionLine from '../../components/ConnectionLine/index'; import { isEdge } from '../../utils/graph'; import MarkerDefinitions from './MarkerDefinitions'; -import { getHandlePosition, getHandle, isEdgeVisible } from './utils'; -import { - Position, - Edge, - Node, - HandleElement, - Elements, - ConnectionLineType, - ConnectionLineComponent, - Transform, -} from '../../types'; +import { getEdgePositions, getHandle, isEdgeVisible, getSourceTargetNode } from './utils'; +import { Position, Edge, Node, Elements, ConnectionLineType, ConnectionLineComponent, Transform } from '../../types'; interface EdgeRendererProps { edgeTypes: any; @@ -24,46 +15,9 @@ interface EdgeRendererProps { arrowHeadColor: string; markerEndId?: string; connectionLineComponent?: ConnectionLineComponent; + onlyRenderVisibleElements: boolean; } -interface EdgePositions { - sourceX: number; - sourceY: number; - targetX: number; - targetY: number; -} - -function getEdgePositions( - sourceNode: Node, - sourceHandle: HandleElement | unknown, - sourcePosition: Position, - targetNode: Node, - targetHandle: HandleElement | unknown, - targetPosition: Position -): EdgePositions { - const sourceHandlePos = getHandlePosition(sourcePosition, sourceNode, sourceHandle); - const sourceX = sourceNode.__rf.position.x + sourceHandlePos.x; - const sourceY = sourceNode.__rf.position.y + sourceHandlePos.y; - - const targetHandlePos = getHandlePosition(targetPosition, targetNode, targetHandle); - const targetX = targetNode.__rf.position.x + targetHandlePos.x; - const targetY = targetNode.__rf.position.y + targetHandlePos.y; - - return { - sourceX, - sourceY, - targetX, - targetY, - }; -} - -type SourceTargetNode = { - sourceNode: Node | null; - targetNode: Node | null; -}; - -const initialSourceTarget: SourceTargetNode = { sourceNode: null, targetNode: null }; - function renderEdge( edge: Edge, props: EdgeRendererProps, @@ -72,18 +26,12 @@ function renderEdge( elementsSelectable: boolean, transform: Transform, width: number, - height: number + height: number, + onlyRenderVisibleElements: boolean ) { const sourceHandleId = edge.sourceHandle || null; const targetHandleId = edge.targetHandle || null; - const { sourceNode, targetNode } = nodes.reduce((res, node) => { - if (node.id === edge.source) { - res.sourceNode = node; - } else if (node.id === edge.target) { - res.targetNode = node; - } - return res; - }, initialSourceTarget); + const { sourceNode, targetNode } = getSourceTargetNode(edge, nodes); if (!sourceNode) { console.warn(`couldn't create edge for source id: ${edge.source}`); @@ -99,15 +47,17 @@ function renderEdge( return null; } - const renderEdge = isEdgeVisible({ - sourcePos: sourceNode.__rf.position, - targetPos: targetNode.__rf.position, - width, - height, - transform, - }); + const isVisible = onlyRenderVisibleElements + ? isEdgeVisible({ + sourcePos: sourceNode.__rf.position, + targetPos: targetNode.__rf.position, + width, + height, + transform, + }) + : true; - if (!renderEdge) { + if (!isVisible) { return null; } @@ -192,7 +142,13 @@ const EdgeRenderer = (props: EdgeRendererProps) => { return null; } - const { connectionLineType, arrowHeadColor, connectionLineStyle, connectionLineComponent } = props; + const { + connectionLineType, + arrowHeadColor, + connectionLineStyle, + connectionLineComponent, + onlyRenderVisibleElements, + } = props; const transformStyle = `translate(${transform[0]},${transform[1]}) scale(${transform[2]})`; const renderConnectionLine = connectionNodeId && connectionHandleType; @@ -201,7 +157,17 @@ const EdgeRenderer = (props: EdgeRendererProps) => { {edges.map((edge: Edge) => - renderEdge(edge, props, nodes, selectedElements, elementsSelectable, transform, width, height) + renderEdge( + edge, + props, + nodes, + selectedElements, + elementsSelectable, + transform, + width, + height, + onlyRenderVisibleElements + ) )} {renderConnectionLine && ( { + const sourceHandlePos = getHandlePosition(sourcePosition, sourceNode, sourceHandle); + const sourceX = sourceNode.__rf.position.x + sourceHandlePos.x; + const sourceY = sourceNode.__rf.position.y + sourceHandlePos.y; + + const targetHandlePos = getHandlePosition(targetPosition, targetNode, targetHandle); + const targetX = targetNode.__rf.position.x + targetHandlePos.x; + const targetY = targetNode.__rf.position.y + targetHandlePos.y; + + return { + sourceX, + sourceY, + targetX, + targetY, + }; +}; + interface IsEdgeVisibleParams { sourcePos: XYPosition; targetPos: XYPosition; @@ -118,3 +159,22 @@ export function isEdgeVisible({ sourcePos, targetPos, width, height, transform } return overlappingArea > 0; } + +type SourceTargetNode = { + sourceNode: Node | null; + targetNode: Node | null; +}; + +export const getSourceTargetNode = (edge: Edge, nodes: Node[]): SourceTargetNode => { + return nodes.reduce( + (res, node) => { + if (node.id === edge.source) { + res.sourceNode = node; + } else if (node.id === edge.target) { + res.targetNode = node; + } + return res; + }, + { sourceNode: null, targetNode: null } as SourceTargetNode + ); +}; diff --git a/src/container/GraphView/index.tsx b/src/container/GraphView/index.tsx index 2e25c628..ee67ae0f 100644 --- a/src/container/GraphView/index.tsx +++ b/src/container/GraphView/index.tsx @@ -93,7 +93,6 @@ const GraphView = ({ const setMinZoom = useStoreActions((actions) => actions.setMinZoom); const setMaxZoom = useStoreActions((actions) => actions.setMaxZoom); const setTranslateExtent = useStoreActions((actions) => actions.setTranslateExtent); - const setOnlyRenderVisibleElements = useStoreActions((actions) => actions.setOnlyRenderVisibleElements); const currentStore = useStore(); const { zoomIn, zoomOut, zoomTo, transform, fitView, initialized } = useZoomPanHelper(); @@ -188,12 +187,6 @@ const GraphView = ({ } }, [translateExtent]); - useEffect(() => { - if (typeof onlyRenderVisibleElements !== 'undefined') { - setOnlyRenderVisibleElements(onlyRenderVisibleElements); - } - }, [translateExtent]); - return ( ); diff --git a/src/container/NodeRenderer/index.tsx b/src/container/NodeRenderer/index.tsx index f44bcd52..42219b99 100644 --- a/src/container/NodeRenderer/index.tsx +++ b/src/container/NodeRenderer/index.tsx @@ -1,5 +1,6 @@ import React, { memo, useMemo, ComponentType, MouseEvent } from 'react'; +import { getNodesInside } from '../../utils/graph'; import { useStoreState } from '../../store/hooks'; import { Node, NodeTypesType, WrapNodeProps, Edge } from '../../types'; @@ -15,6 +16,7 @@ interface NodeRendererProps { onNodeDragStop?: (event: MouseEvent, node: Node) => void; snapToGrid: boolean; snapGrid: [number, number]; + onlyRenderVisibleElements: boolean; } const NodeRenderer = (props: NodeRendererProps) => { @@ -23,7 +25,10 @@ const NodeRenderer = (props: NodeRendererProps) => { const nodesDraggable = useStoreState((state) => state.nodesDraggable); const nodesConnectable = useStoreState((state) => state.nodesConnectable); const elementsSelectable = useStoreState((state) => state.elementsSelectable); - const visibleNodes = useStoreState((state) => state.visibleNodes); + const viewportBox = useStoreState((state) => state.viewportBox); + const nodes = useStoreState((state) => state.nodes); + + const visibleNodes = props.onlyRenderVisibleElements ? getNodesInside(nodes, viewportBox, transform, true) : nodes; const transformStyle = useMemo( () => ({ diff --git a/src/store/index.ts b/src/store/index.ts index 1e6a86bc..89280ade 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -44,12 +44,11 @@ export interface StoreModel { height: number; transform: Transform; elements: Elements; - visibleNodes: Computed; nodes: Computed; edges: Computed; selectedElements: Elements | null; selectedNodesBbox: Rect; - onlyRenderVisibleElements: boolean; + viewportBox: Computed; d3Zoom: ZoomBehavior | null; d3Selection: D3Selection | null; @@ -132,8 +131,6 @@ export interface StoreModel { unsetUserSelection: Action; setMultiSelectionActive: Action; - - setOnlyRenderVisibleElements: Action; } export const storeModel: StoreModel = { @@ -142,19 +139,10 @@ export const storeModel: StoreModel = { transform: [0, 0, 1], elements: [], nodes: computed((state) => state.elements.filter(isNode)), - visibleNodes: computed((state) => { - if (!state.onlyRenderVisibleElements) { - return state.nodes; - } - - const viewportBox = { x: 0, y: 0, width: state.width, height: state.height }; - - return getNodesInside(state.nodes, viewportBox, state.transform, true); - }), + viewportBox: computed((state) => ({ x: 0, y: 0, width: state.width, height: state.height })), edges: computed((state) => state.elements.filter(isEdge)), selectedElements: null, selectedNodesBbox: { x: 0, y: 0, width: 0, height: 0 }, - onlyRenderVisibleElements: true, d3Zoom: null, d3Selection: null, @@ -452,10 +440,6 @@ export const storeModel: StoreModel = { setMultiSelectionActive: action((state, isActive) => { state.multiSelectionActive = isActive; }), - - setOnlyRenderVisibleElements: action((state, onlyRenderVisible) => { - state.onlyRenderVisibleElements = onlyRenderVisible; - }), }; const nodeEnv: string = (typeof __ENV__ !== 'undefined' && __ENV__) as string;