From e1db2c59a1fe0a5aa8d1f73022f9d01c1df8ec49 Mon Sep 17 00:00:00 2001 From: CorvusYe Date: Mon, 30 Jan 2023 08:06:03 +0800 Subject: [PATCH] feat(convert): cache the edge names and vertex tags in graph. feat: support customize background. --- CHANGELOG.md | 4 + README-CN.md | 14 +++ README.md | 14 +++ example/lib/main.dart | 14 +++ example/pubspec.lock | 2 +- lib/core/data_convertor.dart | 8 ++ lib/core/options.dart | 11 ++- .../shape/vertex/vertex_circle_shape.dart | 17 ++-- lib/core/options/style/graph_style.dart | 88 +++++++++++++++++++ lib/flutter_graph_view.dart | 2 + lib/flutter_graph_widget.dart | 5 +- lib/model/graph.dart | 10 +++ lib/model/vertex.dart | 15 +--- lib/widgets/graph_component.dart | 1 + pubspec.yaml | 2 +- 15 files changed, 181 insertions(+), 26 deletions(-) create mode 100644 lib/core/options/style/graph_style.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a4a221..a1560ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.1+8 +- feat(convert): cache the edge names and vertex tags in graph. +- feat: support customize background. + ## 0.0.1+7 - feat: supported customize vertex ui. - feat: supported customize edge ui. diff --git a/README-CN.md b/README-CN.md index addc6e4..883578e 100644 --- a/README-CN.md +++ b/README-CN.md @@ -48,6 +48,11 @@ void main() { { 'id': 'node$i', 'tag': 'tag${r.nextInt(9)}', + 'tags': [ + 'tag${r.nextInt(4)}', + if (r.nextBool()) 'tag${r.nextInt(4)}', + if (r.nextBool()) 'tag${r.nextInt(8)}' + ], }, ); } @@ -83,6 +88,15 @@ void main() { algorithm: ForceDirected(), convertor: MapConvertor(), options: Options() + ..graphStyle = (GraphStyle() + // tagColor is prior to tagColorByIndex. use vertex.tags to get color + ..tagColor = {'tag3': Colors.purple} + ..tagColorByIndex = [ + Colors.blue, + Colors.red, + Colors.green, + Colors.yellow, + ]) ..edgePanelBuilder = edgePanelBuilder ..vertexPanelBuilder = vertexPanelBuilder ..edgeShape = EdgeLineShape() // default is EdgeLineShape. diff --git a/README.md b/README.md index af35b61..34559e7 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,11 @@ void main() { { 'id': 'node$i', 'tag': 'tag${r.nextInt(9)}', + 'tags': [ + 'tag${r.nextInt(4)}', + if (r.nextBool()) 'tag${r.nextInt(4)}', + if (r.nextBool()) 'tag${r.nextInt(8)}' + ], }, ); } @@ -83,6 +88,15 @@ void main() { algorithm: ForceDirected(), convertor: MapConvertor(), options: Options() + ..graphStyle = (GraphStyle() + // tagColor is prior to tagColorByIndex. use vertex.tags to get color + ..tagColor = {'tag3': Colors.purple} + ..tagColorByIndex = [ + Colors.blue, + Colors.red, + Colors.green, + Colors.yellow, + ]) ..edgePanelBuilder = edgePanelBuilder ..vertexPanelBuilder = vertexPanelBuilder ..edgeShape = EdgeLineShape() // default is EdgeLineShape. diff --git a/example/lib/main.dart b/example/lib/main.dart index 30d4781..6bf684b 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -15,6 +15,11 @@ void main() { { 'id': 'node$i', 'tag': 'tag${r.nextInt(9)}', + 'tags': [ + 'tag${r.nextInt(4)}', + if (r.nextBool()) 'tag${r.nextInt(4)}', + if (r.nextBool()) 'tag${r.nextInt(8)}' + ], }, ); } @@ -50,6 +55,15 @@ void main() { algorithm: ForceDirected(), convertor: MapConvertor(), options: Options() + ..graphStyle = (GraphStyle() + // tagColor is prior to tagColorByIndex. use vertex.tags to get color + ..tagColor = {'tag3': Colors.purple} + ..tagColorByIndex = [ + Colors.blue, + Colors.red, + Colors.green, + Colors.yellow, + ]) ..edgePanelBuilder = edgePanelBuilder ..vertexPanelBuilder = vertexPanelBuilder ..edgeShape = EdgeLineShape() // default is EdgeLineShape. diff --git a/example/pubspec.lock b/example/pubspec.lock index a3c2bd2..40ac374 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -76,7 +76,7 @@ packages: path: ".." relative: true source: path - version: "0.0.1+7" + version: "0.0.1+8" flutter_lints: dependency: "direct dev" description: diff --git a/lib/core/data_convertor.dart b/lib/core/data_convertor.dart index a726225..50678c3 100644 --- a/lib/core/data_convertor.dart +++ b/lib/core/data_convertor.dart @@ -30,6 +30,11 @@ abstract class DataConvertor { void vertexAsGraphComponse(V v, Graph g, Vertex vertex) { vertex.data = v; g.keyCache[vertex.id] = vertex; + + vertex.tags?.forEach((tag) { + var absent = !g.allTags.contains(tag); + if (absent) g.allTags.add(tag); + }); } /// Create edge and graph relationship in memory. @@ -45,5 +50,8 @@ abstract class DataConvertor { } result.start.degree++; result.data = e; + + var absent = !g.allEdgeNames.contains(result.edgeName); + if (absent) g.allEdgeNames.add(result.edgeName); } } diff --git a/lib/core/options.dart b/lib/core/options.dart index b32c1ba..3e54159 100644 --- a/lib/core/options.dart +++ b/lib/core/options.dart @@ -2,7 +2,7 @@ // // This source code is licensed under Apache 2.0 License. -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_graph_view/flutter_graph_view.dart'; /// The core api for Graph Options. @@ -28,4 +28,13 @@ class Options { /// /// 给边设置形状 EdgeShape edgeShape = EdgeLineShape(); + + /// use for create background widget. + /// + /// 用于创建背景 + Widget Function(BuildContext) backgroundBuilder = (context) => Container( + color: Colors.black54, + ); + + GraphStyle graphStyle = GraphStyle(); } diff --git a/lib/core/options/shape/vertex/vertex_circle_shape.dart b/lib/core/options/shape/vertex/vertex_circle_shape.dart index 04f37b6..6d4a73d 100644 --- a/lib/core/options/shape/vertex/vertex_circle_shape.dart +++ b/lib/core/options/shape/vertex/vertex_circle_shape.dart @@ -2,9 +2,10 @@ // // This source code is licensed under Apache 2.0 License. -import 'dart:ui'; +import 'dart:ui' as ui; import 'package:flame/collisions.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_graph_view/flutter_graph_view.dart'; /// The default shape impl. @@ -48,22 +49,26 @@ class VertexCircleShape extends VertexShape { @override void setPaint(Vertex vertex) { var cpn = vertex.cpn!; + var colors = vertex.colors; + if (isWeaken(vertex)) { cpn.paint = Paint() - ..shader = Gradient.radial( + ..shader = ui.Gradient.radial( Offset(vertex.radius, vertex.radius), vertex.radius, List.generate( - vertex.colors.length, - (index) => vertex.colors[index].withOpacity(.5), + colors.length, + (index) => colors[index].withOpacity(.5), ), + List.generate(colors.length, (index) => (index + 1) / colors.length), ); } else { cpn.paint = Paint() - ..shader = Gradient.radial( + ..shader = ui.Gradient.radial( Offset(vertex.radius, vertex.radius), vertex.radius, - vertex.colors, + colors, + List.generate(colors.length, (index) => (index + 1) / colors.length), ); } } diff --git a/lib/core/options/style/graph_style.dart b/lib/core/options/style/graph_style.dart new file mode 100644 index 0000000..bf7cfd1 --- /dev/null +++ b/lib/core/options/style/graph_style.dart @@ -0,0 +1,88 @@ +// Copyright (c) 2023- All flutter_graph_view authors. All rights reserved. +// +// This source code is licensed under Apache 2.0 License. + +import 'dart:ui'; +import 'dart:math' as math; + +import 'package:flutter_graph_view/flutter_graph_view.dart'; + +/// The graph style configuration. +/// +/// 图的样式配置类。 +class GraphStyle { + /// [tagColor] is prior to [tagColorByIndex]. use [Vertex.tags] to get color in [vertexColors] + /// + /// [tagColor]的优先级比[tagColorByIndex]高。 + /// 在[vertexColors]方法中使用[Vertex.tags]属性获取颜色 + Map? tagColor; + + /// [tagColor] is prior to [tagColorByIndex]. use [Vertex.tags] to get color in [vertexColors] + /// + /// [tagColor]的优先级比[tagColorByIndex]高。 + /// 在[vertexColors]方法中使用[Vertex.tags]属性获取颜色 + late List tagColorByIndex = []; + + /// set elements color in [graph] + /// + /// 对[graph]中的元素设置颜色 + void graphColor(Graph graph) { + for (var vertex in graph.vertexes) { + vertex.colors = vertexColors(vertex); + } + // TODO set edge color + } + + /// get color list by [vertex]'s `tags`. + /// + /// 通过[vertex]中的`tags`属性获取颜色列表 + List vertexColors(Vertex vertex) { + var tags = vertex.tags; + var allTags = vertex.cpn!.gameRef.graph.allTags; + + if (tags == null) { + return defaultColor(); + } + List colors = []; + + for (var tag in tags) { + Color? color; + if (tagColor != null) { + color = tagColor![tag]; + } + if (color == null) { + var idx = allTags.indexOf(tag); + if (idx < tagColorByIndex.length) color = tagColorByIndex[idx]; + } + if (color != null) { + colors.add(color); + } + } + + if (colors.isEmpty) { + return defaultColor(); + } + return colors; + } + + /// when there is not color matched in [tagColor] on [tagColorByIndex], return random color. + /// + /// 当在 [tagColor] 与 [tagColorByIndex] 中匹配不到颜色时,返回随机颜色 + var defaultColor = () { + var r = math.Random(); + return [ + Color.fromRGBO( + r.nextInt(160) + 80, + r.nextInt(160) + 80, + r.nextInt(160) + 80, + 1, + ), + Color.fromRGBO( + r.nextInt(160) + 80, + r.nextInt(160) + 80, + r.nextInt(160) + 80, + 1, + ), + ]; + }; +} diff --git a/lib/flutter_graph_view.dart b/lib/flutter_graph_view.dart index 0be26b0..9e8d9e8 100644 --- a/lib/flutter_graph_view.dart +++ b/lib/flutter_graph_view.dart @@ -30,6 +30,8 @@ export 'core/algorithm/force_directed.dart'; export 'core/options/shape/vertex/vertex_circle_shape.dart'; export 'core/options/shape/edge/edge_line_shape.dart'; +export 'core/options/style/graph_style.dart'; + /// third party export 'package:flame/flame.dart'; export 'package:flame/components.dart'; diff --git a/lib/flutter_graph_widget.dart b/lib/flutter_graph_widget.dart index ffed126..d807ba2 100644 --- a/lib/flutter_graph_widget.dart +++ b/lib/flutter_graph_widget.dart @@ -79,14 +79,13 @@ class _FlutterGraphWidgetState extends State { @override Widget build(BuildContext context) { return GameWidget( - backgroundBuilder: (context) => Container( - color: Colors.black54, - ), + backgroundBuilder: widget.options?.backgroundBuilder, overlayBuilderMap: overlayBuilderMap2, game: graphCpn = GraphComponent( data: widget.data, convertor: widget.convertor, algorithm: widget.algorithm, + options: widget.options, context: context, ), ); diff --git a/lib/model/graph.dart b/lib/model/graph.dart index 649c933..c06d062 100644 --- a/lib/model/graph.dart +++ b/lib/model/graph.dart @@ -37,4 +37,14 @@ class Graph { /// The origin business data of graph. /// 图的原始业务数据。 dynamic data; + + /// cache the all tags of vertexes. + /// + /// 缓存所有的节点标签 + List allTags = []; + + /// cache the all edge name + /// + /// 缓存所有的边类型 + List allEdgeNames = []; } diff --git a/lib/model/vertex.dart b/lib/model/vertex.dart index 45290ef..74d3144 100644 --- a/lib/model/vertex.dart +++ b/lib/model/vertex.dart @@ -69,20 +69,7 @@ class Vertex { int deep = 1; - late List colors = [ - Color.fromRGBO( - math.Random().nextInt(160) + 80, - math.Random().nextInt(160) + 80, - math.Random().nextInt(160) + 80, - 1, - ), - Color.fromRGBO( - math.Random().nextInt(160) + 80, - math.Random().nextInt(160) + 80, - math.Random().nextInt(160) + 80, - 1, - ), - ]; + List colors = []; /// Default position of current vertex in graph. /// 节点在图中的默认位置。 diff --git a/lib/widgets/graph_component.dart b/lib/widgets/graph_component.dart index 8df64bc..94e7173 100644 --- a/lib/widgets/graph_component.dart +++ b/lib/widgets/graph_component.dart @@ -59,6 +59,7 @@ class GraphComponent extends FlameGame vertex.cpn = vc; add(vc); } + options.graphStyle.graphColor(graph); } updateViewport(x, y) { diff --git a/pubspec.yaml b/pubspec.yaml index 94cf8ba..f82dce9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_graph_view description: Widgets for beautiful graphic data structures, such as force-oriented diagrams. -version: 0.0.1+7 +version: 0.0.1+8 homepage: https://github.com/dudu-ltd/flutter_graph_view environment: