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
Parameter | Type | Description |
---|---|---|
items | List<E> | Data items to display in the chart |
idProvider | String Function(E) | Function to extract unique ID from an item |
toProvider | String? 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+) |
boxSize | Size | Size of each node box (default: Size(200, 100) ) |
spacing | double | Horizontal spacing between nodes (default: 20 ) |
runSpacing | double | Vertical spacing between rows (default: 50 ) |
orientation | GraphOrientation | Layout direction (default: topToBottom ) |
leafColumns | int | Number of columns to arrange leaf nodes (default: 4 ) |
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:
Action | Description |
---|---|
ActionOnNodeRemoval.unlinkDescendants | Removes node and sets its subordinates' manager to null |
ActionOnNodeRemoval.connectDescendantsToParent | Connects subordinates to the removed node's own manager |
ActionOnNodeRemoval.removeDescendants | Removes the node and all its subordinates |
The enum values were renamed in version 5.0.0-alpha.3 for better clarity:
unlink
→unlinkDescendants
connectToParent
→connectDescendantsToParent
remove
→removeDescendants
// 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:
-
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
-
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.