Skip to main content

Graph Widgets

Both OrgChart and Genogram extend the BaseGraph class, sharing a common set of properties, and customization options.

Core Properties

PropertyTypeDefaultDescription
controllerBaseGraphController<E>requiredController that manages the graph data and layout
builderWidget Function(NodeBuilderDetails<E>)requiredBuilder function for rendering individual nodes
isDraggablebooltrueWhether nodes can be dragged
minScaledouble0.001Minimum zoom scale
maxScaledouble5.6Maximum zoom scale

Node Rendering

The builder property accepts a function that receives NodeBuilderDetails<E> and returns a widget. This allows for complete customization of each node's appearance.

OrgChart<Employee>(
controller: controller,
builder: (details) {
return Card(
color: details.isBeingDragged ? Colors.lightBlue : Colors.white,
elevation: 4,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(details.item.name, style: TextStyle(fontWeight: FontWeight.bold)),
Text(details.item.position),
if (details.level > 1) // Not showing for root nodes
IconButton(
icon: Icon(details.nodesHidden ? Icons.add : Icons.remove),
onPressed: () => details.hideNodes(),
),
],
),
),
);
},
)

NodeBuilderDetails

PropertyTypeDescription
itemEThe data item for this node
levelintDepth level of this node (1 = root)
hideNodesFunction({bool? hide, bool center})Function to toggle child visibility
nodesHiddenboolWhether this node's children are hidden
isBeingDraggedboolWhether this node is being dragged
isOverlappedboolWhether this node is being overlapped by a dragged node

Node Interaction

Nodes support several interaction modes:

  • Drag and Drop: When isDraggable is true, users can drag nodes
  • Long Press: Displays a context menu for the node
  • Toggle Children: Through the hideNodes() function available in builder callback

Edge Styling

You can customize the appearance of the lines connecting nodes:

OrgChart<Employee>(
// ...other properties
linePaint: Paint()
..color = Colors.blue
..strokeWidth = 2.0
..style = PaintingStyle.stroke,
cornerRadius: 15.0,
arrowStyle: const SolidGraphArrow(),
)
PropertyTypeDefaultDescription
linePaintPaintBlack, 0.5px, strokePaint object for lines
cornerRadiusdouble10.0Radius for edge corners
arrowStyleGraphArrowStyleSolidGraphArrow()Style of arrows on lines

Arrow Styles

The library provides two types of arrow styles:

1. Solid Arrow

// Default solid arrow
arrowStyle: const SolidGraphArrow()

The SolidGraphArrow style creates a standard, continuous line with solid arrow heads.

2. Dashed Arrow

// Dashed arrow with custom dash pattern
arrowStyle: const DashedGraphArrow(
pattern: [5, 3], // Pattern of [dash length, gap length]
)

The DashedGraphArrow style creates dashed lines with the following options:

ParameterTypeDefaultDescription
patternIterable<double>[10, 5]Alternating dash and gap lengths

The pattern should contain an even number of values, representing alternating dash and gap lengths. For example:

  • [10, 5] creates a 10px dash followed by a 5px gap
  • [5, 2, 15, 3] creates a 5px dash, 2px gap, 15px dash, 3px gap pattern that is repeated

Interactive Viewer

Both chart widgets use CustomInteractiveViewer for pan, zoom, and navigation:

PropertyTypeDefaultDescription
enableZoombooltrueEnables pinch to zoom
enableRotationboolfalseEnables rotation gestures
enableFlingbooltrueEnables fling momentum after panning
enablePanbooltrueEnables panning/dragging the chart
enableDoubleTapZoombooltrueEnables double-tap to zoom in
doubleTapZoomFactordouble2.0Zoom multiplier on double-tap
constrainBoundsboolfalseIf true, prevents scrolling outside chart boundaries

Keyboard & Accessibility

Both widgets support keyboard navigation for improved accessibility:

OrgChart<Employee>(
// ...other properties
enableKeyboardControls: true,
keyboardPanDistance: 30.0,
keyboardZoomFactor: 1.2,
focusNode: myFocusNode,
)
PropertyTypeDefaultDescription
enableKeyboardControlsbooltrueEnable arrow key navigation
keyboardPanDistancedouble20.0Distance moved on each arrow key press
keyboardZoomFactordouble1.1Zoom factor for + and - keys
enableKeyRepeatbooltrueAuto-repeat when keys are held
keyRepeatInitialDelayDuration500msDelay before key repeat starts
keyRepeatIntervalDuration50msInterval between repeats
invertArrowKeyDirectionboolfalseInverts direction of arrow key navigation
animateKeyboardTransitionsbooltrueAnimate transitions from keyboard
keyboardAnimationCurveCurveCurves.easeInOutAnimation curve for keyboard transitions
keyboardAnimationDurationDuration300msDuration of keyboard animations

Context Menu

You can provide custom context menu options for nodes:

OrgChart<Employee>(
// ...other properties
optionsBuilder: (employee) => [
PopupMenuItem(
value: 'edit',
child: ListTile(
leading: Icon(Icons.edit),
title: Text('Edit'),
),
),
PopupMenuItem(
value: 'delete',
child: ListTile(
leading: Icon(Icons.delete),
title: Text('Delete'),
),
),
],
onOptionSelect: (employee, value) {
if (value == 'edit') {
// Show edit dialog
} else if (value == 'delete') {
// Show delete confirmation
}
},
)

Animation

Both widgets support animated transitions when node positions change:

PropertyTypeDefaultDescription
curveCurveCurves.elasticOutAnimation curve for position changes
durationDuration700msDuration of node position animations

Diagram Export

You can export the diagram as an image or PDF using the controller:

// Export as PNG
final Uint8List? pngBytes = await controller.exportAsImage();
if (pngBytes != null) {
// Save PNG bytes to a file or share them
}

// Export as PDF
final pw.Document? pdf = await controller.exportAsPdf();
if (pdf != null) {
// Save PDF or share it
final bytes = await pdf.save();
}

Differences Between Widgets

The OrgChart widget specializes in hierarchical structures with a single parent-child relationship. It includes:

  • onDrop callback with three parameters: dragged item, target item, and a boolean isTargetSubnode that helps prevent circular references
  • Support for collapsing/expanding subtrees
  • Built-in level calculation
OrgChart<Employee>(
controller: controller,
builder: nodeBuilder,
onDrop: (dragged, target, isTargetSubnode) {
// Handle reorganization in your data model
if (!isTargetSubnode) {
// Safe to make dragged a child of target
}
},
)