flet-charts 0.2.0.dev13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of flet-charts might be problematic. Click here for more details.

Files changed (38) hide show
  1. flet_charts/__init__.py +35 -0
  2. flet_charts/bar_chart.py +237 -0
  3. flet_charts/bar_chart_group.py +33 -0
  4. flet_charts/bar_chart_rod.py +111 -0
  5. flet_charts/bar_chart_rod_stack_item.py +31 -0
  6. flet_charts/chart_axis.py +64 -0
  7. flet_charts/line_chart.py +251 -0
  8. flet_charts/line_chart_data.py +140 -0
  9. flet_charts/line_chart_data_point.py +85 -0
  10. flet_charts/matplotlib_chart.py +64 -0
  11. flet_charts/pie_chart.py +89 -0
  12. flet_charts/pie_chart_section.py +89 -0
  13. flet_charts/plotly_chart.py +56 -0
  14. flet_charts/scatter_chart.py +218 -0
  15. flet_charts/scatter_chart_spot.py +102 -0
  16. flet_charts/types.py +288 -0
  17. flet_charts-0.2.0.dev13.dist-info/METADATA +69 -0
  18. flet_charts-0.2.0.dev13.dist-info/RECORD +38 -0
  19. flet_charts-0.2.0.dev13.dist-info/WHEEL +5 -0
  20. flet_charts-0.2.0.dev13.dist-info/licenses/LICENSE +201 -0
  21. flet_charts-0.2.0.dev13.dist-info/top_level.txt +2 -0
  22. flutter/flet_charts/CHANGELOG.md +3 -0
  23. flutter/flet_charts/LICENSE +201 -0
  24. flutter/flet_charts/README.md +3 -0
  25. flutter/flet_charts/analysis_options.yaml +5 -0
  26. flutter/flet_charts/lib/flet_charts.dart +3 -0
  27. flutter/flet_charts/lib/src/bar_chart.dart +95 -0
  28. flutter/flet_charts/lib/src/extension.dart +25 -0
  29. flutter/flet_charts/lib/src/line_chart.dart +236 -0
  30. flutter/flet_charts/lib/src/pie_chart.dart +71 -0
  31. flutter/flet_charts/lib/src/scatter_chart.dart +140 -0
  32. flutter/flet_charts/lib/src/utils/bar_chart.dart +177 -0
  33. flutter/flet_charts/lib/src/utils/charts.dart +173 -0
  34. flutter/flet_charts/lib/src/utils/line_chart.dart +208 -0
  35. flutter/flet_charts/lib/src/utils/pie_chart.dart +56 -0
  36. flutter/flet_charts/lib/src/utils/scatter_chart.dart +85 -0
  37. flutter/flet_charts/pubspec.lock +776 -0
  38. flutter/flet_charts/pubspec.yaml +24 -0
@@ -0,0 +1,140 @@
1
+ import 'package:fl_chart/fl_chart.dart';
2
+ import 'package:flet/flet.dart';
3
+ import 'package:flutter/material.dart';
4
+
5
+ import 'utils/charts.dart';
6
+ import 'utils/scatter_chart.dart';
7
+
8
+ class ScatterChartControl extends StatefulWidget {
9
+ final Control control;
10
+
11
+ ScatterChartControl({Key? key, required this.control})
12
+ : super(key: ValueKey("control_${control.id}"));
13
+
14
+ @override
15
+ State<ScatterChartControl> createState() => _ScatterChartControlState();
16
+ }
17
+
18
+ class _ScatterChartControlState extends State<ScatterChartControl> {
19
+ @override
20
+ Widget build(BuildContext context) {
21
+ final theme = Theme.of(context);
22
+ var animation = widget.control.getAnimation(
23
+ "animation",
24
+ ImplicitAnimationDetails(
25
+ duration: const Duration(milliseconds: 150),
26
+ curve: Curves.linear))!;
27
+ var border = widget.control.getBorder("border", theme);
28
+
29
+ var leftTitles = parseAxisTitles(widget.control.child("left_axis"));
30
+ var topTitles = parseAxisTitles(widget.control.child("top_axis"));
31
+ var rightTitles = parseAxisTitles(widget.control.child("right_axis"));
32
+ var bottomTitles = parseAxisTitles(widget.control.child("bottom_axis"));
33
+
34
+ var interactive = widget.control.getBool("interactive", true)!;
35
+
36
+ // Build list of ScatterSpotData
37
+ final spots = widget.control.children('spots').map((spot) {
38
+ var x = spot.getDouble('x', 0)!;
39
+ var y = spot.getDouble('y', 0)!;
40
+ return ScatterSpot(x, y,
41
+ show: spot.getBool('visible', true)!,
42
+ renderPriority: spot.getInt('render_priority', 0)!,
43
+ xError: spot.get('x_error'),
44
+ yError: spot.get('y_error'),
45
+ dotPainter: spot.get("point") != null
46
+ ? parseChartDotPainter(spot.get("point"), theme, 0, null, null)
47
+ : FlDotCirclePainter(
48
+ radius: spot.getDouble("radius"),
49
+ color: spot.getColor(
50
+ "color",
51
+ context,
52
+ Colors.primaries[
53
+ ((x * y) % Colors.primaries.length).toInt()])!,
54
+ ));
55
+ }).toList();
56
+
57
+ final chart = ScatterChart(
58
+ ScatterChartData(
59
+ scatterSpots: spots,
60
+ backgroundColor: widget.control.getColor("bgcolor", context),
61
+ minX: widget.control.getDouble("min_x"),
62
+ maxX: widget.control.getDouble("max_x"),
63
+ minY: widget.control.getDouble("min_y"),
64
+ maxY: widget.control.getDouble("max_y"),
65
+ baselineX: widget.control.getDouble("baseline_x"),
66
+ baselineY: widget.control.getDouble("baseline_y"),
67
+ titlesData: FlTitlesData(
68
+ show: (leftTitles.sideTitles.showTitles ||
69
+ topTitles.sideTitles.showTitles ||
70
+ rightTitles.sideTitles.showTitles ||
71
+ bottomTitles.sideTitles.showTitles),
72
+ leftTitles: leftTitles,
73
+ topTitles: topTitles,
74
+ rightTitles: rightTitles,
75
+ bottomTitles: bottomTitles,
76
+ ),
77
+ borderData: FlBorderData(show: border != null, border: border),
78
+ gridData: parseChartGridData(
79
+ widget.control.get("horizontal_grid_lines"),
80
+ widget.control.get("vertical_grid_lines"),
81
+ theme),
82
+ scatterTouchData: ScatterTouchData(
83
+ enabled: interactive,
84
+ touchCallback: widget.control.getBool("on_event", false)!
85
+ ? (evt, resp) {
86
+ var eventData =
87
+ ScatterChartEventData.fromDetails(evt, resp);
88
+ widget.control.triggerEvent("event", eventData.toMap());
89
+ }
90
+ : null,
91
+ longPressDuration:
92
+ widget.control.getDuration("long_press_duration"),
93
+ handleBuiltInTouches:
94
+ widget.control.getBool("handle_built_in_touches", true)!,
95
+ touchTooltipData:
96
+ parseScatterTouchTooltipData(context, widget.control, spots)),
97
+ scatterLabelSettings: ScatterLabelSettings(
98
+ showLabel: true,
99
+ getLabelFunction: (spotIndex, spot) {
100
+ var dp = widget.control.children("spots")[spotIndex];
101
+ return dp.getString("label_text", "")!;
102
+ },
103
+ getLabelTextStyleFunction: (spotIndex, spot) {
104
+ var dp = widget.control.children("spots")[spotIndex];
105
+ var labelStyle =
106
+ dp.getTextStyle("label_style", theme, const TextStyle())!;
107
+ if (labelStyle.color == null) {
108
+ labelStyle =
109
+ labelStyle.copyWith(color: spot.dotPainter.mainColor);
110
+ }
111
+ return labelStyle;
112
+ },
113
+ ),
114
+ showingTooltipIndicators: widget.control
115
+ .children('spots')
116
+ .asMap()
117
+ .entries
118
+ .where((e) => e.value.getBool("selected", false)!)
119
+ .map((e) => e.key)
120
+ .toList(),
121
+ rotationQuarterTurns:
122
+ widget.control.getInt('rotation_quarter_turns', 0)!,
123
+ //errorIndicatorData: widget.control.get('error_indicator_data'),
124
+ ),
125
+ duration: animation.duration,
126
+ curve: animation.curve,
127
+ );
128
+
129
+ return ConstrainedControl(
130
+ control: widget.control,
131
+ child: LayoutBuilder(
132
+ builder: (BuildContext context, BoxConstraints constraints) {
133
+ return (constraints.maxHeight == double.infinity)
134
+ ? ConstrainedBox(
135
+ constraints: const BoxConstraints(maxHeight: 300),
136
+ child: chart)
137
+ : chart;
138
+ }));
139
+ }
140
+ }
@@ -0,0 +1,177 @@
1
+ import 'package:collection/collection.dart';
2
+ import 'package:equatable/equatable.dart';
3
+ import 'package:fl_chart/fl_chart.dart';
4
+ import 'package:flet/flet.dart';
5
+ import 'package:flutter/material.dart';
6
+
7
+ import 'charts.dart';
8
+
9
+ class BarChartEventData extends Equatable {
10
+ final String eventType;
11
+ final int? groupIndex;
12
+ final int? rodIndex;
13
+ final int? stackItemIndex;
14
+
15
+ const BarChartEventData(
16
+ {required this.eventType,
17
+ required this.groupIndex,
18
+ required this.rodIndex,
19
+ required this.stackItemIndex});
20
+
21
+ factory BarChartEventData.fromDetails(
22
+ FlTouchEvent event, BarTouchResponse? response) {
23
+ return BarChartEventData(
24
+ eventType: eventMap[event.runtimeType.toString()] ?? "undefined",
25
+ groupIndex: response != null && response.spot != null
26
+ ? response.spot!.touchedBarGroupIndex
27
+ : null,
28
+ rodIndex: response != null && response.spot != null
29
+ ? response.spot!.touchedRodDataIndex
30
+ : null,
31
+ stackItemIndex: response != null && response.spot != null
32
+ ? response.spot!.touchedStackItemIndex
33
+ : null);
34
+ }
35
+
36
+ Map<String, dynamic> toMap() => <String, dynamic>{
37
+ 'type': eventType,
38
+ 'group_index': groupIndex,
39
+ 'rod_index': rodIndex,
40
+ 'stack_item_index': stackItemIndex
41
+ };
42
+
43
+ @override
44
+ List<Object?> get props => [eventType, groupIndex, rodIndex, stackItemIndex];
45
+ }
46
+
47
+ TooltipDirection? parseTooltipDirection(String? value,
48
+ [TooltipDirection? defaultValue]) {
49
+ if (value == null) return defaultValue;
50
+ return TooltipDirection.values.firstWhereOrNull(
51
+ (e) => e.name.toLowerCase() == value.toLowerCase()) ??
52
+ defaultValue;
53
+ }
54
+
55
+ BarTouchTooltipData? parseBarTouchTooltipData(
56
+ BuildContext context, Control control,
57
+ [BarTouchTooltipData? defaultValue]) {
58
+ var tooltip = control.get("tooltip");
59
+ if (tooltip == null) return defaultValue;
60
+
61
+ final theme = Theme.of(context);
62
+
63
+ return BarTouchTooltipData(
64
+ getTooltipColor: (BarChartGroupData group) =>
65
+ parseColor(tooltip["bgcolor"], theme, theme.colorScheme.secondary)!,
66
+ tooltipBorderRadius: parseBorderRadius(tooltip["border_radius"]),
67
+ tooltipMargin: parseDouble(tooltip["margin"]),
68
+ tooltipPadding: parsePadding(tooltip["padding"]),
69
+ maxContentWidth: parseDouble(tooltip["max_width"]),
70
+ rotateAngle: parseDouble(tooltip["rotate_angle"]),
71
+ tooltipHorizontalOffset: parseDouble(tooltip["horizontal_offset"]),
72
+ tooltipBorder: parseBorderSide(tooltip["border_side"], theme),
73
+ fitInsideHorizontally: parseBool(tooltip["fit_inside_horizontally"]),
74
+ fitInsideVertically: parseBool(tooltip["fit_inside_vertically"]),
75
+ direction: parseTooltipDirection(tooltip["direction"]),
76
+ getTooltipItem: (group, groupIndex, rod, rodIndex) {
77
+ var rod =
78
+ control.children("groups")[groupIndex].children("rods")[rodIndex];
79
+ return parseBarTooltipItem(rod, context);
80
+ },
81
+ );
82
+ }
83
+
84
+ BarTooltipItem? parseBarTooltipItem(Control rod, BuildContext context) {
85
+ if (!rod.getBool("show_tooltip", true)!) return null;
86
+
87
+ final theme = Theme.of(context);
88
+
89
+ var tooltip = rod.get("tooltip");
90
+ var tooltipTextStyle =
91
+ parseTextStyle(tooltip["text_style"], theme, const TextStyle())!;
92
+ if (tooltipTextStyle.color == null) {
93
+ tooltipTextStyle = tooltipTextStyle.copyWith(
94
+ color: rod.getGradient("gradient", theme)?.colors.first ??
95
+ rod.getColor("color", context, Colors.blueGrey)!);
96
+ }
97
+ return BarTooltipItem(
98
+ tooltip["text"] ?? rod.getDouble("to_y", 0)!.toString(), tooltipTextStyle,
99
+ textAlign: parseTextAlign(tooltip["text_align"], TextAlign.center)!,
100
+ children: tooltip["text_spans"] != null
101
+ ? parseTextSpans(tooltip["text_spans"], theme, (s, eventName,
102
+ [eventData]) {
103
+ s.triggerEvent(eventName, eventData);
104
+ })
105
+ : null);
106
+ }
107
+
108
+ BarChartGroupData parseBarChartGroupData(
109
+ Control group, bool interactiveChart, BuildContext context) {
110
+ group.notifyParent = true;
111
+ return BarChartGroupData(
112
+ x: group.getInt("x", 0)!,
113
+ barsSpace: group.getDouble("spacing"),
114
+ groupVertically: group.getBool("group_vertically", false)!,
115
+ showingTooltipIndicators: group
116
+ .children("rods")
117
+ .asMap()
118
+ .entries
119
+ .where(
120
+ (rod) => !interactiveChart && rod.value.getBool("selected", false)!)
121
+ .map((rod) => rod.key)
122
+ .toList(),
123
+ barRods: group
124
+ .children("rods")
125
+ .map((rod) => parseBarChartRodData(rod, interactiveChart, context))
126
+ .toList(),
127
+ );
128
+ }
129
+
130
+ BarChartRodData parseBarChartRodData(
131
+ Control rod, bool interactiveChart, BuildContext context) {
132
+ rod.notifyParent = true;
133
+
134
+ final theme = Theme.of(context);
135
+ var bgFromY = rod.getDouble("bg_from_y");
136
+ var bgToY = rod.getDouble("bg_to_y");
137
+ var bgcolor = rod.getColor("bgcolor", context);
138
+ var backgroundGradient = rod.getGradient("background_gradient", theme);
139
+
140
+ return BarChartRodData(
141
+ fromY: rod.getDouble("from_y"),
142
+ toY: rod.getDouble("to_y", 0)!,
143
+ width: rod.getDouble("width"),
144
+ color: rod.getColor("color", context),
145
+ gradient: rod.getGradient("gradient", theme),
146
+ borderRadius: rod.getBorderRadius("border_radius"),
147
+ borderSide: rod.getBorderSide("border_side", theme,
148
+ defaultValue: BorderSide.none),
149
+ backDrawRodData: BackgroundBarChartRodData(
150
+ show: (bgFromY != null ||
151
+ bgToY != null ||
152
+ bgcolor != null ||
153
+ backgroundGradient != null),
154
+ fromY: bgFromY,
155
+ toY: bgToY,
156
+ color: bgcolor,
157
+ gradient: backgroundGradient),
158
+ rodStackItems: rod
159
+ .children("stack_items")
160
+ .map((rodStackItem) => parseBarChartRodStackItem(
161
+ rodStackItem, interactiveChart, context))
162
+ .toList());
163
+ }
164
+
165
+ BarChartRodStackItem parseBarChartRodStackItem(
166
+ Control rodStackItem,
167
+ bool interactiveChart,
168
+ BuildContext context,
169
+ ) {
170
+ rodStackItem.notifyParent = true;
171
+ return BarChartRodStackItem(
172
+ rodStackItem.getDouble("from_y")!,
173
+ rodStackItem.getDouble("to_y", 0)!,
174
+ rodStackItem.getColor("color", context)!,
175
+ rodStackItem.getBorderSide("border_side", Theme.of(context),
176
+ defaultValue: BorderSide.none)!);
177
+ }
@@ -0,0 +1,173 @@
1
+ import 'package:collection/collection.dart';
2
+ import 'package:fl_chart/fl_chart.dart';
3
+ import 'package:flet/flet.dart';
4
+ import 'package:flutter/material.dart';
5
+
6
+ FlDotPainter invisibleDotPainter =
7
+ FlDotCirclePainter(radius: 0, strokeWidth: 0);
8
+ FlLine invisibleLine = const FlLine(strokeWidth: 0);
9
+
10
+ FlGridData parseChartGridData(
11
+ dynamic horizontal, dynamic vertical, ThemeData theme) {
12
+ if (horizontal == null && vertical == null) {
13
+ return const FlGridData(show: false);
14
+ }
15
+
16
+ var hLine = parseFlLine(horizontal, theme);
17
+ var vLine = parseFlLine(vertical, theme);
18
+
19
+ return FlGridData(
20
+ show: true,
21
+ drawHorizontalLine: horizontal != null,
22
+ horizontalInterval:
23
+ horizontal != null ? parseDouble(horizontal["interval"]) : null,
24
+ getDrawingHorizontalLine:
25
+ hLine == null ? defaultGridLine : (value) => hLine,
26
+ drawVerticalLine: vertical != null,
27
+ verticalInterval:
28
+ vertical != null ? parseDouble(vertical["interval"]) : null,
29
+ getDrawingVerticalLine: vLine == null ? defaultGridLine : (value) => vLine,
30
+ );
31
+ }
32
+
33
+ FlLine? parseFlLine(dynamic value, ThemeData theme, [FlLine? defaultValue]) {
34
+ if (value == null ||
35
+ (value['color'] == null &&
36
+ value['width'] == null &&
37
+ value['dash_pattern'] == null)) {
38
+ return defaultValue;
39
+ }
40
+
41
+ return FlLine(
42
+ color: parseColor(value['color'], theme, Colors.black)!,
43
+ strokeWidth: parseDouble(value['width'], 2)!,
44
+ dashArray: (value['dash_pattern'] as List?)
45
+ ?.map((e) => parseInt(e))
46
+ .nonNulls
47
+ .toList());
48
+ }
49
+
50
+ FlLine? parseSelectedFlLine(
51
+ dynamic value, ThemeData theme, Color? color, Gradient? gradient,
52
+ [FlLine? defaultValue]) {
53
+ if (value == null) return defaultValue;
54
+
55
+ if (value == false) {
56
+ return invisibleLine;
57
+ } else if (value == true) {
58
+ return FlLine(
59
+ color: getDefaultPointColor(0, color, gradient), strokeWidth: 3);
60
+ }
61
+
62
+ return parseFlLine(value, theme, defaultValue)?.copyWith(
63
+ color: parseColor(
64
+ value['color'], theme, defaultGetDotStrokeColor(0, color, gradient)));
65
+ }
66
+
67
+ FlDotPainter? parseChartDotPainter(dynamic value, ThemeData theme,
68
+ double percentage, Color? barColor, Gradient? barGradient,
69
+ {FlDotPainter? defaultValue, bool selected = false}) {
70
+ if (value == null) {
71
+ return defaultValue;
72
+ } else if (value == false) {
73
+ return invisibleDotPainter;
74
+ } else if (value == true) {
75
+ return getDefaultDotPainter(percentage, barColor, barGradient,
76
+ selected: selected);
77
+ }
78
+ var type = value["_type"];
79
+ var strokeWidth = parseDouble(value["stroke_width"]);
80
+ var size = parseDouble(value["size"]);
81
+ var color = parseColor(value['color'], theme);
82
+ var strokeColor = parseColor(value['stroke_color'], theme,
83
+ defaultGetDotStrokeColor(percentage, barColor, barGradient))!;
84
+
85
+ if (type == "ChartCirclePoint") {
86
+ return FlDotCirclePainter(
87
+ color: color ?? getDefaultPointColor(percentage, barColor, barGradient),
88
+ radius: parseDouble(value["radius"]),
89
+ strokeColor: strokeColor,
90
+ strokeWidth: strokeWidth ?? 0.0);
91
+ } else if (type == "ChartSquarePoint") {
92
+ return FlDotSquarePainter(
93
+ color: color ?? getDefaultPointColor(percentage, barColor, barGradient),
94
+ size: size ?? 4.0,
95
+ strokeColor: strokeColor,
96
+ strokeWidth: strokeWidth ?? 1.0);
97
+ } else if (type == "ChartCrossPoint") {
98
+ return FlDotCrossPainter(
99
+ color:
100
+ color ?? defaultGetDotStrokeColor(percentage, barColor, barGradient),
101
+ size: size ?? 8.0,
102
+ width: parseDouble(value["width"], 2.0)!,
103
+ );
104
+ }
105
+ return defaultValue;
106
+ }
107
+
108
+ FlDotPainter getDefaultDotPainter(
109
+ double percentage, Color? barColor, Gradient? barGradient,
110
+ {bool selected = false}) {
111
+ return FlDotCirclePainter(
112
+ radius: selected ? 8 : 4,
113
+ strokeWidth: selected ? 2 : 1,
114
+ color: getDefaultPointColor(percentage, barColor, barGradient),
115
+ strokeColor: defaultGetDotStrokeColor(percentage, barColor, barGradient),
116
+ );
117
+ }
118
+
119
+ Color getDefaultPointColor(
120
+ double percentage, Color? barColor, Gradient? barGradient) {
121
+ if (barGradient != null && barGradient is LinearGradient) {
122
+ return lerpGradient(
123
+ barGradient.colors, barGradient.getSafeColorStops(), percentage / 100);
124
+ }
125
+ return barGradient?.colors.first ?? barColor ?? Colors.blueGrey;
126
+ }
127
+
128
+ Color defaultGetDotStrokeColor(double percentage,
129
+ [Color? barColor, Gradient? barGradient]) {
130
+ Color color = getDefaultPointColor(percentage, barColor, barGradient);
131
+ return color.darken();
132
+ }
133
+
134
+ AxisTitles parseAxisTitles(Control? control) {
135
+ if (control == null) {
136
+ return const AxisTitles(sideTitles: SideTitles(showTitles: false));
137
+ }
138
+
139
+ return AxisTitles(
140
+ axisNameWidget: control.buildWidget("title"),
141
+ axisNameSize: control.getDouble("title_size", 16)!,
142
+ sideTitles: SideTitles(
143
+ showTitles: control.getBool("show_labels", true)!,
144
+ reservedSize: control.getDouble("label_size", 22)!,
145
+ interval: control.getDouble("label_spacing"),
146
+ getTitlesWidget: control.children("labels").isEmpty
147
+ ? defaultGetTitle
148
+ : (double value, TitleMeta meta) {
149
+ var label = control
150
+ .children("labels")
151
+ .firstWhereOrNull((l) => l.getDouble("value") == value);
152
+ return label?.buildTextOrWidget("label") ??
153
+ const SizedBox.shrink();
154
+ },
155
+ ));
156
+ }
157
+
158
+ const eventMap = {
159
+ "FlPointerEnterEvent": "pointerEnter",
160
+ "FlPointerExitEvent": "pointerExit",
161
+ "FlPointerHoverEvent": "pointerHover",
162
+ "FlPanCancelEvent": "panCancel",
163
+ "FlPanDownEvent": "panDown",
164
+ "FlPanEndEvent": "panEnd",
165
+ "FlPanStartEvent": "panStart",
166
+ "FlPanUpdateEvent": "panUpdate",
167
+ "FlLongPressEnd": "longPressEnd",
168
+ "FlLongPressMoveUpdate": "longPressMoveUpdate",
169
+ "FlLongPressStart": "longPressStart",
170
+ "FlTapCancelEvent": "tapCancel",
171
+ "FlTapDownEvent": "tapDown",
172
+ "FlTapUpEvent": "tapUp",
173
+ };
@@ -0,0 +1,208 @@
1
+ import 'package:equatable/equatable.dart';
2
+ import 'package:fl_chart/fl_chart.dart';
3
+ import 'package:flet/flet.dart';
4
+ import 'package:flutter/material.dart';
5
+
6
+ import 'charts.dart';
7
+
8
+ class LineChartEventData extends Equatable {
9
+ final String eventType;
10
+ final List<LineChartEventDataSpot> barSpots;
11
+
12
+ const LineChartEventData({required this.eventType, required this.barSpots});
13
+
14
+ factory LineChartEventData.fromDetails(
15
+ FlTouchEvent event, LineTouchResponse? response) {
16
+ return LineChartEventData(
17
+ eventType: eventMap[event.runtimeType.toString()] ?? "undefined",
18
+ barSpots: response != null && response.lineBarSpots != null
19
+ ? response.lineBarSpots!
20
+ .map((bs) => LineChartEventDataSpot(
21
+ barIndex: bs.barIndex, spotIndex: bs.spotIndex))
22
+ .toList()
23
+ : []);
24
+ }
25
+
26
+ Map<String, dynamic> toMap() => <String, dynamic>{
27
+ 'type': eventType,
28
+ 'spots': barSpots,
29
+ };
30
+
31
+ @override
32
+ List<Object?> get props => [eventType, barSpots];
33
+ }
34
+
35
+ class LineChartEventDataSpot extends Equatable {
36
+ final int barIndex;
37
+ final int spotIndex;
38
+
39
+ const LineChartEventDataSpot(
40
+ {required this.barIndex, required this.spotIndex});
41
+
42
+ Map<String, dynamic> toMap() => <String, dynamic>{
43
+ 'bar_index': barIndex,
44
+ 'spot_index': spotIndex,
45
+ };
46
+
47
+ @override
48
+ List<Object?> get props => [barIndex, spotIndex];
49
+ }
50
+
51
+ LineTooltipItem? parseLineTooltipItem(
52
+ Control dataPoint, LineBarSpot spot, BuildContext context) {
53
+ if (!dataPoint.getBool("show_tooltip", true)!) return null;
54
+
55
+ final theme = Theme.of(context);
56
+
57
+ var tooltip = dataPoint.get("tooltip");
58
+ var style = parseTextStyle(tooltip["text_style"], theme, const TextStyle())!;
59
+ if (style.color == null) {
60
+ style = style.copyWith(
61
+ color: spot.bar.gradient?.colors.first ??
62
+ spot.bar.color ??
63
+ Colors.blueGrey);
64
+ }
65
+ return LineTooltipItem(
66
+ tooltip["text"] ?? dataPoint.getDouble("y", 0)!.toString(), style,
67
+ textAlign: parseTextAlign(tooltip["text_align"], TextAlign.center)!,
68
+ children: tooltip["text_spans"] != null
69
+ ? parseTextSpans(tooltip["text_spans"], theme, (s, eventName,
70
+ [eventData]) {
71
+ s.triggerEvent(eventName, eventData);
72
+ })
73
+ : null);
74
+ }
75
+
76
+ LineTouchTooltipData? parseLineTouchTooltipData(
77
+ BuildContext context, Control control,
78
+ [LineTouchTooltipData? defaultValue]) {
79
+ final tooltip = control.get("tooltip");
80
+ if (tooltip == null) return defaultValue;
81
+
82
+ final theme = Theme.of(context);
83
+
84
+ return LineTouchTooltipData(
85
+ getTooltipColor: (LineBarSpot spot) => parseColor(
86
+ tooltip["bgcolor"], theme, const Color.fromRGBO(96, 125, 139, 1))!,
87
+ tooltipBorderRadius: parseBorderRadius(tooltip["border_radius"]),
88
+ tooltipMargin: parseDouble(tooltip["margin"], 16)!,
89
+ tooltipPadding: parsePadding(tooltip["padding"],
90
+ const EdgeInsets.symmetric(horizontal: 16, vertical: 8))!,
91
+ maxContentWidth: parseDouble(tooltip["max_width"], 120)!,
92
+ rotateAngle: parseDouble(tooltip["rotate_angle"], 0.0)!,
93
+ tooltipHorizontalOffset: parseDouble(tooltip["horizontal_offset"], 0)!,
94
+ tooltipBorder: parseBorderSide(tooltip["border_side"], theme,
95
+ defaultValue: BorderSide.none)!,
96
+ fitInsideHorizontally:
97
+ parseBool(tooltip["fit_inside_horizontally"], false)!,
98
+ fitInsideVertically: parseBool(tooltip["fit_inside_vertically"], false)!,
99
+ showOnTopOfTheChartBoxArea:
100
+ parseBool(tooltip["show_on_top_of_chart_box_area"], false)!,
101
+ getTooltipItems: (List<LineBarSpot> touchedSpots) {
102
+ return touchedSpots
103
+ .map((LineBarSpot spot) => parseLineTooltipItem(
104
+ control
105
+ .children("data_series")[spot.barIndex]
106
+ .children("points")[spot.spotIndex],
107
+ spot,
108
+ context))
109
+ .nonNulls
110
+ .toList();
111
+ },
112
+ );
113
+ }
114
+
115
+ LineChartBarData parseLineChartBarData(
116
+ Control parent,
117
+ Control chartData,
118
+ bool interactiveChart,
119
+ BuildContext context,
120
+ Map<int, List<FlSpot>> barSpots) {
121
+ final theme = Theme.of(context);
122
+
123
+ var aboveLineBgcolor = chartData.getColor("above_line_bgcolor", context);
124
+ var aboveLineGradient = chartData.getGradient("above_line_gradient", theme);
125
+ var belowLineBgcolor = chartData.getColor("below_line_bgcolor", context);
126
+ var belowLineGradient = chartData.getGradient("below_line_gradient", theme);
127
+ var dashPattern = chartData.get("dash_pattern");
128
+ var barColor = chartData.getColor("color", context, Colors.cyan)!;
129
+ var barGradient = chartData.getGradient("gradient", theme);
130
+ var aboveLine = parseFlLine(chartData.get("above_line"), Theme.of(context));
131
+ var belowLine = parseFlLine(chartData.get("below_line"), Theme.of(context));
132
+ var aboveLineCutoffY = chartData.getDouble("above_line_cutoff_y");
133
+ var belowLineCutoffY = chartData.getDouble("below_line_cutoff_y");
134
+
135
+ Map<FlSpot, Control> spots = {
136
+ for (var e in chartData.children("points"))
137
+ FlSpot(e.getDouble("x", 0)!, e.getDouble("y", 0)!): e
138
+ };
139
+ return LineChartBarData(
140
+ preventCurveOverShooting:
141
+ chartData.getBool("prevent_curve_over_shooting", false)!,
142
+ preventCurveOvershootingThreshold:
143
+ chartData.getDouble("prevent_curve_over_shooting_threshold", 10.0)!,
144
+ spots: barSpots[chartData.id] ?? [],
145
+ showingIndicators: chartData
146
+ .children("points")
147
+ .asMap()
148
+ .entries
149
+ .where(
150
+ (dp) => !interactiveChart && dp.value.getBool("selected", false)!)
151
+ .map((e) => e.key)
152
+ .toList(),
153
+ isCurved: chartData.getBool("curved", false)!,
154
+ isStrokeCapRound: chartData.getBool("rounded_stroke_cap", false)!,
155
+ barWidth: chartData.getDouble("stroke_width", 2.0)!,
156
+ dashArray: dashPattern != null
157
+ ? (dashPattern as List).map((e) => parseInt(e)).nonNulls.toList()
158
+ : null,
159
+ shadow: parseBoxShadow(chartData.get("shadow"), Theme.of(context)) ??
160
+ const Shadow(color: Colors.transparent),
161
+ dotData: FlDotData(
162
+ show: true,
163
+ getDotPainter: (spot, percent, barData, index) {
164
+ var allDotsPainter = parseChartDotPainter(
165
+ chartData.get("point"), theme, percent, barColor, barGradient);
166
+ var dotPainter = parseChartDotPainter(
167
+ chartData.children("points")[index].get("point"),
168
+ theme,
169
+ percent,
170
+ barColor,
171
+ barGradient);
172
+ return dotPainter ?? allDotsPainter ?? invisibleDotPainter;
173
+ }),
174
+ aboveBarData: aboveLineBgcolor != null ||
175
+ aboveLineGradient != null ||
176
+ aboveLine != null
177
+ ? BarAreaData(
178
+ show: true,
179
+ color: aboveLineBgcolor,
180
+ gradient: aboveLineGradient,
181
+ applyCutOffY: aboveLineCutoffY != null,
182
+ cutOffY: aboveLineCutoffY ?? 0,
183
+ spotsLine: BarAreaSpotsLine(
184
+ show: aboveLine != null,
185
+ flLineStyle: aboveLine ?? const FlLine(),
186
+ checkToShowSpotLine: (spot) =>
187
+ spots[spot]!.getBool("show_above_line", true)!,
188
+ ))
189
+ : null,
190
+ belowBarData: belowLineBgcolor != null ||
191
+ belowLineGradient != null ||
192
+ belowLine != null
193
+ ? BarAreaData(
194
+ show: true,
195
+ color: belowLineBgcolor,
196
+ gradient: belowLineGradient,
197
+ applyCutOffY: belowLineCutoffY != null,
198
+ cutOffY: belowLineCutoffY ?? 0,
199
+ spotsLine: BarAreaSpotsLine(
200
+ show: belowLine != null,
201
+ flLineStyle: belowLine ?? const FlLine(),
202
+ checkToShowSpotLine: (spot) =>
203
+ spots[spot]!.getBool("show_below_line", true)!,
204
+ ))
205
+ : null,
206
+ color: barColor,
207
+ gradient: barGradient);
208
+ }