Files
mnote/src/lib/mindmap/layout/engines/logicalStructure.ts
T

63 lines
1.5 KiB
TypeScript

import {
LayoutEngine,
LayoutNode,
LayoutOptions,
LayoutResult,
MindmapNode,
MindmapTree,
} from '@/lib/mindmap/types';
interface PositionedNode {
node: MindmapNode;
depth: number;
index: number;
}
export class LogicalStructureLayout implements LayoutEngine {
readonly name = 'logical' as const;
compute(tree: MindmapTree, options: LayoutOptions = {}): LayoutResult {
const horizontalSpacing = options.horizontalSpacing ?? 280;
const verticalSpacing = options.verticalSpacing ?? 96;
const positioned: PositionedNode[] = [];
walk(tree, 0, positioned);
const nodes: LayoutNode[] = positioned.map((item) => ({
id: item.node.id,
parentId: item.node.parentId,
depth: item.depth,
data: item.node.data,
position: {
x: item.depth * horizontalSpacing,
y: item.index * verticalSpacing,
},
}));
const edges = nodes
.filter((n) => n.parentId)
.map((n) => ({
id: `${n.parentId}-${n.id}`,
source: n.parentId!,
target: n.id,
}));
const bounds = {
width: Math.max(...nodes.map((n) => n.position.x), 0) + horizontalSpacing,
height:
Math.max(...nodes.map((n) => n.position.y), 0) + verticalSpacing,
};
return { nodes, edges, bounds };
}
}
function walk(node: MindmapNode, depth: number, acc: PositionedNode[], nextIndex = { value: 0 }) {
acc.push({ node, depth, index: nextIndex.value++ });
node.children?.forEach((child) => {
child.parentId = node.id;
walk(child, depth + 1, acc, nextIndex);
});
}