using System; using System.Collections.Generic; using System.Linq; using System.ComponentModel; using SciChart.Charting.Model.DataSeries; using SciChart.Charting.Visuals.RenderableSeries; using Aitex.Core.Util; using System.Windows.Media; using System.Threading.Tasks; using SciChart.Charting.Visuals.Annotations; using System.Windows; using System.Collections.ObjectModel; namespace SicUI.Models.PMs.Charting { public class ChartDataLineX : FastLineRenderableSeries, INotifyPropertyChanged { private string[] _dbModules = { "PM1", "PM2" }; #region PropertyChanged public event PropertyChangedEventHandler PropertyChanged; public void InvokePropertyChanged(string propertyName) { PropertyChangedEventArgs eventArgs = new PropertyChangedEventArgs(propertyName); PropertyChangedEventHandler changed = PropertyChanged; if (changed != null) { changed(this, eventArgs); } } public void InvokePropertyChanged() { Type t = this.GetType(); var ps = t.GetProperties(); foreach (var p in ps) { InvokePropertyChanged(p.Name); } } #endregion public string UniqueId { get; set; } public string ProcessGuid { get; set; } public string Module { get; set; } public string RecName { get; set; } public List> Points { get { lock (_lockData) { return _queueRawData.ToList(); } } } public string DataSource { get; set; } public string DataName { get; set; } public string DisplayName { get { return DataSeries.SeriesName; } set { DataSeries.SeriesName = value; } } public double LineThickness { get { return StrokeThickness; } set { var i = Convert.ToInt32(value); if (i < 1) i = 1; if (i > 100) i = 100; StrokeThickness = i; InvokePropertyChanged("LineThickness"); } } private double _dataFactor = 1.0; public double DataFactor { get => _dataFactor; set { if (Math.Abs(_dataFactor - value) > 0.001) { _dataFactor = value; InvokePropertyChanged(nameof(DataFactor)); UpdateChartSeriesValue(); } } } private double _dataOffset = 0; public double DataOffset { get => _dataOffset; set { if (Math.Abs(_dataOffset - value) > 0.001) { _dataOffset = value; InvokePropertyChanged(nameof(DataFactor)); UpdateChartSeriesValue(); } } } private double _dataxOffset = 0; public double DataXOffset { get => _dataxOffset; set { _dataxOffset = value; InvokePropertyChanged(nameof(DataFactor)); RePaintChartSeriesValue(); } } private int _capacity = 10000; public int Capacity { get { return _capacity; } set { _capacity = value; //DataSeries.FifoCapacity = value; if (_queueRawData != null) { _queueRawData.FixedSize = value; } } } private object _lockData = new object(); private FixSizeQueue> _queueRawData; public List> _alarmData; public ChartDataLineX(string dataName) : this(dataName, dataName, Colors.Blue) { Module = "System"; foreach (var dbModule in _dbModules) { if (dataName.StartsWith(dbModule)) { Module = dbModule; break; } } } public ChartDataLineX(string dataName, string displayName, Color seriesColor) { UniqueId = Guid.NewGuid().ToString(); _queueRawData = new FixSizeQueue>(_capacity); _alarmData = new List>(); XAxisId = "DefaultAxisId"; YAxisId = "DefaultAxisId"; DataSeries = new XyDataSeries(0); DisplayName = displayName; DataName = dataName; Stroke = seriesColor; IsVisible = true; DataOffset = 0; LineThickness = 1; DataFactor = 1; } public void Append(double xvalue, double value) { lock (_lockData) { _queueRawData.Enqueue(Tuple.Create(xvalue, value)); var series = DataSeries as XyDataSeries; if (series != null) { series.Append(xvalue, value * _dataFactor + _dataOffset); //while (series.Count > _capacity) //{ // series.RemoveRange(0, series.Count - _capacity); //} } } } public void UpdateChartSeriesValue() { lock (_lockData) { using (DataSeries.SuspendUpdates()) { XyDataSeries s = DataSeries as XyDataSeries; for (int i = 0; i < s.Count; i++) { s.Update(i, _queueRawData.ElementAt(i).Item2 * _dataFactor + _dataOffset); } } } } public void RePaintChartSeriesValue() { lock (_lockData) { using (DataSeries.SuspendUpdates()) { DataSeries.Clear(); var series = DataSeries as XyDataSeries; for (int i = 0; i < _queueRawData.Count; i++) { series.Append(_queueRawData.ElementAt(i).Item1 + DataXOffset, _queueRawData.ElementAt(i).Item2 * _dataFactor + _dataOffset); } } } } public void ClearData() { lock (_lockData) { _queueRawData.Clear(); (DataSeries as XyDataSeries)?.Clear(); } } public void AppedAlarm(long timeTicks, string alarmID) { _alarmData.Add(Tuple.Create(timeTicks, alarmID)); } private int _pointCount; public int PointCount { get { return _pointCount; } set { _pointCount = value; InvokePropertyChanged(nameof(PointCount)); } } private double _variance; public double Variance { get { return _variance; } set { _variance = value; InvokePropertyChanged(nameof(Variance)); } } private double _maxValue; public double MaxValue { get { return _maxValue; } set { _maxValue = value; InvokePropertyChanged(nameof(MaxValue)); } } private double _minValue; public double MinValue { get { return _minValue; } set { _minValue = value; InvokePropertyChanged(nameof(MinValue)); } } private double _avgValue; public double AvgValue { get { return _avgValue; } set { _avgValue = value; InvokePropertyChanged(nameof(AvgValue)); } } public void Caculate(double x1,double x2) { //if (RecName == "RealTime") //{ // return; //} double min = x1; double max = x2; if (x1 > x2) { min = x2; max = x1; } if (max - min < 10) { min = 0; max = 100000000; } PointCount = Points.Where(a => a.Item1 >= min && a.Item1 <= max).Count(); if (PointCount == 0) { MaxValue = 0; MinValue = 0; AvgValue = 0; Variance = 0; } else { MaxValue = Points.Where(a => a.Item1 >= min && a.Item1 <= max).Max(x => x.Item2); MinValue = Points.Where(a => a.Item1 >= min && a.Item1 <= max).Min(x => x.Item2); AvgValue = Points.Where(a => a.Item1 >= min && a.Item1 <= max).Average(x => x.Item2); Variance = Points.Where(a => a.Item1 >= min && a.Item1 <= max).Sum(x => Math.Pow(x.Item2 - AvgValue, 2)) / PointCount; } } } }