112 lines
4.1 KiB
JavaScript
112 lines
4.1 KiB
JavaScript
import { useCallback } from 'react';
|
|
import { isLeafNode } from './nodeUtils';
|
|
import { getStatusColor } from '../dataUtils';
|
|
|
|
export const useDataParser = (nodePositions, collapsedNodes) => {
|
|
const getNodeStyle = useCallback((item, isLeaf) => ({
|
|
width: isLeaf ? 60 : 70,
|
|
height: isLeaf ? 60 : 70,
|
|
borderRadius: '50%',
|
|
backgroundColor: getStatusColor(item.status),
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
color: 'black',
|
|
border: '2px solid #fff',
|
|
fontSize: isLeaf ? '0.8rem' : '1rem'
|
|
}), []);
|
|
|
|
const getCenterNodeStyle = useCallback((item) => ({
|
|
width: 80,
|
|
height: 80,
|
|
borderRadius: '50%',
|
|
backgroundColor: getStatusColor(item.status),
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
color: 'black',
|
|
border: '2px solid #fff',
|
|
fontSize: '1.2rem'
|
|
}), []);
|
|
|
|
const parseData = useCallback((data) => {
|
|
if (!data) return { nodes: [], edges: [] };
|
|
|
|
const nodes = [];
|
|
const edges = [];
|
|
const centerX = 500;
|
|
const centerY = 400;
|
|
const baseLevelRadius = 150;
|
|
|
|
const traverse = (item, parentId = null, level = 0, angleStart = 0, angleEnd = 2 * Math.PI, parentRadius = 0) => {
|
|
if (!item || collapsedNodes[parentId]) return; // Пропускаем свёрнутые узлы
|
|
|
|
const nodeId = item.id;
|
|
const items = item.items || [];
|
|
const isLeaf = isLeafNode(item);
|
|
|
|
const savedPosition = nodePositions[nodeId];
|
|
let position = savedPosition || {
|
|
x: Math.round(centerX + Math.cos((angleStart + angleEnd) / 2) * (parentRadius + baseLevelRadius)),
|
|
y: Math.round(centerY + Math.sin((angleStart + angleEnd) / 2) * (parentRadius + baseLevelRadius))
|
|
};
|
|
|
|
const node = {
|
|
id: nodeId,
|
|
type: 'customNode',
|
|
position,
|
|
data: {
|
|
...item,
|
|
label: item.title,
|
|
style: getNodeStyle(item, isLeaf), // Переносим стили в data
|
|
hasChildren: items.length > 0,
|
|
collapsed: collapsedNodes[nodeId]
|
|
}
|
|
};
|
|
|
|
nodes.push(node);
|
|
|
|
if (parentId) {
|
|
edges.push({
|
|
id: `${parentId}-${nodeId}`,
|
|
source: parentId,
|
|
target: nodeId,
|
|
style: { stroke: isLeaf ? '#aaa' : '#666', strokeWidth: isLeaf ? 1 : 2 }
|
|
});
|
|
}
|
|
|
|
if (!collapsedNodes[nodeId] && items.length > 0) {
|
|
const spreadAngle = angleEnd - angleStart;
|
|
items.forEach((child, index) => {
|
|
if (!child) return;
|
|
const itemAngleStart = angleStart + (index / items.length) * spreadAngle;
|
|
const itemAngleEnd = angleStart + ((index + 1) / items.length) * spreadAngle;
|
|
traverse(child, nodeId, level + 1, itemAngleStart, itemAngleEnd, parentRadius + baseLevelRadius);
|
|
});
|
|
}
|
|
};
|
|
|
|
const centerNode = {
|
|
id: data.id,
|
|
type: 'customNode', // Добавляем тип узла
|
|
position: nodePositions[data.id] || { x: centerX, y: centerY },
|
|
style: getCenterNodeStyle(data),
|
|
data: { label: data.title, hasChildren: data.items.length > 0, collapsed: collapsedNodes[data.id] }
|
|
};
|
|
|
|
|
|
nodes.push(centerNode);
|
|
|
|
if (!collapsedNodes[data.id] && data.items.length > 0) {
|
|
const angleStep = (2 * Math.PI) / data.items.length;
|
|
data.items.forEach((child, index) => {
|
|
if (!child) return;
|
|
traverse(child, data.id, 1, index * angleStep, (index + 1) * angleStep, 0);
|
|
});
|
|
}
|
|
|
|
return { nodes, edges };
|
|
}, [nodePositions, collapsedNodes, getNodeStyle, getCenterNodeStyle]);
|
|
|
|
return { parseData };
|
|
}; |