99 lines
2.7 KiB
JavaScript
99 lines
2.7 KiB
JavaScript
import React, { useEffect, useMemo, useRef } from 'react';
|
|
import ReactFlow, { Controls, Background } from 'reactflow';
|
|
import 'reactflow/dist/style.css';
|
|
import { debounce } from 'lodash';
|
|
import { useFlowChart } from './FlowChartComponents/useFlowChart';
|
|
import { useNodeHandlers } from './FlowChartComponents/useNodeHandlers';
|
|
import { useDataParser } from './FlowChartComponents/DataParser';
|
|
import NodeWrapper from './FlowChartComponents/NodeWrapper';
|
|
|
|
const nodeTypes = {
|
|
customNode: NodeWrapper
|
|
};
|
|
|
|
const FlowChart = ({ data }) => {
|
|
const {
|
|
nodes,
|
|
edges,
|
|
nodePositions,
|
|
setNodes,
|
|
setEdges,
|
|
onNodesChange,
|
|
onEdgesChange,
|
|
setNodePositions,
|
|
collapsedNodes,
|
|
toggleNodeCollapse
|
|
} = useFlowChart(data);
|
|
|
|
const { parseData } = useDataParser(nodePositions, collapsedNodes);
|
|
const initialized = useRef(false);
|
|
|
|
const debouncedSetNodePositions = useMemo(
|
|
() => debounce(setNodePositions, 100),
|
|
[setNodePositions]
|
|
);
|
|
|
|
const { onNodeDrag, onNodeDragStop } = useNodeHandlers(debouncedSetNodePositions);
|
|
|
|
useEffect(() => {
|
|
const { nodes: initialNodes, edges: initialEdges } = parseData(data);
|
|
setNodes(initialNodes);
|
|
setEdges(initialEdges);
|
|
|
|
// Автоматически сворачиваем узлы, которые являются родителями последнего уровня
|
|
if (!initialized.current && data) {
|
|
const findAndCollapseLastLevelParents = (items) => {
|
|
items.forEach(item => {
|
|
if (item.items && item.items.length > 0) {
|
|
const hasGrandchildren = item.items.some(child =>
|
|
child.items && child.items.length > 0
|
|
);
|
|
|
|
if (!hasGrandchildren) {
|
|
toggleNodeCollapse(item.id);
|
|
} else {
|
|
findAndCollapseLastLevelParents(item.items);
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
findAndCollapseLastLevelParents(data.items || []);
|
|
initialized.current = true;
|
|
}
|
|
}, [data, parseData, setNodes, setEdges, toggleNodeCollapse]);
|
|
|
|
const onNodeClick = (event, node) => {
|
|
if (node.data.hasChildren) {
|
|
toggleNodeCollapse(node.id);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
return () => {
|
|
debouncedSetNodePositions.cancel();
|
|
};
|
|
}, [debouncedSetNodePositions]);
|
|
|
|
return (
|
|
<div style={{ height: '85vh', width: '100%' }}>
|
|
<ReactFlow
|
|
nodes={nodes}
|
|
edges={edges}
|
|
nodeTypes={nodeTypes}
|
|
onNodesChange={onNodesChange}
|
|
onEdgesChange={onEdgesChange}
|
|
onNodeDrag={onNodeDrag}
|
|
onNodeDragStop={onNodeDragStop}
|
|
nodeDragThreshold={1}
|
|
onNodeClick={onNodeClick}
|
|
fitView
|
|
>
|
|
<Background />
|
|
<Controls />
|
|
</ReactFlow>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default React.memo(FlowChart); |