Skip to main content

OrgChart Controller

The OrgChartController manages data and layout for hierarchical organizational charts with single-parent relationships.

Creating a Controller

final controller = OrgChartController<Employee>(
items: employees,
idProvider: (emp) => emp.id.toString(),
toProvider: (emp) => emp.managerId?.toString(),
boxSize: const Size(180, 100),
spacing: 25,
runSpacing: 50,
leafColumns: 4,
);

Constructor Parameters

ParameterTypeDescription
itemsList<E>Data items to display in the chart
idProviderString Function(E)Function to extract unique ID from an item
toProviderString? Function(E)Function to extract parent/manager ID from an item
toSetter (optional)E Function(E, String?)Function to update an item's parent/manager ID, returns a new instance (v5.0.0-alpha.3+)
boxSizeSizeSize of each node box (default: Size(200, 100))
spacingdoubleHorizontal spacing between nodes (default: 20)
runSpacingdoubleVertical spacing between rows (default: 50)
orientationGraphOrientationLayout direction (default: topToBottom)
leafColumnsintNumber of columns to arrange leaf nodes (default: 4)
note

Starting from version 5.0.0-alpha.3, the toSetter function you are required to return a new instance instead of modifying the existing one in place. This allows the use of final instances with copyWith methods.

// Before v5.0.0-alpha.3
toSetter: (employee, managerId) {
employee.managerId = managerId; // Modifies in place
}

// v5.0.0-alpha.3+
toSetter: (employee, managerId) {
return employee.copyWith(managerId: managerId); // Returns new instance
}

Key Methods

Hierarchy Management

// Get root nodes (items with no manager)
List<Node<Employee>> roots = controller.roots;

// Get direct reports of a node
List<Node<Employee>> reportees = controller.getSubNodes(someNode);

// Determine if one node is a descendant of another (prevents circular refs)
bool isSubordinate = controller.isSubNode(employeeNode, managerNode);

// Get the parent/manager of a node
Node<Employee>? manager = controller.getParent(employeeNode);

// Get the level/depth of a node in the hierarchy
int level = controller.getLevel(employeeNode); // 1 = root

Node Operations

// Add a new employee
controller.addItem(newEmployee);

// Add multiple employees at once (v5.0.0-alpha.3+)
controller.addItems([employee1, employee2, employee3]);

// Clear all employees from the chart (v5.0.0-alpha.3+)
controller.clearItems();

// Remove an employee with different strategies
controller.removeItem(
'123',
ActionOnNodeRemoval.unlinkDescendants, // Remove links to this node
);

// Available removal actions (updated in v5.0.0-alpha.3):
// - unlinkDescendants: Remove employee but leave subordinates without a manager
// - connectDescendantsToParent: Connect subordinates to the employee's manager
// - removeDescendants: Remove the employee and all subordinates

Layout Configuration

// Change the number of columns used for leaf nodes
controller.leafColumns = 3;
controller.calculatePosition();

// Change the orientation
controller.switchOrientation(orientation: GraphOrientation.leftToRight);

Node Removal Actions

When removing a node, you can choose how to handle its subordinates:

ActionDescription
ActionOnNodeRemoval.unlinkDescendantsRemoves node and sets its subordinates' manager to null
ActionOnNodeRemoval.connectDescendantsToParentConnects subordinates to the removed node's own manager
ActionOnNodeRemoval.removeDescendantsRemoves the node and all its subordinates
note

The enum values were renamed in version 5.0.0-alpha.3 for better clarity:

  • unlinkunlinkDescendants
  • connectToParentconnectDescendantsToParent
  • removeremoveDescendants
// Example: Promoting subordinates when removing a manager
controller.removeItem(
managerId,
ActionOnNodeRemoval.connectDescendantsToParent
);

// Example: Removing an entire department
controller.removeItem(
departmentHeadId,
ActionOnNodeRemoval.removeDescendants
);

Layout Algorithm

The controller implements two different layout algorithms depending on the orientation:

  1. Top-to-Bottom: Nodes are positioned in rows, with parents above their children.

    • Root nodes are positioned at the top
    • Each level is positioned below the previous level
    • Parents are centered above their children
  2. Left-to-Right: Nodes are positioned in columns, with parents to the left of their children.

    • Root nodes are positioned at the leftmost side
    • Each level is positioned to the right of the previous level
    • Parents are centered to the left of their children

For leaf nodes (nodes without children), the controller arranges them in a grid pattern with leafColumns columns.