LCOV - code coverage report
Current view: top level - lib/charts/painter - forecast_chart_painter.dart Coverage Total Hit
Test: lcov.info Lines: 0.0 % 51 0
Test Date: 2026-11-14 15:04:37 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:material_ui/material_ui.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).withValues(alpha: 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 2.0-1