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
+2 -2
View File
@@ -36,8 +36,8 @@ const BasicFlow = () => {
const [nodes, setNodes] = useState<Node[]>(initialNodes);
const [edges, setEdges] = useState<Edge[]>(initialEdges);
const onConnect = useCallback((params: Edge | Connection, nds: Node[]) => {
setEdges((eds) => addEdge(params, nds, eds));
const onConnect = useCallback((params: Edge | Connection) => {
setEdges((eds) => addEdge(params, eds));
}, []);
const onLoad = useCallback((reactFlowInstance: OnLoadParams) => setRfInstance(reactFlowInstance), []);
@@ -0,0 +1,25 @@
import React, { memo, FC, CSSProperties } from 'react';
import { Handle, Position, NodeProps, Connection, Edge } from 'react-flow-renderer';
const targetHandleStyle: CSSProperties = { background: '#555' };
const sourceHandleStyleA: CSSProperties = { ...targetHandleStyle, top: 10 };
const sourceHandleStyleB: CSSProperties = { ...targetHandleStyle, bottom: 10, top: 'auto' };
const onConnect = (params: Connection | Edge) => console.log('handle onConnect', params);
const ColorSelectorNode: FC<NodeProps> = ({ data, isConnectable }) => {
return (
<>
<Handle type="target" position={Position.Left} style={targetHandleStyle} onConnect={onConnect} />
<div>
Custom Color Picker Node: <strong>{data.color}</strong>
</div>
<input className="nodrag" type="color" onChange={data.onChange} defaultValue={data.color} />
<Handle type="source" position={Position.Right} id="a" style={sourceHandleStyleA} isConnectable={isConnectable} />
<Handle type="source" position={Position.Right} id="b" style={sourceHandleStyleB} isConnectable={isConnectable} />
</>
);
};
export default memo(ColorSelectorNode);
+147
View File
@@ -0,0 +1,147 @@
import { useState, useEffect, MouseEvent, useCallback } from 'react';
import { ChangeEvent } from 'react';
import ReactFlow, {
addEdge,
MiniMap,
Controls,
Node,
OnLoadParams,
Position,
SnapGrid,
Connection,
Edge,
NodeChange,
applyNodeChanges,
applyEdgeChanges,
EdgeChange,
} from 'react-flow-renderer';
import ColorSelectorNode from './ColorSelectorNode';
const onLoad = (reactFlowInstance: OnLoadParams) => console.log('flow loaded:', reactFlowInstance);
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
const initBgColor = '#1A192B';
const connectionLineStyle = { stroke: '#fff' };
const snapGrid: SnapGrid = [16, 16];
const nodeTypes = {
selectorNode: ColorSelectorNode,
};
const CustomNodeFlow = () => {
const [nodes, setNodes] = useState<Node[]>([]);
const [edges, setEdges] = useState<Edge[]>([]);
const [bgColor, setBgColor] = useState<string>(initBgColor);
useEffect(() => {
const onChange = (event: ChangeEvent<HTMLInputElement>) => {
setNodes((nds) =>
nds.map((node) => {
if (node.id !== '2') {
return node;
}
const color = event.target.value;
setBgColor(color);
return {
...node,
data: {
...node.data,
color,
},
};
})
);
};
setNodes([
{
id: '1',
type: 'input',
data: { label: 'An input node' },
position: { x: 0, y: 50 },
sourcePosition: Position.Right,
},
{
id: '2',
type: 'selectorNode',
data: { onChange: onChange, color: initBgColor },
style: { border: '1px solid #777', padding: 10 },
position: { x: 250, y: 50 },
},
{
id: '3',
type: 'output',
data: { label: 'Output A' },
position: { x: 550, y: 25 },
targetPosition: Position.Left,
},
{
id: '4',
type: 'output',
data: { label: 'Output B' },
position: { x: 550, y: 100 },
targetPosition: Position.Left,
},
]);
setEdges([
{ id: 'e1-2', source: '1', target: '2', animated: true, style: { stroke: '#fff' } },
{ id: 'e2a-3', source: '2', sourceHandle: 'a', target: '3', animated: true, style: { stroke: '#fff' } },
{ id: 'e2b-4', source: '2', sourceHandle: 'b', target: '4', animated: true, style: { stroke: '#fff' } },
]);
}, []);
const onConnect = (params: Connection | Edge) =>
setEdges((eds) => addEdge({ ...params, animated: true, style: { stroke: '#fff' } }, eds));
const onNodesChange = useCallback((changes: NodeChange[]) => {
setNodes((ns) => applyNodeChanges(changes, ns));
}, []);
const onEdgesChange = useCallback((changes: EdgeChange[]) => {
setEdges((es) => applyEdgeChanges(changes, es));
}, []);
return (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onNodeClick={onNodeClick}
onConnect={onConnect}
onNodeDragStop={onNodeDragStop}
style={{ background: bgColor }}
onLoad={onLoad}
nodeTypes={nodeTypes}
connectionLineStyle={connectionLineStyle}
snapToGrid={true}
snapGrid={snapGrid}
defaultZoom={1.5}
>
<MiniMap
nodeStrokeColor={(n: Node): string => {
if (n.type === 'input') return '#0041d0';
if (n.type === 'selectorNode') return bgColor;
if (n.type === 'output') return '#ff0072';
return '#eee';
}}
nodeColor={(n: Node): string => {
if (n.type === 'selectorNode') return bgColor;
return '#fff';
}}
/>
<Controls />
</ReactFlow>
);
};
export default CustomNodeFlow;
+19 -10
View File
@@ -8,25 +8,27 @@ import ReactFlow, {
Node,
NodeChange,
applyNodeChanges,
Connection,
addEdge,
} from 'react-flow-renderer';
import { getElements } from './utils';
import { getNodesAndEdges } from './utils';
const buttonWrapperStyles: CSSProperties = { position: 'absolute', right: 10, top: 10, zIndex: 4 };
const onLoad = (reactFlowInstance: OnLoadParams) => {
reactFlowInstance.fitView();
console.log(reactFlowInstance.getElements());
console.log(reactFlowInstance.getNodes());
};
const initialElements = getElements(30, 30);
const { nodes: initialNodes, edges: initialEdges } = getNodesAndEdges(30, 30);
const StressFlow = () => {
const [nodes, setNodes] = useState<Node[]>(initialElements.nodes);
const [edges, setEdges] = useState<Edge[]>(initialElements.edges);
// const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
// const onConnect = (params: Connection | Edge, nds: Node[]) => setElements((els) => addEdge(params, els));
const [nodes, setNodes] = useState<Node[]>(initialNodes);
const [edges, setEdges] = useState<Edge[]>(initialEdges);
const onConnect = useCallback((params: Edge | Connection) => {
setEdges((eds) => addEdge(params, eds));
}, []);
const updatePos = () => {
setNodes((nds) => {
return nds.map((n) => {
@@ -43,7 +45,7 @@ const StressFlow = () => {
const updateElements = () => {
const grid = Math.ceil(Math.random() * 10);
const initialElements = getElements(grid, grid);
const initialElements = getNodesAndEdges(grid, grid);
setNodes(initialElements.nodes);
setEdges(initialElements.edges);
};
@@ -53,7 +55,14 @@ const StressFlow = () => {
}, []);
return (
<ReactFlow nodes={nodes} edges={edges} onLoad={onLoad} onNodesChange={onNodesChange}>
<ReactFlow
onlyRenderVisibleElements
nodes={nodes}
edges={edges}
onLoad={onLoad}
onConnect={onConnect}
onNodesChange={onNodesChange}
>
<MiniMap />
<Controls />
<Background />
+1 -1
View File
@@ -5,7 +5,7 @@ type ElementsCollection = {
edges: Edge[];
};
export function getElements(xElements: number = 10, yElements: number = 10): ElementsCollection {
export function getNodesAndEdges(xElements: number = 10, yElements: number = 10): ElementsCollection {
const initialNodes = [];
const initialEdges: Edge[] = [];
let nodeId = 1;
+5
View File
@@ -5,6 +5,7 @@ import { BrowserRouter as Router, Route, Switch, withRouter } from 'react-router
import Basic from './Basic';
import UpdateNode from './UpdateNode';
import Stress from './Stress';
import CustomNode from './CustomNode';
import './index.css';
@@ -21,6 +22,10 @@ const routes = [
path: '/stress',
component: Stress,
},
{
path: '/custom-node',
component: CustomNode,
},
];
const Header = withRouter(({ history, location }) => {