LCOV - code coverage report
Current view: top level - lib/charts/painter - foreground_chart_painter.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 67 107 62.6 %
Date: 2024-10-04 11:12:13 Functions: 0 0 -

          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 'package:app_finance/_classes/herald/app_locale.dart';
       5             : import 'package:app_finance/charts/painter/abstract_painter.dart';
       6             : import 'package:flutter/material.dart';
       7             : import 'package:intl/intl.dart' as intl;
       8             : 
       9             : typedef Percentage = int;
      10             : 
      11             : class ForegroundChartPainter extends AbstractPainter {
      12             :   final Color color;
      13             :   final Color lineColor;
      14             :   final Color areaColor;
      15             :   final Color background;
      16             :   final List<double> yArea;
      17             :   final Type? xType;
      18             :   final Type? yType;
      19             :   final List<dynamic> yMap;
      20             :   late final double textArea;
      21             :   late final double shift;
      22             :   late final int yDiv;
      23             :   final int yDivider;
      24             :   late final int xDiv;
      25             :   final int xDivider;
      26             :   final dynamic xTpl;
      27             :   final dynamic yTpl;
      28             : 
      29             :   static const double coercion = 1.2;
      30             : 
      31           1 :   ForegroundChartPainter({
      32             :     required super.size,
      33             :     super.indent = 0.0,
      34             :     this.areaColor = Colors.green,
      35             :     this.background = Colors.grey,
      36             :     this.color = Colors.black,
      37             :     this.lineColor = Colors.black,
      38             :     this.xDivider = 12,
      39             :     super.xMin = 0.0,
      40             :     super.xMax = 1.0,
      41             :     this.xTpl,
      42             :     this.xType = double,
      43             :     this.yArea = const [],
      44             :     this.yMap = const [],
      45             :     this.yDivider = 12,
      46             :     super.yMin = 0.0,
      47             :     super.yMax = 1.0,
      48             :     this.yTpl,
      49             :     this.yType = double,
      50             :   }) {
      51           1 :     _setTextArea();
      52           3 :     shift = textArea * coercion;
      53           1 :     final tmp = size ?? const Size(0, 0);
      54           5 :     yDiv = yDivider * tmp.height ~/ 400;
      55           5 :     xDiv = xDivider * tmp.width ~/ 640;
      56             :   }
      57             : 
      58           1 :   void _setTextArea() {
      59           3 :     double tmp = (size?.width ?? 0) / 20;
      60           1 :     if (tmp > 32) {
      61           0 :       textArea = 32.0;
      62           1 :     } else if (tmp < 20) {
      63           1 :       textArea = 20.0;
      64             :     } else {
      65           0 :       textArea = tmp;
      66             :     }
      67             :   }
      68             : 
      69           1 :   @override
      70             :   void paint(Canvas canvas, Size size) {
      71           1 :     size = this.size ?? size;
      72           1 :     _paintAxisY(canvas, size);
      73           1 :     _paintAxisX(canvas, size);
      74           3 :     if (yArea.length == 2) {
      75           0 :       _plotAssert(canvas, size);
      76           0 :       _paintAssertLine(canvas, size, (yArea[0] + yArea[1]) / 2);
      77           3 :     } else if (yArea.length == 1) {
      78           0 :       _paintAssertLine(canvas, size, yArea[0]);
      79             :     }
      80             :   }
      81             : 
      82           0 :   void _paintAssertLine(Canvas canvas, Size size, double yPos) {
      83           0 :     final line = Paint()
      84           0 :       ..color = areaColor
      85           0 :       ..strokeWidth = 1;
      86           0 :     if (yMax == 0 || yDiv == 0) {
      87             :       return;
      88             :     }
      89           0 :     double y = _shiftStep(size.height, textArea, yDiv, (yPos - yMin) / (yMax / yDiv));
      90           0 :     canvas.drawLine(Offset(shift, y), Offset(size.width, y), line);
      91             :   }
      92             : 
      93           0 :   void _plotAssert(Canvas canvas, Size size) {
      94           0 :     final background = Paint()
      95           0 :       ..color = areaColor.withOpacity(0.1)
      96           0 :       ..style = PaintingStyle.fill;
      97           0 :     if (yMax == 0 || yDiv == 0) {
      98             :       return;
      99             :     }
     100           0 :     canvas.drawRect(
     101           0 :       Rect.fromPoints(
     102           0 :         Offset(shift, _shiftStep(size.height, textArea, yDiv, ((yArea[0] - yMin) / (yMax / yDiv)).round())),
     103           0 :         Offset(size.width, _shiftStep(size.height, textArea, yDiv, ((yArea[1] - yMin) / (yMax / yDiv)).round())),
     104             :       ),
     105             :       background,
     106             :     );
     107             :   }
     108             : 
     109           1 :   void _paintText(Canvas canvas, double x, double y, String text) {
     110           1 :     final textPainter = TextPainter(
     111           1 :       text: TextSpan(
     112             :         text: text,
     113           1 :         style: TextStyle(
     114           1 :           color: color,
     115           2 :           fontSize: textArea / 2.2,
     116             :           fontFamily: 'Abel-Regular',
     117             :         ),
     118             :       ),
     119             :       textDirection: TextDirection.ltr,
     120             :     );
     121           1 :     textPainter.layout();
     122           4 :     textPainter.paint(canvas, Offset(x - textPainter.width, y));
     123             :   }
     124             : 
     125           0 :   void _paintIcon(Canvas canvas, double x, double y, IconData? icon) {
     126             :     if (icon == null) {
     127             :       return;
     128             :     }
     129           0 :     final textPainter = TextPainter(
     130           0 :       text: TextSpan(
     131           0 :         text: String.fromCharCode(icon.codePoint),
     132           0 :         style: TextStyle(
     133           0 :           color: color,
     134           0 :           fontSize: textArea,
     135           0 :           fontFamily: Icons.question_mark.fontFamily,
     136             :         ),
     137             :       ),
     138             :       textDirection: TextDirection.ltr,
     139             :     );
     140           0 :     textPainter.layout();
     141           0 :     textPainter.paint(canvas, Offset(x - textPainter.width, y));
     142             :   }
     143             : 
     144           1 :   void _paintAxisY(Canvas canvas, Size size) {
     145           1 :     final lineColor = Paint()
     146           3 :       ..color = this.lineColor.withOpacity(0.4)
     147           1 :       ..strokeWidth = 0.5;
     148           5 :     double step = (yMax - yMin) / yDiv;
     149           3 :     for (int i = 0; i < yDiv; i++) {
     150           1 :       double delta = step * i;
     151           4 :       double y = _shiftStep(size.height, textArea, yDiv, i);
     152           1 :       if (yType != null || i == 0) {
     153           5 :         canvas.drawLine(Offset(shift, y), Offset(size.width, y), lineColor);
     154             :       }
     155           1 :       switch (yType) {
     156           1 :         case double:
     157           3 :           final formatter = yTpl ?? intl.NumberFormat.decimalPatternDigits(decimalDigits: 2, locale: AppLocale.code);
     158           8 :           _paintText(canvas, textArea, y - textArea / 3, formatter.format(yMin + delta));
     159             :           break;
     160           0 :         case IconData:
     161           0 :           final code = i >= yMap.length ? null : yMap[i];
     162           0 :           _paintIcon(canvas, textArea, y - textArea, code);
     163             :           break;
     164           0 :         case Percentage:
     165           0 :           final formatter = yTpl ?? intl.NumberFormat.decimalPatternDigits(decimalDigits: 0, locale: AppLocale.code);
     166           0 :           _paintText(canvas, textArea, y - textArea / 3, formatter.format(yMin + delta) + ' %');
     167             :           break;
     168             :       }
     169             :     }
     170             :   }
     171             : 
     172           1 :   double _shiftStep(total, shift, div, i) {
     173           4 :     return (total - shift) * (1 - i / div);
     174             :   }
     175             : 
     176           1 :   void _paintAxisX(Canvas canvas, Size size) {
     177           1 :     final lineColor = Paint()
     178           3 :       ..color = this.lineColor.withOpacity(0.4)
     179           1 :       ..strokeWidth = 0.5;
     180           1 :     final background = Paint()
     181           3 :       ..color = this.background.withOpacity(0.05)
     182           1 :       ..style = PaintingStyle.fill;
     183           1 :     double step = switch (xType) {
     184           7 :       DateTime => (xMax - xMin - 1) / xDiv,
     185           0 :       _ => (xMax - xMin) / xDiv,
     186             :     };
     187           3 :     double height = size.height - textArea;
     188           3 :     for (int i = 0; i <= xDiv; i++) {
     189           3 :       double delta = step * (xDiv - i);
     190           4 :       double x = _shiftStep(size.width, shift, xDiv, i);
     191           8 :       canvas.drawLine(Offset(x + shift, height), Offset(x + shift, height + 4), lineColor);
     192           2 :       if (i < xDiv) {
     193           2 :         dynamic value = xMin + delta;
     194           2 :         if (xType == DateTime) {
     195           1 :           final formatter = xTpl ?? intl.DateFormat('d');
     196           3 :           value = formatter.format(DateTime.fromMillisecondsSinceEpoch(value.toInt()));
     197             :         } else {
     198           0 :           final formatter = xTpl ?? intl.NumberFormat.decimalPatternDigits(decimalDigits: 1, locale: AppLocale.code);
     199           0 :           value = formatter.format(value as double);
     200             :         }
     201           1 :         if (xType != null) {
     202           6 :           _paintText(canvas, x + shift - 2, height + 1, value.toString());
     203             :         }
     204             :       }
     205           2 :       if (i % 2 != 0) {
     206           1 :         canvas.drawRect(
     207           1 :           Rect.fromPoints(
     208           3 :             Offset(x + shift, 0),
     209           8 :             Offset(_shiftStep(size.width, shift, xDiv, i - 1) + shift, height),
     210             :           ),
     211             :           background,
     212             :         );
     213             :       }
     214             :     }
     215             :   }
     216             : }

Generated by: LCOV version 1.14