import '@xyflow/react/dist/style.css';
import ELK from 'elkjs/lib/elk.bundled.js';
import { CARD_HEIGHT, CARD_WIDTH } from './getNodesEdges';
const elk = new ELK();
const elkOptions = {
'elk.algorithm': 'mrtree',
'elk.direction': 'DOWN',
'elk.spacing.nodeNode': '60',
'elk.spacing.componentComponent': '80',
'elk.mrtree.edgeRoutingMode': 'ORTHOGONAL',
'elk.mrtree.nodePlacement.strategy': 'SIMPLE',
'elk.mrtree.fixedAlignment': 'BALANCED',
'elk.mrtree.considerModelOrder': 'NODES_AND_EDGES',
'elk.mrtree.compaction.post.compaction.strategy': 'EDGE_LENGTH',
'elk.random.seed': '12345',
};
export const getLayoutedElements = async (
nodes: any[],
edges: any[],
options = {},
previousPositions?: Record<string, { x: number, y: number }>,
) => {
if (previousPositions && nodes.every(node => node.id in previousPositions)) {
const positionedNodes = nodes.map((node) => {
const prevPos = previousPositions[node.id];
return {
...node,
position: prevPos,
x: prevPos.x,
y: prevPos.y,
width: node.width || CARD_WIDTH,
height: node.height || CARD_HEIGHT,
targetPosition: 'top',
sourcePosition: 'bottom',
data: {
...node.data,
level: Math.floor(prevPos.y / 100),
},
};
});
return {
nodes: positionedNodes,
edges,
meta: {
layoutType: 'reused',
reused: true,
timestamp: new Date().toISOString(),
},
};
}
const graph = {
id: 'root',
layoutOptions: { ...elkOptions, ...options },
children: nodes.map(node => ({
...node,
width: node.width || CARD_WIDTH,
height: node.height || CARD_HEIGHT,
targetPosition: 'top',
sourcePosition: 'bottom',
'elk.mrtree.compaction': 'true',
'elk.mrtree.considerModelOrder': 'true',
})),
edges,
};
try {
const layoutedGraph = await elk.layout(graph);
const layoutedNodes = layoutedGraph?.children?.map((node) => {
const newX = (node.x || 0) + (window.innerWidth * 0.1);
const newY = (node.y || 0) + 50;
return {
...node,
position: { x: newX, y: newY },
x: newX,
y: newY,
data: {
...(node as any)?.data,
level: Math.floor((node.y || 0) / 100),
},
width: node.width || CARD_WIDTH,
height: node.height || CARD_HEIGHT,
targetPosition: 'top',
sourcePosition: 'bottom',
};
}) || [];
return {
nodes: layoutedNodes,
edges,
meta: {
layoutType: 'tree',
direction: 'vertical',
spacing: elkOptions['elk.spacing.nodeNode'],
algorithm: 'mrtree',
version: '1.0.0',
timestamp: new Date().toISOString(),
},
};
} catch (error) {
console.error('ELK树形布局计算错误:', error);
return {
nodes: [],
edges: [],
meta: {
error: error instanceof Error ? error.message : 'Unknown error',
success: false,
},
};
}
};