Skip to content

Commit 91e2f65

Browse files
authored
Merge pull request #137 from nabil6391/develop
Develop
2 parents a5620d2 + b86c834 commit 91e2f65

17 files changed

+1309
-618
lines changed

example/lib/example.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import 'package:example/layer_graphview.dart';
22
import 'package:flutter/material.dart';
33

4-
import 'directed_graphview.dart';
4+
import 'force_directed_graphview.dart';
55
import 'tree_graphview.dart';
66

77
void main() {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class _GraphClusterViewPageState extends State<GraphClusterViewPage> {
2020
constrained: false,
2121
boundaryMargin: EdgeInsets.all(8),
2222
minScale: 0.001,
23-
maxScale: 100,
23+
maxScale: 10000,
2424
child: GraphView(
2525
graph: graph,
2626
algorithm: builder,
Lines changed: 71 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
import 'dart:async';
21
import 'dart:math';
3-
42
import 'package:flutter/material.dart';
53
import 'package:graphview/GraphView.dart';
64

75
class GraphScreen extends StatefulWidget {
8-
Graph graph;
9-
Algorithm algorithm;
6+
final Graph graph;
7+
final Algorithm algorithm;
108
final Paint? paint;
119

1210
GraphScreen(this.graph, this.algorithm, this.paint);
@@ -16,14 +14,15 @@ class GraphScreen extends StatefulWidget {
1614
}
1715

1816
class _GraphScreenState extends State<GraphScreen> {
19-
bool animated = true;
20-
Random r = Random();
17+
GraphViewController _controller = GraphViewController();
18+
final Random r = Random();
19+
int nextNodeId = 1;
2120

2221
@override
2322
Widget build(BuildContext context) {
2423
return Scaffold(
2524
appBar: AppBar(
26-
title: Text('Graph Screen'),
25+
title: Text('Graph View'),
2726
actions: [
2827
IconButton(
2928
icon: Icon(Icons.add),
@@ -41,43 +40,81 @@ class _GraphScreenState extends State<GraphScreen> {
4140
icon: Icon(Icons.animation),
4241
onPressed: () async {
4342
setState(() {
44-
animated = !animated;
4543
});
4644
},
4745
)
4846
],
4947
),
50-
body: InteractiveViewer(
51-
constrained: false,
52-
boundaryMargin: EdgeInsets.all(100),
53-
minScale: 0.0001,
54-
maxScale: 10.6,
55-
child: GraphView(
56-
graph: widget.graph,
57-
algorithm: widget.algorithm,
58-
animated: animated,
59-
builder: (Node node) {
60-
// I can decide what widget should be shown here based on the id
61-
var a = node.key!.value as String;
62-
return rectangWidget(a);
63-
},
64-
)),
48+
49+
body: Column(
50+
children: [
51+
// Navigation controls
52+
Wrap(
53+
children: [
54+
ElevatedButton(
55+
onPressed: () => _navigateToRandomNode(),
56+
child: Text('Go to Node $nextNodeId'),
57+
),
58+
ElevatedButton(
59+
onPressed: () => _controller.resetView(),
60+
child: Text('Reset View'),
61+
),
62+
ElevatedButton(
63+
onPressed: () => _controller.zoomToFit(),
64+
child: Text("Zoom to fit"),
65+
),
66+
],
67+
),
68+
Expanded(
69+
child: GraphView.builder(
70+
controller: _controller,
71+
graph: widget.graph,
72+
algorithm: widget.algorithm,
73+
paint: widget.paint,
74+
builder: (Node node) {
75+
var a = node.key?.value;
76+
return rectangleWidget(a);
77+
},
78+
),
79+
),
80+
],
81+
),
6582
);
6683
}
6784

68-
Widget rectangWidget(String? i) {
69-
return Container(
70-
padding: EdgeInsets.all(16),
85+
Widget rectangleWidget(nodeText) {
86+
return InkWell(
87+
onTap: () => print('clicked $nodeText'),
88+
child: Container(
89+
padding: EdgeInsets.all(10),
7190
decoration: BoxDecoration(
72-
borderRadius: BorderRadius.circular(4),
73-
boxShadow: [
74-
BoxShadow(color: Colors.blue, spreadRadius: 1),
75-
],
91+
color: Colors.red,
92+
border: Border.all(color: Colors.white, width: 1),
93+
borderRadius: BorderRadius.circular(30),
94+
),
95+
child: Center(
96+
child: Text(
97+
'$nodeText',
98+
style: TextStyle(fontSize: 10),
99+
),
76100
),
77-
child: Center(child: Text('Node $i')));
101+
),
102+
);
78103
}
79104

80-
Future<void> update() async {
81-
setState(() {});
105+
void _navigateToRandomNode() {
106+
if (widget.graph.nodes.isEmpty) return;
107+
108+
final randomNode = widget.graph.nodes.firstWhere(
109+
(node) => node.key != null && node.key!.value == nextNodeId,
110+
orElse: () => widget.graph.nodes.first,
111+
);
112+
final nodeId = randomNode.key!;
113+
_controller.animateToNode(nodeId);
114+
115+
setState(() {
116+
nextNodeId = r.nextInt(widget.graph.nodes.length) + 1;
117+
});
82118
}
83-
}
119+
120+
}

example/lib/layer_graphview.dart

Lines changed: 79 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import 'dart:math';
2-
32
import 'package:flutter/material.dart';
43
import 'package:graphview/GraphView.dart';
54

@@ -9,6 +8,10 @@ class LayeredGraphViewPage extends StatefulWidget {
98
}
109

1110
class _LayeredGraphViewPageState extends State<LayeredGraphViewPage> {
11+
GraphViewController _controller = GraphViewController();
12+
final Random r = Random();
13+
int nextNodeId = 0;
14+
1215
@override
1316
Widget build(BuildContext context) {
1417
return Scaffold(
@@ -52,7 +55,7 @@ class _LayeredGraphViewPageState extends State<LayeredGraphViewPage> {
5255
),
5356
),
5457
Container(
55-
width: 100,
58+
width: 120,
5659
child: Column(
5760
children: [
5861
Text('Alignment'),
@@ -82,63 +85,83 @@ class _LayeredGraphViewPageState extends State<LayeredGraphViewPage> {
8285
setState(() {});
8386
},
8487
child: Text('Add'),
85-
)
88+
),
89+
ElevatedButton(
90+
onPressed: () => _navigateToRandomNode(),
91+
child: Text('Go to Node $nextNodeId'),
92+
),
93+
ElevatedButton(
94+
onPressed: () => _controller.resetView(),
95+
child: Text('Reset View'),
96+
),
97+
ElevatedButton(
98+
onPressed: () => _controller.zoomToFit(),
99+
child: Text("Zoom to fit"),
100+
),
86101
],
87102
),
88103
Expanded(
89-
child: InteractiveViewer(
90-
constrained: false,
91-
boundaryMargin: EdgeInsets.all(100),
92-
minScale: 0.0001,
93-
maxScale: 10.6,
94-
child: GraphView(
95-
graph: graph,
96-
algorithm: SugiyamaAlgorithm(builder),
97-
paint: Paint()
98-
..color = Colors.green
99-
..strokeWidth = 1
100-
..style = PaintingStyle.stroke,
101-
builder: (Node node) {
102-
// I can decide what widget should be shown here based on the id
103-
var a = node.key!.value as int?;
104-
return rectangleWidget(a);
105-
},
106-
)),
104+
child: GraphView.builder(
105+
controller: _controller,
106+
graph: graph,
107+
algorithm: SugiyamaAlgorithm(builder),
108+
paint: Paint()
109+
..color = Colors.green
110+
..strokeWidth = 1
111+
..style = PaintingStyle.stroke,
112+
builder: (Node node) {
113+
var a = node.key!.value as int?;
114+
return rectangleWidget(a);
115+
},
116+
),
107117
),
108118
],
109119
));
110120
}
111121

112-
Random r = Random();
113-
114122
Widget rectangleWidget(int? a) {
115123
return Container(
116124
padding: EdgeInsets.all(16),
117125
decoration: BoxDecoration(
118-
borderRadius: BorderRadius.circular(4),
126+
shape: BoxShape.circle,
119127
boxShadow: [
120128
BoxShadow(color: Colors.blue[100]!, spreadRadius: 1),
121129
],
122130
),
123-
child: Text('Node ${a}'));
131+
child: Text('${a}'));
124132
}
125133

126134
final Graph graph = Graph();
127-
128135
SugiyamaConfiguration builder = SugiyamaConfiguration()
129136
..bendPointShape = CurvedBendPointShape(curveLength: 20);
130137

138+
void _navigateToRandomNode() {
139+
if (graph.nodes.isEmpty) return;
140+
141+
final randomNode = graph.nodes.firstWhere(
142+
(node) => node.key != null && node.key!.value == nextNodeId,
143+
orElse: () => graph.nodes.first,
144+
);
145+
final nodeId = randomNode.key!;
146+
_controller.animateToNode(nodeId);
147+
148+
setState(() {
149+
nextNodeId = r.nextInt(graph.nodes.length) + 1;
150+
});
151+
}
152+
131153
@override
132154
void initState() {
133155
super.initState();
156+
final node0 = Node.Id(0);
134157
final node1 = Node.Id(1);
135158
final node2 = Node.Id(2);
136159
final node3 = Node.Id(3);
137160
final node4 = Node.Id(4);
138161
final node5 = Node.Id(5);
139162
final node6 = Node.Id(6);
140-
final node8 = Node.Id(7);
141-
final node7 = Node.Id(8);
163+
final node7 = Node.Id(7);
164+
final node8 = Node.Id(8);
142165
final node9 = Node.Id(9);
143166
final node10 = Node.Id(10);
144167
final node11 = Node.Id(11);
@@ -152,49 +175,38 @@ class _LayeredGraphViewPageState extends State<LayeredGraphViewPage> {
152175
final node19 = Node.Id(19);
153176
final node20 = Node.Id(20);
154177
final node21 = Node.Id(21);
155-
final node22 = Node.Id(22);
156-
final node23 = Node.Id(23);
157178

158-
graph.addEdge(node1, node13, paint: Paint()..color = Colors.red);
159-
graph.addEdge(node1, node21);
160-
graph.addEdge(node1, node4);
161-
graph.addEdge(node1, node3);
162-
graph.addEdge(node2, node3);
163-
graph.addEdge(node2, node20);
164-
graph.addEdge(node3, node4);
165-
graph.addEdge(node3, node5);
166-
graph.addEdge(node3, node23);
167-
graph.addEdge(node4, node6);
168-
graph.addEdge(node5, node7);
169-
graph.addEdge(node6, node8);
170-
graph.addEdge(node6, node16);
171-
graph.addEdge(node6, node23);
172-
graph.addEdge(node7, node9);
173-
graph.addEdge(node8, node10);
174-
graph.addEdge(node8, node11);
175-
graph.addEdge(node9, node12);
176-
graph.addEdge(node10, node13);
177-
graph.addEdge(node10, node14);
178-
graph.addEdge(node10, node15);
179-
graph.addEdge(node11, node15);
180-
graph.addEdge(node11, node16);
181-
graph.addEdge(node12, node20);
182-
graph.addEdge(node13, node17);
183-
graph.addEdge(node14, node17);
184-
graph.addEdge(node14, node18);
185-
graph.addEdge(node16, node18);
186-
graph.addEdge(node16, node19);
187-
graph.addEdge(node16, node20);
188-
graph.addEdge(node18, node21);
189-
graph.addEdge(node19, node22);
190-
graph.addEdge(node21, node23);
191-
graph.addEdge(node22, node23);
192-
graph.addEdge(node1, node22);
193-
graph.addEdge(node7, node8);
179+
// Adding edges based on parent-child relationships
180+
graph.addEdge(node8, node0);
181+
graph.addEdge(node2, node11);
182+
graph.addEdge(node11, node3);
183+
graph.addEdge(node12, node4);
184+
graph.addEdge(node4, node9);
185+
graph.addEdge(node18, node5);
186+
graph.addEdge(node9, node6);
187+
graph.addEdge(node15, node6);
188+
graph.addEdge(node17, node6);
189+
graph.addEdge(node3, node7);
190+
graph.addEdge(node17, node7);
191+
graph.addEdge(node20, node7);
192+
graph.addEdge(node21, node7);
193+
graph.addEdge(node0, node16);
194+
graph.addEdge(node21, node10);
195+
graph.addEdge(node16, node10);
196+
graph.addEdge(node21, node12);
197+
graph.addEdge(node4, node13);
198+
graph.addEdge(node12, node13);
199+
graph.addEdge(node1, node14);
200+
graph.addEdge(node8, node14);
201+
graph.addEdge(node9, node18);
202+
graph.addEdge(node19, node17);
194203

195204
builder
196205
..nodeSeparation = (15)
197206
..levelSeparation = (15)
198207
..orientation = SugiyamaConfiguration.ORIENTATION_TOP_BOTTOM;
208+
209+
// Set initial random node for navigation
210+
nextNodeId = r.nextInt(22); // 0-21 nodes exist
199211
}
200-
}
212+
}

0 commit comments

Comments
 (0)