Plough is a library for creating interactive network graph visualizations in Flutter applications.
- đź“Š Add custom properties to nodes and links freely.
- 🔄 Multiple layout algorithms available: force-directed, tree, random, as well as custom layouts and manual node positioning.
- 🖱️ Interactive manipulation support: define behaviors for node/link dragging and tap gestures.
- 🎨 Customizable graph appearance and behavior: nodes and links are widgets, requiring no special rendering implementation.
- 🎬 Smooth animation of nodes from initial to final positions during first render.
To use AI assistance with this library, load prompt/user_guide.xml
into the AI assistant.
user_guide.xml
contains structured documentation in XML format, including the contents of this README, to help the AI assistant understand the library's functionality.
Add to pubspec.yaml:
dependencies:
plough: ^0.6.0
Or run the command:
flutter pub add plough
This example shows how to draw a simple graph with two nodes and a connecting link using default settings:
@override
Widget build(BuildContext context) {
final graph = Graph();
final alice = GraphNode(properties: {
'label': 'Alice',
'description': 'Alice node'
});
final bob = GraphNode(properties: {
'label': 'Bob',
'description': 'Bob node'
});
final follow = GraphLink(
source: alice,
target: bob,
properties: {
'label': 'follows',
'description': 'Alice follows Bob'
},
direction: GraphLinkDirection.outgoing,
);
graph
..addNode(alice)
..addNode(bob)
..addLink(follow);
return GraphView(
graph: graph,
layoutStrategy: GraphForceDirectedLayoutStrategy(),
behavior: const GraphViewDefaultBehavior(),
);
}
This code generates graph data with two nodes and one link, laying out the nodes using a force-directed algorithm. The graph view uses default implementations without customization.
Here are the basic steps to draw a graph with Plough:
-
Import
package:plough/plough.dart
. -
Create a
Graph
object and build graph data. This is the library's core data structure for managing nodes and links. -
Use
GraphNode
class to create nodes. Theproperties
map can store arbitrary properties for customizing node display and properties. -
Use
GraphLink
class to create links between nodes. Specify nodes withsource
andtarget
, and set direction withdirection
. Links can also have aproperties
map. -
Add the created nodes and links to the
Graph
object. -
Use
GraphView
widget to render the graph. Specify node placement withlayoutStrategy
and customize graph view behavior withbehavior
.
Here's an example of drawing a simple graph with three nodes and two links:
// Import library
import 'package:plough/plough.dart';
// Create graph
final graph = Graph();
// Create nodes
final node1 = GraphNode(properties: {
'label': 'Node1',
'description': 'First node'
});
final node2 = GraphNode(properties: {
'label': 'Node2',
'description': 'Second node'
});
final node3 = GraphNode(properties: {
'label': 'Node3',
'description': 'Third node'
});
// Create links between nodes
final link1 = GraphLink(
source: node1,
target: node2,
direction: GraphLinkDirection.outgoing,
);
final link2 = GraphLink(
source: node2,
target: node3,
direction: GraphLinkDirection.outgoing,
);
// Add nodes and links to graph
graph
..addNode(node1)
..addNode(node2)
..addNode(node3)
..addLink(link1)
..addLink(link2);
// Display graph view
return GraphView(
graph: graph,
layoutStrategy: GraphForceDirectedLayoutStrategy(),
behavior: const GraphViewDefaultBehavior(),
);
This example uses force-directed layout and default implementations for graph rendering and view behavior.
In the default implementation, a node's label
property is displayed within the node view, and its description
property appears as a tooltip.
Behavior (GraphViewBehavior
) is a component for defining graph appearance and interactive operations.
The library provides GraphViewDefaultBehavior
with basic behavior implementation, and recommends subclassing for custom behaviors.
Methods that users can define. See API reference for details.
createNodeViewBehavior()
: Defines node display method. Returns node appearance and tooltip settingscreateLinkViewBehavior()
: Defines link display method. Returns link appearance and connection settingsgetConnectionPoints()
: Calculates connection points for links between nodesonNodeSelect()
: Defines handling when a node is selectedonNodeTap()
: Defines handling when a node is tappedonNodeDragStart()
,onNodeDragUpdate()
,onNodeDragEnd()
: Define handling for node drag operations
The library provides default implementations for rendering nodes and links. Here are the features of each renderer:
-
GraphDefaultNodeRenderer
: Default implementation for node rendering- Circular or rectangular node shapes (default is circular)
- Displays value of
label
key fromproperties
as label - Style settings (color, size, etc.)
-
GraphDefaultLinkRenderer
: Default implementation for link rendering- Displays arrow-headed lines
- Link thickness and color settings
To customize default renderers, implement createNodeViewBehavior
or createLinkViewBehavior
.
Example:
class CustomBehavior extends GraphViewDefaultBehavior {
@override
GraphNodeViewBehavior createNodeViewBehavior() {
return GraphNodeViewBehavior.defaultBehavior(
nodeRendererBuilder: (context, graph, node, child) {
return GraphDefaultNodeRenderer(
node: node,
style: const GraphDefaultNodeRendererStyle(
shape: GraphDefaultNodeRendererShape.rectangle,
),
child: Center(
child: Text(node['label']! as String),
),
);
},
);
}
}
Specify layout in GraphView
with the layoutStrategy
parameter. Layouts are implemented as instances of GraphLayoutStrategy
and the following layout strategies are available:
GraphForceDirectedLayoutStrategy
applies a force-directed model between nodes and automatically calculates layout. It achieves balanced placement considering repulsive forces between nodes and attractive forces from links.
GraphTreeLayoutStrategy
is suitable for graphs with hierarchical structure. It arranges nodes hierarchically to visually represent parent-child relationships.
GraphRandomLayoutStrategy
places nodes at random positions. It can be used for initial placement or as a base for other layouts.
GraphManualLayoutStrategy
is for complete manual control of node positions.
While node positions can be manually specified in any strategy, this strategy allows more detailed control.
To implement your own layout algorithm, create your own strategy by inheriting from GraphCustomLayoutStrategy
.
Individual nodes can be manually positioned with any layout strategy. Manually positioned nodes are excluded from layout algorithm calculations.
Node positions can be directly specified with nodePositions
in each strategy's constructor.
Here's an example of arranging three nodes in a triangle:
// Define node positions
final basePositions = {
nodeA.id: Offset(0.0, 0.0), // Top
nodeB.id: Offset(-1.0, 1.732), // Bottom left
nodeC.id: Offset(1.0, 1.732), // Bottom right
};
// Create node positions
final nodePositions = GraphNodeLayoutPosition.fromMap(
Map.fromEntries(
basePositions.entries.map(
(entry) => MapEntry(entry.key, entry.value.scale(scale, scale)),
),
),
);
// Apply layout
// Can be specified with any strategy
final layoutStrategy = GraphManualLayoutStrategy(
nodePositions: nodePositions,
origin: GraphLayoutPositionOrigin.alignCenter,
);
When animation is enabled, nodes smoothly move from initial to final positions during first render.
Animation settings can be specified with GraphView.animationEnabled
.
See API reference for details.
- Layout strategies
- Circular
- Grid
- Layered
- Layout saving and restoration
- Layout import and export
- Weight reflection in layouts
Apache License 2.0
SUZUKI Tetsuya [email protected]