using System; using System.Collections.ObjectModel; using CommunityToolkit.Mvvm.ComponentModel; using LiveChartsCore; using LiveChartsCore.Defaults; using LiveChartsCore.SkiaSharpView; using LiveChartsCore.SkiaSharpView.Painting; using SkiaSharp; namespace HC_APTBS.ViewModels { /// /// Reusable ViewModel for a single real-time scrolling line chart. /// Backed by LiveChartsCore with a fixed-width sample window. /// public sealed partial class SingleFlowChartViewModel : ObservableObject { private const int DefaultMaxSamples = 200; private readonly ObservableCollection _values = new(); private readonly int _maxSamples; /// Chart title label. [ObservableProperty] private string _title = string.Empty; /// Most recent sample value, displayed as a numeric label alongside the chart. [ObservableProperty] private double _currentValue; /// Series array bound to the CartesianChart. public ISeries[] Series { get; } /// X axes for the chart (auto-scrolling, no labels). public Axis[] XAxes { get; } /// Y axes for the chart. public Axis[] YAxes { get; } /// /// Tolerance band sections overlaid on the chart. /// Updated when is called. /// [ObservableProperty] private RectangularSection[] _sections = Array.Empty(); /// /// Creates a new chart ViewModel. /// /// Display title for the chart. /// SKColor for the line series. /// Maximum number of samples before the oldest is dropped. public SingleFlowChartViewModel(string title, SKColor lineColor, int maxSamples = DefaultMaxSamples) { _title = title; _maxSamples = maxSamples; Series = new ISeries[] { new LineSeries { Values = _values, Fill = null, GeometrySize = 0, Stroke = new SolidColorPaint(lineColor, 2), LineSmoothness = 0, AnimationsSpeed = TimeSpan.Zero } }; XAxes = new Axis[] { new Axis { IsVisible = false, AnimationsSpeed = TimeSpan.Zero } }; YAxes = new Axis[] { new Axis { AnimationsSpeed = TimeSpan.Zero, MinLimit = 0 } }; } /// /// Appends a value to the chart. Drops the oldest value when the window is full. /// Must be called on the UI thread. /// public void AddValue(double value) { _values.Add(value); CurrentValue = value; if (_values.Count > _maxSamples) _values.RemoveAt(0); } /// /// Sets the tolerance band (displayed as a shaded region on the chart). /// /// Center value of the tolerance band. /// Half-width of the tolerance band. public void SetTolerance(double target, double tolerance) { Sections = new[] { new RectangularSection { Yi = target - tolerance, Yj = target + tolerance, Fill = new SolidColorPaint(SKColors.LimeGreen.WithAlpha(40)) } }; } /// /// Clears all sample data and tolerance bands. /// public void Clear() { _values.Clear(); Sections = Array.Empty(); } } }