arrangeInTree static method

List<NmGraphNodeData> arrangeInTree(
  1. List<NmGraphNodeData> nodes,
  2. List<NmGraphEdgeData> edges, {
  3. String? rootId,
  4. Offset topLeft = const Offset(50, 50),
  5. double horizontalSpacing = 100,
  6. 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;
}