Line data Source code
1 : // Copyright 2023 The terCAD team. All rights reserved.
2 : // Use of this source code is governed by a CC BY-NC-ND 4.0 license that can be found in the LICENSE file.
3 :
4 : import 'dart:collection';
5 : import 'dart:math';
6 :
7 : import 'package:app_finance/_classes/herald/app_locale.dart';
8 : import 'package:app_finance/_classes/structure/interface_app_data.dart';
9 : import 'package:app_finance/_ext/build_context_ext.dart';
10 : import 'package:app_finance/charts/interface/chart_data.dart';
11 : import 'package:app_finance/charts/painter/bar_chart_painter.dart';
12 : import 'package:app_finance/charts/painter/foreground_chart_painter.dart';
13 : import 'package:app_finance/design/generic/empty_widget.dart';
14 : import 'package:material_ui/material_ui.dart';
15 : import 'package:intl/intl.dart';
16 :
17 : class BarRaceChart extends StatelessWidget {
18 : final double width;
19 : final double indent;
20 : final String tooltip;
21 : final List<InterfaceAppData> categories;
22 : final List<Offset> data;
23 :
24 0 : const BarRaceChart({
25 : super.key,
26 : required this.data,
27 : required this.categories,
28 : required this.width,
29 : this.indent = 0.0,
30 : this.tooltip = '',
31 : });
32 :
33 0 : List<ChartData> _getData() {
34 0 : final plot = SplayTreeMap<double, ChartData>();
35 0 : final rnd = Random();
36 0 : for (int i = 0; i < data.length; i++) {
37 0 : final key = data[i].dy + rnd.nextDouble();
38 0 : final id = data[i].dx.toInt();
39 0 : plot[key] = ChartData([data[i]], color: categories[id].color ?? Colors.grey, helper: categories[id]);
40 : }
41 0 : int idx = plot.values.length;
42 0 : return plot.values.map((e) {
43 0 : e.data.replaceRange(0, 1, [Offset(idx.toDouble(), e.data.first.dy)]);
44 0 : idx--;
45 : return e;
46 0 : }).toList();
47 : }
48 :
49 0 : @override
50 : Widget build(BuildContext context) {
51 0 : if (data.isEmpty) {
52 : return const EmptyWidget();
53 : }
54 0 : final bgColor = context.colorScheme.onSurface;
55 0 : final xMax = data.reduce((max, item) => item.dy > max.dy ? item : max).dy;
56 0 : final plot = _getData();
57 0 : final size = Size(width, 36.0 * (1 + plot.length));
58 0 : final bg = ForegroundChartPainter(
59 : size: size,
60 : color: bgColor,
61 : lineColor: bgColor,
62 0 : background: bgColor.withValues(alpha: 0.1),
63 : yMin: 0.0,
64 0 : yMax: 1.0 + plot.length,
65 : yType: null,
66 : xMin: 0.0,
67 0 : xMax: (xMax * 1.2).ceilToDouble(),
68 : xType: double,
69 0 : xTpl: NumberFormat.compact(locale: AppLocale.code),
70 : );
71 0 : return SizedBox(
72 0 : height: size.height,
73 0 : width: size.width,
74 0 : child: CustomPaint(
75 : size: size,
76 0 : painter: BarChartPainter(
77 0 : indent: bg.shift,
78 : lineColor: bgColor,
79 : size: size,
80 : data: plot,
81 0 : yMax: bg.yMax + 0.4,
82 0 : xMin: bg.xMin,
83 0 : xMax: bg.xMax,
84 : ),
85 : foregroundPainter: bg,
86 : willChange: false,
87 0 : child: Padding(
88 0 : padding: EdgeInsets.only(top: indent / 4),
89 0 : child: Text(tooltip),
90 : ),
91 : ),
92 : );
93 : }
94 : }
|