LCOV - code coverage report
Current view: top level - lib/charts/painter - forecast_chart_painter.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 51 0.0 %
Date: 2024-10-04 11:09:33 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/charts/data/monte_carlo_simulation.dart';
       5             : import 'package:app_finance/charts/interface/chart_data.dart';
       6             : import 'package:app_finance/charts/painter/abstract_painter.dart';
       7             : import 'package:flutter/material.dart';
       8             : import 'dart:ui';
       9             : 
      10             : class ForecastChartPainter extends AbstractPainter {
      11             :   final List<ChartData> data;
      12             : 
      13           0 :   ForecastChartPainter({
      14             :     required super.indent,
      15             :     required this.data,
      16             :     super.size,
      17             :     super.xMax = 1.0,
      18             :     super.xMin = 0.0,
      19             :     super.yMax = 1.0,
      20             :   });
      21             : 
      22           0 :   @override
      23             :   void paint(Canvas canvas, Size size) {
      24           0 :     if (data.isEmpty) {
      25             :       return;
      26             :     }
      27           0 :     size = this.size ?? size;
      28           0 :     for (final scope in data) {
      29           0 :       _paint(canvas, scope.data, size, scope.color);
      30           0 :       final dx = scope.data.last.dx;
      31           0 :       final total = _sumY(scope.data);
      32           0 :       if (scope.data.length > 2 && dx < xMax && total < yMax) {
      33           0 :         final cycles = (xMax - dx) ~/ msDay;
      34           0 :         final forecast = [Offset(scope.data.last.dx, total)];
      35           0 :         forecast.addAll(MonteCarloSimulation(cycles: cycles).generate(scope.data, msDay, xMax - 2 * msDay));
      36           0 :         _paint(canvas, forecast, size, scope.color.withBlue(200).withOpacity(0.4));
      37             :       }
      38             :     }
      39             :   }
      40             : 
      41           0 :   List<dynamic> _bind(Offset point, Size size, double total) {
      42           0 :     return [
      43           0 :       total + point.dy,
      44           0 :       getValue(point, size, total),
      45             :     ];
      46             :   }
      47             : 
      48           0 :   double _sumY(List<Offset> scope) {
      49           0 :     return scope.fold(0.0, (v, e) => v + e.dy);
      50             :   }
      51             : 
      52           0 :   Offset _getMedian(List<Offset> scope, double dx) {
      53           0 :     return Offset(dx, _sumY(scope));
      54             :   }
      55             : 
      56           0 :   void _paint(Canvas canvas, List<Offset> scope, Size size, Color color, [double total = 0.0]) {
      57           0 :     if (scope.isEmpty) {
      58             :       return;
      59             :     }
      60             :     Offset startPoint;
      61           0 :     [_, startPoint] = _bind(scope.first, size, total);
      62             :     int count = 0;
      63             :     Offset endPoint;
      64           0 :     [count, endPoint] = _paintDots(canvas, scope, size, color, total);
      65           0 :     int third = count ~/ 3;
      66           0 :     if (third > 0) {
      67           0 :       double dx = scope[count ~/ 2].dx;
      68           0 :       Offset startBezier = getValue(_getMedian(scope.sublist(0, third), dx), size, total);
      69           0 :       total += _sumY(scope.sublist(0, third));
      70           0 :       Offset endBezier = getValue(_getMedian(scope.sublist(third, third * 2), dx), size, total);
      71           0 :       _paintCurve(canvas, startPoint, startBezier, endBezier, endPoint, color);
      72             :     }
      73             :   }
      74             : 
      75           0 :   List<dynamic> _paintDots(Canvas canvas, List<Offset> scope, Size size, Color color, double total) {
      76             :     Offset point = const Offset(0, 0);
      77             :     int i = 0;
      78           0 :     for (i; i < scope.length; i++) {
      79           0 :       [total, point] = _bind(scope[i], size, total);
      80           0 :       if (point.dy < 0) {
      81           0 :         point = Offset(point.dx, 0);
      82           0 :         _paintDot(canvas, point, color);
      83             :         break;
      84             :       }
      85           0 :       _paintDot(canvas, point, color);
      86             :     }
      87           0 :     return [i, point];
      88             :   }
      89             : 
      90           0 :   void _paintDot(Canvas canvas, Offset point, Color color) {
      91           0 :     final dot = Paint()..color = color;
      92           0 :     canvas.drawCircle(point, 2.2, dot);
      93             :   }
      94             : 
      95           0 :   _paintCurve(Canvas canvas, Offset p0, Offset k1, Offset k2, Offset p1, Color color) {
      96           0 :     final line = Paint()
      97           0 :       ..color = color
      98           0 :       ..style = PaintingStyle.stroke
      99           0 :       ..strokeWidth = 2;
     100           0 :     final path = Path()..moveTo(p0.dx, p0.dy);
     101           0 :     path.cubicTo(k1.dx, k1.dy, k2.dx, k2.dy, p1.dx, p1.dy);
     102           0 :     canvas.drawPath(path, line);
     103             :   }
     104             : }

Generated by: LCOV version 1.14