arrangeInTree static method
List<NmGraphNodeData>
arrangeInTree(
- List<
NmGraphNodeData> nodes, - List<
NmGraphEdgeData> edges, { - String? rootId,
- Offset topLeft = const Offset(50, 50),
- double horizontalSpacing = 100,
- double verticalSpacing = 100,
Arrange nodes in a hierarchical tree layout.
Implementation
static List<NmGraphNodeData> arrangeInTree(
List<NmGraphNodeData> nodes,
List<NmGraphEdgeData> edges, {
String? rootId,
Offset topLeft = const Offset(50, 50),
double horizontalSpacing = 100,
double verticalSpacing = 100,
}) {
if (nodes.isEmpty) return [];
// Find root node
final root = rootId != null ? nodes.firstWhere((n) => n.id == rootId, orElse: () => nodes.first) : nodes.first;
// Build adjacency map
final children = <String, List<String>>{};
for (final edge in edges) {
children.putIfAbsent(edge.sourceId, () => []).add(edge.targetId);
}
// BFS to assign levels
final levels = <String, int>{};
final queue = [root.id];
levels[root.id] = 0;
while (queue.isNotEmpty) {
final nodeId = queue.removeAt(0);
final level = levels[nodeId]!;
for (final childId in children[nodeId] ?? const <String>[]) {
if (!levels.containsKey(childId)) {
levels[childId] = level + 1;
queue.add(childId);
}
}
}
// Group nodes by level
final nodesByLevel = <int, List<String>>{};
for (final entry in levels.entries) {
nodesByLevel.putIfAbsent(entry.value, () => []).add(entry.key);
}
// Assign positions
final result = <NmGraphNodeData>[];
for (final node in nodes) {
final level = levels[node.id] ?? 0;
final nodesAtLevel = nodesByLevel[level] ?? [];
final indexAtLevel = nodesAtLevel.indexOf(node.id);
final totalAtLevel = nodesAtLevel.length;
final x = topLeft.dx + (indexAtLevel + 0.5) * horizontalSpacing * (totalAtLevel > 1 ? 1 : 0) + horizontalSpacing / 2;
final y = topLeft.dy + level * verticalSpacing;
result.add(node.copyWith(position: Offset(x, y)));
}
return result;
}