calculateLayout static method

Map<String, Offset> calculateLayout(
  1. ElectricalNode? root
)

Calculate positions for all nodes in the tree Returns a map of node IDs to their calculated positions

Implementation

static Map<String, Offset> calculateLayout(ElectricalNode? root) {
  if (root == null) return {};

  final Map<String, Offset> positions = {};
  final Map<String, double> subtreeWidths = {};

  const double nodeW = kNodeWidth;
  const double siblingGap = 50.0;
  const double levelHeight = 250.0;

  // Phase 1: Calculate subtree widths (bottom-up)
  double calculateWidth(ElectricalNode node) {
    final children = _getChildren(node);

    if (children.isEmpty) {
      subtreeWidths[node.id] = nodeW;
      return nodeW;
    }

    double width = 0;
    for (var child in children) {
      width += calculateWidth(child);
    }
    width += (children.length - 1) * siblingGap;

    final myW = (width > nodeW ? width : nodeW);
    subtreeWidths[node.id] = myW;
    return myW;
  }

  calculateWidth(root);

  // Phase 2: Assign positions (top-down)
  void assignPosition(ElectricalNode node, double x, double y) {
    final myWidth = subtreeWidths[node.id]!;
    final centeredX = x + (myWidth - nodeW) / 2;

    // Ensure every node gets a position (including Panels)
    positions[node.id] = Offset(centeredX, y);

    final children = _getChildren(node);
    if (children.isEmpty) return;

    final childY = y + levelHeight;

    // Force Center children distribution
    double totalChildrenWidth = 0;
    for (var child in children) {
      totalChildrenWidth += subtreeWidths[child.id]!;
    }
    if (children.length > 1) {
      totalChildrenWidth += (children.length - 1) * siblingGap;
    }

    // Start X for children (Centered under parent's allocated width)
    double currentX = x + (myWidth - totalChildrenWidth) / 2;

    for (var child in children) {
      assignPosition(child, currentX, childY);
      currentX += subtreeWidths[child.id]! + siblingGap;
    }
  }

  // Start layout in "middle" of canvas (matching old implementation)
  // Canvas is 5000x5000, so we start at (2500, 150) for proper centering
  assignPosition(root, 2500, 150);

  return positions;
}