GraphView
Flutter GraphView 用于在图结构中显示数据。它可以显示树状布局和有向图。
该库旨在支持不同的图布局,目前对小型图效果极佳。
您可以在此处查看 Flutter Web 实现
http://graphview.surge.sh/


布局
树
使用 Walker 算法并结合 Buchheim 的运行时改进(BuchheimWalkerAlgorithm 类)。支持不同的方向。您只需使用 BuchheimWalkerConfiguration.orientation 并选择 ORIENTATION_LEFT_RIGHT、ORIENTATION_RIGHT_LEFT、ORIENTATION_TOP_BOTTOM 或
ORIENTATION_BOTTOM_TOP(默认)。此外,还可以设置兄弟节点、层级、子树等分隔参数。
适用于:家族树、层级视图、Flutter Widget 树,
有向图
通过模拟吸引/排斥力绘制有向图。为此,实现了 Fruchterman 和 Reingold 的算法(FruchtermanReingoldAlgorithm 类)。
适用于:社交网络、思维导图、集群、图、城市间道路网络,
用法
目前 GraphView 必须与缩放引擎一起使用,例如 InteractiveViewer。要更改缩放值,只需使用 InteractiveViewer 类中描述的不同属性。
要创建图,我们需要实例化 Graph 类。然后我们需要传递布局,还可以选择性地传递边渲染器。
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) => MaterialApp(
home: GraphViewPage(),
);
}
class GraphViewPage extends StatefulWidget {
@override
_GraphViewPageState createState() => _GraphViewPageState();
}
class _GraphViewPageState extends State<GraphViewPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisSize: MainAxisSize.max,
children: [
Wrap(
children: [
Container(
width: 100,
child: TextFormField(
initialValue: builder.siblingSeparation.toString(),
decoration: InputDecoration(labelText: "Sibling Sepration"),
onChanged: (text) {
builder.siblingSeparation = int.tryParse(text) ?? 100;
this.setState(() {});
},
),
),
Container(
width: 100,
child: TextFormField(
initialValue: builder.levelSeparation.toString(),
decoration: InputDecoration(labelText: "Level Seperation"),
onChanged: (text) {
builder.levelSeparation = int.tryParse(text) ?? 100;
this.setState(() {});
},
),
),
Container(
width: 100,
child: TextFormField(
initialValue: builder.subtreeSeparation.toString(),
decoration: InputDecoration(labelText: "Subtree separation"),
onChanged: (text) {
builder.subtreeSeparation = int.tryParse(text) ?? 100;
this.setState(() {});
},
),
),
Container(
width: 100,
child: TextFormField(
initialValue: builder.orientation.toString(),
decoration: InputDecoration(labelText: "Orientation"),
onChanged: (text) {
builder.orientation = int.tryParse(text) ?? 100;
this.setState(() {});
},
),
),
RaisedButton(
onPressed: () {
final Node node12 = Node(getNodeText());
var edge = graph.getNodeAtPosition(r.nextInt(graph.nodeCount()));
print(edge);
graph.addEdge(edge, node12);
setState(() {});
},
child: Text("Add"),
)
],
),
Expanded(
child: InteractiveViewer(
constrained: false,
scaleEnabled: false,
boundaryMargin: EdgeInsets.all(100),
minScale: 0.01,
maxScale: 5.6,
child: GraphView(
graph: graph,
algorithm: BuchheimWalkerAlgorithm(builder),
renderer: TreeEdgeRenderer(builder),
)),
),
],
)
);
}
Random r = Random();
int n = 1;
Widget getNodeText() {
return Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
boxShadow: [
BoxShadow(color: Colors.blue[100], spreadRadius: 1),
],
),
child: Text("Node ${n++}"));
}
final Graph graph = Graph();
BuchheimWalkerConfiguration builder = BuchheimWalkerConfiguration();
@override
void initState() {
final Node node1 = Node(getNodeText());
final Node node2 = Node(getNodeText());
final Node node3 = Node(getNodeText());
final Node node4 = Node(getNodeText());
final Node node5 = Node(getNodeText());
final Node node6 = Node(getNodeText());
final Node node8 = Node(getNodeText());
final Node node7 = Node(getNodeText());
final Node node9 = Node(getNodeText());
final Node node10 = Node(getNodeText());
final Node node11 = Node(getNodeText());
final Node node12 = Node(getNodeText());
graph.addEdge(node1, node2);
graph.addEdge(node1, node3);
graph.addEdge(node1, node4);
graph.addEdge(node2, node5);
graph.addEdge(node2, node6);
graph.addEdge(node6, node7);
graph.addEdge(node6, node8);
graph.addEdge(node4, node9);
graph.addEdge(node4, node10);
graph.addEdge(node4, node11);
graph.addEdge(node11, node12);
builder
..siblingSeparation = (100)
..levelSeparation = (150)
..subtreeSeparation = (150)
..orientation = (BuchheimWalkerConfiguration.ORIENTATION_TOP_BOTTOM);
}
}
在 Node 中使用任何 Widget
您可以在节点中使用任何 Widget
Node node = Node(getNodeText);
getNodeText() {
return Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
boxShadow: [
BoxShadow(color: Colors.blue[100], spreadRadius: 1),
],
),
child: Text("Node ${n++}"));
}
示例
根节点树

根节点树(从下到上)

根节点树(从左到右)

根节点树(从右到左)

有向图

灵感来源
该库基本上是 Team-Blox 出色的 Android 库 GraphView 的 Dart 版本。
我想感谢他们开源了他们的代码,因此我能够将他们的代码移植到 Dart 并用于 Flutter。
未来工作
[] 添加 nodeOnTap
[] 添加分层图(欢迎 PR)
[] 使用构建器模式按需绘制项目。