refactor(elements): render only visible elements
This commit is contained in:
@@ -4,11 +4,10 @@ import shallow from 'zustand/shallow';
|
||||
import { useStore } from '../../store';
|
||||
import ConnectionLine from '../../components/ConnectionLine/index';
|
||||
import MarkerDefinitions from './MarkerDefinitions';
|
||||
import { getEdgePositions, getHandle, getSourceTargetNodes } from './utils';
|
||||
import { getEdgePositions, getHandle, getSourceTargetNodes, isEdgeVisible } from './utils';
|
||||
import {
|
||||
Position,
|
||||
Edge,
|
||||
Node,
|
||||
Connection,
|
||||
ConnectionLineType,
|
||||
ConnectionLineComponent,
|
||||
@@ -19,8 +18,6 @@ import {
|
||||
} from '../../types';
|
||||
|
||||
interface EdgeRendererProps {
|
||||
nodes: Node[];
|
||||
edges: Edge[];
|
||||
edgeTypes: any;
|
||||
connectionLineType: ConnectionLineType;
|
||||
connectionLineStyle?: CSSProperties;
|
||||
@@ -162,26 +159,12 @@ const Edge = memo(
|
||||
targetPosition
|
||||
);
|
||||
|
||||
// const isVisible = onlyRenderVisibleElements
|
||||
// ? isEdgeVisible({
|
||||
// sourcePos: { x: sourceX, y: sourceY },
|
||||
// targetPos: { x: targetX, y: targetY },
|
||||
// width,
|
||||
// height,
|
||||
// transform,
|
||||
// })
|
||||
// : true;
|
||||
|
||||
// if (!isVisible) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
return (
|
||||
<EdgeComponent
|
||||
key={edge.id}
|
||||
id={edge.id}
|
||||
className={edge.className}
|
||||
type={edge.type}
|
||||
type={edgeType}
|
||||
data={edge.data}
|
||||
onClick={onEdgeClick}
|
||||
isSelected={!!edge.isSelected}
|
||||
@@ -233,6 +216,7 @@ const selector = (s: ReactFlowState) => ({
|
||||
width: s.width,
|
||||
height: s.height,
|
||||
connectionMode: s.connectionMode,
|
||||
nodes: s.nodes,
|
||||
});
|
||||
|
||||
const EdgeRenderer = (props: EdgeRendererProps) => {
|
||||
@@ -247,8 +231,42 @@ const EdgeRenderer = (props: EdgeRendererProps) => {
|
||||
width,
|
||||
height,
|
||||
connectionMode,
|
||||
nodes,
|
||||
} = useStore(selector, shallow);
|
||||
|
||||
const edges = useStore(
|
||||
useCallback(
|
||||
(s: ReactFlowState) => {
|
||||
if (!props.onlyRenderVisibleElements) {
|
||||
return s.edges;
|
||||
}
|
||||
|
||||
return s.edges.filter((e) => {
|
||||
const { sourceNode, targetNode } = getSourceTargetNodes(e, s.nodes);
|
||||
|
||||
return (
|
||||
sourceNode?.width &&
|
||||
sourceNode?.height &&
|
||||
targetNode?.width &&
|
||||
targetNode?.height &&
|
||||
isEdgeVisible({
|
||||
sourcePos: sourceNode.position,
|
||||
targetPos: targetNode.position,
|
||||
sourceWidth: sourceNode.width,
|
||||
sourceHeight: sourceNode.height,
|
||||
targetWidth: targetNode.width,
|
||||
targetHeight: targetNode.height,
|
||||
width: s.width,
|
||||
height: s.height,
|
||||
transform: s.transform,
|
||||
})
|
||||
);
|
||||
});
|
||||
},
|
||||
[props.onlyRenderVisibleElements]
|
||||
)
|
||||
);
|
||||
|
||||
if (!width) {
|
||||
return null;
|
||||
}
|
||||
@@ -260,8 +278,8 @@ const EdgeRenderer = (props: EdgeRendererProps) => {
|
||||
<svg width={width} height={height} className="react-flow__edges">
|
||||
<MarkerDefinitions color={arrowHeadColor} />
|
||||
<g transform={`translate(${transform[0]},${transform[1]}) scale(${transform[2]})`}>
|
||||
{props.edges.map((edge: Edge) => {
|
||||
const { sourceNode, targetNode } = getSourceTargetNodes(edge, props.nodes);
|
||||
{edges.map((edge: Edge) => {
|
||||
const { sourceNode, targetNode } = getSourceTargetNodes(edge, nodes);
|
||||
return (
|
||||
<Edge
|
||||
key={edge.id}
|
||||
|
||||
@@ -116,17 +116,31 @@ export const getEdgePositions = (
|
||||
interface IsEdgeVisibleParams {
|
||||
sourcePos: XYPosition;
|
||||
targetPos: XYPosition;
|
||||
sourceWidth: number;
|
||||
sourceHeight: number;
|
||||
targetWidth: number;
|
||||
targetHeight: number;
|
||||
width: number;
|
||||
height: number;
|
||||
transform: Transform;
|
||||
}
|
||||
|
||||
export function isEdgeVisible({ sourcePos, targetPos, width, height, transform }: IsEdgeVisibleParams): boolean {
|
||||
export function isEdgeVisible({
|
||||
sourcePos,
|
||||
targetPos,
|
||||
sourceWidth,
|
||||
sourceHeight,
|
||||
targetWidth,
|
||||
targetHeight,
|
||||
width,
|
||||
height,
|
||||
transform,
|
||||
}: IsEdgeVisibleParams): boolean {
|
||||
const edgeBox = {
|
||||
x: Math.min(sourcePos.x, targetPos.x),
|
||||
y: Math.min(sourcePos.y, targetPos.y),
|
||||
x2: Math.max(sourcePos.x, targetPos.x),
|
||||
y2: Math.max(sourcePos.y, targetPos.y),
|
||||
x2: Math.max(sourcePos.x + sourceWidth, targetPos.x + targetWidth),
|
||||
y2: Math.max(sourcePos.y + sourceHeight, targetPos.y + targetHeight),
|
||||
};
|
||||
|
||||
if (edgeBox.x === edgeBox.x2) {
|
||||
|
||||
@@ -13,7 +13,6 @@ import { ReactFlowState } from '../../types';
|
||||
interface FlowRendererProps
|
||||
extends Omit<
|
||||
GraphViewProps,
|
||||
| 'elements'
|
||||
| 'snapToGrid'
|
||||
| 'nodeTypes'
|
||||
| 'edgeTypes'
|
||||
@@ -22,8 +21,6 @@ interface FlowRendererProps
|
||||
| 'arrowHeadColor'
|
||||
| 'onlyRenderVisibleElements'
|
||||
| 'selectNodesOnDrag'
|
||||
| 'nodes'
|
||||
| 'edges'
|
||||
> {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
@@ -4,14 +4,14 @@ import { useStoreApi } from '../../store';
|
||||
import FlowRenderer from '../FlowRenderer';
|
||||
import NodeRenderer from '../NodeRenderer';
|
||||
import EdgeRenderer from '../EdgeRenderer';
|
||||
import { onLoadProject, onLoadGetElements, onLoadToObject } from '../../utils/graph';
|
||||
import { onLoadProject, onLoadGetNodes, onLoadGetEdges, onLoadToObject } from '../../utils/graph';
|
||||
import useZoomPanHelper from '../../hooks/useZoomPanHelper';
|
||||
|
||||
import { ReactFlowProps } from '../ReactFlow';
|
||||
|
||||
import { NodeTypesType, EdgeTypesType, ConnectionLineType, KeyCode } from '../../types';
|
||||
|
||||
export interface GraphViewProps extends Omit<ReactFlowProps, 'onSelectionChange'> {
|
||||
export interface GraphViewProps extends Omit<ReactFlowProps, 'onSelectionChange' | 'nodes' | 'edges'> {
|
||||
nodeTypes: NodeTypesType;
|
||||
edgeTypes: EdgeTypesType;
|
||||
selectionKeyCode: KeyCode;
|
||||
@@ -26,8 +26,6 @@ export interface GraphViewProps extends Omit<ReactFlowProps, 'onSelectionChange'
|
||||
}
|
||||
|
||||
const GraphView = ({
|
||||
nodes,
|
||||
edges,
|
||||
nodeTypes,
|
||||
edgeTypes,
|
||||
onMove,
|
||||
@@ -97,7 +95,8 @@ const GraphView = ({
|
||||
zoomTo,
|
||||
setTransform: transform,
|
||||
project: onLoadProject(store.getState),
|
||||
getElements: onLoadGetElements(store.getState),
|
||||
getNodes: onLoadGetNodes(store.getState),
|
||||
getEdges: onLoadGetEdges(store.getState),
|
||||
toObject: onLoadToObject(store.getState),
|
||||
});
|
||||
}
|
||||
@@ -147,7 +146,6 @@ const GraphView = ({
|
||||
onNodeDragStart={onNodeDragStart}
|
||||
selectNodesOnDrag={selectNodesOnDrag}
|
||||
onlyRenderVisibleElements={onlyRenderVisibleElements}
|
||||
nodes={nodes}
|
||||
/>
|
||||
<EdgeRenderer
|
||||
edgeTypes={edgeTypes}
|
||||
@@ -167,8 +165,6 @@ const GraphView = ({
|
||||
onEdgeUpdateStart={onEdgeUpdateStart}
|
||||
onEdgeUpdateEnd={onEdgeUpdateEnd}
|
||||
edgeUpdaterRadius={edgeUpdaterRadius}
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
/>
|
||||
</FlowRenderer>
|
||||
);
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import React, { memo, useMemo, ComponentType, MouseEvent } from 'react';
|
||||
import React, { memo, useMemo, ComponentType, MouseEvent, useCallback } from 'react';
|
||||
import shallow from 'zustand/shallow';
|
||||
|
||||
import { useStore } from '../../store';
|
||||
import { Node, NodeTypesType, ReactFlowState, WrapNodeProps } from '../../types';
|
||||
import { getNodesInside } from '../../utils/graph';
|
||||
interface NodeRendererProps {
|
||||
nodeTypes: NodeTypesType;
|
||||
selectNodesOnDrag: boolean;
|
||||
@@ -16,7 +17,6 @@ interface NodeRendererProps {
|
||||
onNodeDrag?: (event: MouseEvent, node: Node) => void;
|
||||
onNodeDragStop?: (event: MouseEvent, node: Node) => void;
|
||||
onlyRenderVisibleElements: boolean;
|
||||
nodes: Node[];
|
||||
}
|
||||
|
||||
const selector = (s: ReactFlowState) => ({
|
||||
@@ -40,9 +40,16 @@ const NodeRenderer = (props: NodeRendererProps) => {
|
||||
snapToGrid,
|
||||
} = useStore(selector, shallow);
|
||||
|
||||
// const visibleNodes = props.onlyRenderVisibleElements
|
||||
// ? getNodesInside(nodes, { x: 0, y: 0, width, height }, transform, true)
|
||||
// : nodes;
|
||||
const nodes = useStore(
|
||||
useCallback(
|
||||
(s: ReactFlowState) => {
|
||||
return props.onlyRenderVisibleElements
|
||||
? getNodesInside(s.nodes, { x: 0, y: 0, width: s.width, height: s.height }, s.transform, true)
|
||||
: s.nodes;
|
||||
},
|
||||
[props.onlyRenderVisibleElements]
|
||||
)
|
||||
);
|
||||
|
||||
const transformStyle = useMemo(
|
||||
() => ({
|
||||
@@ -68,7 +75,7 @@ const NodeRenderer = (props: NodeRendererProps) => {
|
||||
|
||||
return (
|
||||
<div className="react-flow__nodes" style={transformStyle}>
|
||||
{props.nodes.map((node) => {
|
||||
{nodes.map((node) => {
|
||||
const nodeType = node.type || 'default';
|
||||
const NodeComponent = (props.nodeTypes[nodeType] || props.nodeTypes.default) as ComponentType<WrapNodeProps>;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import { BezierEdge, StepEdge, SmoothStepEdge, StraightEdge } from '../../compon
|
||||
import { createEdgeTypes } from '../EdgeRenderer/utils';
|
||||
import Wrapper from './Wrapper';
|
||||
import {
|
||||
Elements,
|
||||
OnSelectionChangeFunc,
|
||||
NodeTypesType,
|
||||
EdgeTypesType,
|
||||
OnLoadFunc,
|
||||
@@ -81,7 +81,7 @@ export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'on
|
||||
onMove?: (flowTransform?: FlowTransform) => void;
|
||||
onMoveStart?: (flowTransform?: FlowTransform) => void;
|
||||
onMoveEnd?: (flowTransform?: FlowTransform) => void;
|
||||
onSelectionChange?: (elements: Elements | null) => void;
|
||||
onSelectionChange?: OnSelectionChangeFunc;
|
||||
onSelectionDragStart?: (event: ReactMouseEvent, nodes: Node[]) => void;
|
||||
onSelectionDrag?: (event: ReactMouseEvent, nodes: Node[]) => void;
|
||||
onSelectionDragStop?: (event: ReactMouseEvent, nodes: Node[]) => void;
|
||||
@@ -227,8 +227,6 @@ const ReactFlow = forwardRef<ReactFlowRefType, ReactFlowProps>(
|
||||
<div {...rest} ref={ref} className={reactFlowClasses}>
|
||||
<Wrapper>
|
||||
<GraphView
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
onLoad={onLoad}
|
||||
onMove={onMove}
|
||||
onMoveStart={onMoveStart}
|
||||
|
||||
Reference in New Issue
Block a user