refactor(elements): render only visible elements

This commit is contained in:
moklick
2021-10-19 14:57:34 +02:00
parent 410b12946d
commit 1525af39cf
21 changed files with 376 additions and 217 deletions
+39 -21
View File
@@ -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}
+17 -3
View File
@@ -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) {
-3
View File
@@ -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 -8
View File
@@ -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>
);
+13 -6
View File
@@ -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>;
+2 -4
View File
@@ -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}