Files
CapMachine/CapMachine.Wpf/Models/LightChart/ChartRtSeries.cs
2024-12-18 15:50:21 +08:00

613 lines
19 KiB
C#

using Arction.Wpf.Charting;
using Arction.Wpf.Charting.Annotations;
using Arction.Wpf.Charting.Axes;
using Arction.Wpf.Charting.SeriesXY;
using CapMachine.Model;
using CapMachine.Wpf.ChannelModel;
using CapMachine.Wpf.Models.Tag;
using CapMachine.Wpf.Services;
using Force.DeepCloner;
using ImTools;
using Prism.Mvvm;
using System;
using System.Collections.ObjectModel;
using System.IO.Ports;
using System.Windows;
namespace CapMachine.Wpf.Models.LightChart
{
/// <summary>
/// 曲线实时系列模型
/// 曲线的系列的封装
/// </summary>
public class ChartRtSeries : BindableBase
{
/// <summary>
/// 实例化函数
/// </summary>
public ChartRtSeries(LightningChart Chart, ChartColor ChartColor, ObservableCollection<ChartRtSeries> listchartRtSeries, ConfigChart configChart, ConfigService configService,short decimalPoint)
{
//模型赋值
LgChart = Chart;
ChartColorInfo = ChartColor;
ChartAxisY = configChart.ConfigChartYAxis;
ChartAxisX = LgChart.ViewXY.XAxes[0];
Name = configChart.Name;
ListChartRtSeries = listchartRtSeries;
ConfigService = configService;
DecimalPoint = decimalPoint;
AddSeries(configChart.Name!, configChart.ConfigChartYAxis!);
//初始化字符串
ValueEngValueStr = Math.Round(0.00, DecimalPoint).ToString();
LeftCursorEngValueStr = Math.Round(0.00, DecimalPoint).ToString();
RightCursorEngValueStr = Math.Round(0.00, DecimalPoint).ToString();
MinEngValueStr = Math.Round(0.00, DecimalPoint).ToString();
MaxEngValueStr = Math.Round(0.00, DecimalPoint).ToString();
AveEngValueStr = Math.Round(0.00, DecimalPoint).ToString();
}
public ChartRtSeries(LightningChart Chart, ChartColor ChartColor, ObservableCollection<ChartRtSeries> listchartRtSeries, HistoryConfigChart configChart, ConfigService configService, short decimalPoint)
{
//模型赋值
LgChart = Chart;
ChartColorInfo = ChartColor;
ChartAxisY = configChart.ConfigChartYAxis;
ChartAxisX = LgChart.ViewXY.XAxes[0];
Name = configChart.Name;
ListChartRtSeries = listchartRtSeries;
ConfigService = configService;
DecimalPoint = decimalPoint;
AddSeries(configChart.Name!, configChart.ConfigChartYAxis!);
//初始化字符串
ValueEngValueStr= Math.Round(0.00, DecimalPoint).ToString();
LeftCursorEngValueStr = Math.Round(0.00, DecimalPoint).ToString();
RightCursorEngValueStr = Math.Round(0.00, DecimalPoint).ToString();
MinEngValueStr = Math.Round(0.00, DecimalPoint).ToString();
MaxEngValueStr = Math.Round(0.00, DecimalPoint).ToString();
AveEngValueStr = Math.Round(0.00, DecimalPoint).ToString();
}
#region
private string? _Name;
/// <summary>
/// 系列的名称
/// 也是变量的名称
/// </summary>
public string? Name
{
get { return _Name; }
set { _Name = value; RaisePropertyChanged(); }
}
private double _Value;
/// <summary>
/// 值
/// </summary>
public double Value
{
get { return _Value; }
set
{
if (_Value != value)
{
_Value = value;
RaisePropertyChanged();
ValueEngValueStr = Math.Round(value, DecimalPoint).ToString();
}
}
}
private string _ValueEngValueStr;
/// <summary>
/// ValueEngValueStr 值 工程值的字符串
/// </summary>
public string ValueEngValueStr
{
get { return _ValueEngValueStr; }
set { _ValueEngValueStr = value; RaisePropertyChanged(); }
}
/// <summary>
/// 小数点
/// </summary>
public short DecimalPoint { get; set; }
private string? _Group;
/// <summary>
/// 组信息
/// </summary>
public string? Group
{
get { return _Group; }
set { _Group = value; RaisePropertyChanged(); }
}
private string? _Unit;
/// <summary>
/// 单位
/// </summary>
public string? Unit
{
get { return _Unit; }
set { _Unit = value; RaisePropertyChanged(); }
}
private string? _FontInfo = "&#xe6d0;";
/// <summary>
/// 字体信息
/// </summary>
public string? FontInfo
{
get { return _FontInfo; }
set { _FontInfo = value; RaisePropertyChanged(); }
}
/// <summary>
/// 订阅到的缓存的数据
/// </summary>
public List<CacheRtChartData> ListCacheRtChartData { get; set; } = new List<CacheRtChartData>();
#endregion
#region 线
private double _LeftCursorValue;
/// <summary>
/// 左游标值
/// </summary>
public double LeftCursorValue
{
get { return _LeftCursorValue; }
set
{
if (_LeftCursorValue != value)
{
_LeftCursorValue = value;
RaisePropertyChanged();
LeftCursorEngValueStr = Math.Round(value, DecimalPoint).ToString();
}
}
}
private string _LeftCursorEngValueStr;
/// <summary>
/// LeftCursor 左游标值 工程值的字符串
/// </summary>
public string LeftCursorEngValueStr
{
get { return _LeftCursorEngValueStr; }
set { _LeftCursorEngValueStr = value; RaisePropertyChanged(); }
}
private double _RightCursorValue;
/// <summary>
/// 右游标值
/// </summary>
public double RightCursorValue
{
get { return _RightCursorValue; }
set
{
if (_RightCursorValue != value)
{
_RightCursorValue = value;
RaisePropertyChanged();
RightCursorEngValueStr = Math.Round(value, DecimalPoint).ToString();
}
}
}
private string _RightCursorEngValueStr;
/// <summary>
/// RightCursor 右游标值 工程值的字符串
/// </summary>
public string RightCursorEngValueStr
{
get { return _RightCursorEngValueStr; }
set { _RightCursorEngValueStr = value; RaisePropertyChanged(); }
}
private double _MinValue;
/// <summary>
/// 最小值
/// </summary>
public double MinValue
{
get { return _MinValue; }
set
{
if (_MinValue != value)
{
_MinValue = value;
RaisePropertyChanged();
MinEngValueStr = Math.Round(value, DecimalPoint).ToString();
}
}
}
private string _MinEngValueStr;
/// <summary>
/// Min 最小值 工程值的字符串
/// </summary>
public string MinEngValueStr
{
get { return _MinEngValueStr; }
set { _MinEngValueStr = value; RaisePropertyChanged(); }
}
private double _MaxValue;
/// <summary>
/// 最大值
/// </summary>
public double MaxValue
{
get { return _MaxValue; }
set
{
if (_MaxValue != value)
{
_MaxValue = value;
RaisePropertyChanged();
MaxEngValueStr = Math.Round(value, DecimalPoint).ToString();
}
}
}
private string _MaxEngValueStr;
/// <summary>
/// Max 最大值 工程值的字符串
/// </summary>
public string MaxEngValueStr
{
get { return _MaxEngValueStr; }
set { _MaxEngValueStr = value; RaisePropertyChanged(); }
}
private double _AveValue;
/// <summary>
/// 平均值
/// </summary>
public double AveValue
{
get { return _AveValue; }
set
{
if (_AveValue != value)
{
_AveValue = value;
RaisePropertyChanged();
AveEngValueStr = Math.Round(value, DecimalPoint).ToString();
}
}
}
private string _AveEngValueStr;
/// <summary>
/// Ave 平均值 工程值的字符串
/// </summary>
public string AveEngValueStr
{
get { return _AveEngValueStr; }
set { _AveEngValueStr = value; RaisePropertyChanged(); }
}
#endregion
///// <summary>
///// Chart图表X轴的跨度-秒
///// 可以删除之前的数据
///// </summary>
//public int ChartXDateTimeRange { get; set; } = 3600_8;
/// <summary>
/// 删除曲线系列上的数据
/// 积累到一定量后再删除,避免每次更新都删除
/// </summary>
private int MaxDeleteCacheCount { get; set; } = 0;
/// <summary>
/// 增加系列
/// </summary>
/// <param name="Name"></param>
private void AddSeries(string SeriesName, ConfigChartYAxis configChartYAxis)
{
LgChart.BeginUpdate();
//定义一个轴设置
AxisY AxisYInfo;
if (configChartYAxis == null)
{
MessageBox.Show($"没有发现曲线:【{SeriesName}】轴设置信息,将使用默认的轴设置。请到【曲线轴设置】中进行检查", "提示", MessageBoxButton.OK, MessageBoxImage.Hand);
//新增
AxisYInfo = new AxisY();
}
else
{
//轴信息不为空的话,则进行后续的判断
//判断之前的系列是否已经存在(依据名称),存在使用之前的系列,否则新增
AxisYInfo = GetAxisY(configChartYAxis.Name);
if (AxisYInfo == null)
{
//新增
AxisYInfo = new AxisY();
AxisYInfo.Title.Text = configChartYAxis.Name;
AxisYInfo.Title.AllowDragging = false;
AxisYInfo.SetRange(configChartYAxis.Min, configChartYAxis.Max);
AxisYInfo.MajorGrid.Visible = false;
//取消滚轮缩放
AxisYInfo.ZoomingEnabled = false;
LgChart.ViewXY.YAxes.Add(AxisYInfo);
}
else
{
//使用之前
AxisYInfo.SetRange(configChartYAxis.Min, configChartYAxis.Max);
}
}
var SeriesInfo = GetPointLineSeries(SeriesName);
if (SeriesInfo == null)
{
//新增
SeriesInfo = new PointLineSeries(LgChart.ViewXY, LgChart.ViewXY.XAxes[0], AxisYInfo);
SeriesInfo.Title.Text = SeriesName;
SeriesInfo.LineStyle.Color = ChartColorInfo.ListColor[LgChart.ViewXY.PointLineSeries.Count];
SeriesInfo.AllowUserInteraction = false;
LgChart.ViewXY.PointLineSeries.Add(SeriesInfo);
}
else
{
//使用之前
SeriesInfo.AssignYAxisIndex = AxisYInfo.SegmentIndex;
}
//赋值给当前的模型
ChartPointLineSeries = SeriesInfo;
//Configure and add series to the chart
LgChart.EndUpdate();
}
public void AddPointByCache(DateTime dateTime, double value, bool IsDeleteBefore, bool IsScrollEnable)
{
//入缓存集合中
ListCacheRtChartData.Add(new CacheRtChartData()
{
Value = value,
CreateTime = dateTime,
});
//判断是否满足要求
if (ListCacheRtChartData.Count() >= 6)
{
//Disable updates, to prevent several extra refreshes
LgChart.BeginUpdate();
var ListSeriesPoint = ListCacheRtChartData.Select(a => new SeriesPoint()
{
X = ChartAxisX!.DateTimeToAxisValue(a.CreateTime),
Y = a.Value
});
ChartPointLineSeries!.AddPoints(ListSeriesPoint.ToArray(), false);
//暂时不删除数据
if (IsDeleteBefore)
{
MaxDeleteCacheCount++;
//积累到一定量后再删除旧的数据
if (MaxDeleteCacheCount >= 200)
{
ChartPointLineSeries!.DeletePointsBeforeX(ListSeriesPoint.LastOrDefault().X - ConfigService.ChartRtDataCacheTimeSec);
MaxDeleteCacheCount = 0;
}
}
//ChartPointLineSeries!.DeletePointsBeforeX(_previousX - ChartXDateTimeRange);
//item.DeletePointsBeforeX(_previousX - 100);
if (IsScrollEnable)
{
LgChart.ViewXY.XAxes[0].ScrollPosition = ListSeriesPoint.FirstOrDefault().X;
}
//Allow updates again, and update
LgChart.EndUpdate();
//删除缓存的数据
ListCacheRtChartData.Clear();
}
}
/// <summary>
/// 增加数据的点
/// </summary>
public void AddPoint(DateTime dateTime, double value, bool IsDeleteBefore, bool IsScrollEnable)
{
//Disable updates, to prevent several extra refreshes
LgChart.BeginUpdate();
//Array for 1 point
SeriesPoint[] points = new SeriesPoint[1];
//Convert 'Now' to X value
var _previousX = LgChart.ViewXY.XAxes[0].DateTimeToAxisValue(dateTime);
points[0].X = _previousX;
points[0].Y = value;
//Add the new point into end of first PointLineSeries
ChartPointLineSeries!.AddPoints(points, false);
//暂时不删除数据
if (IsDeleteBefore)
{
ChartPointLineSeries!.DeletePointsBeforeX(_previousX - ConfigService.ChartRtDataCacheTimeSec);
}
//ChartPointLineSeries!.DeletePointsBeforeX(_previousX - ChartXDateTimeRange);
//item.DeletePointsBeforeX(_previousX - 100);
if (IsScrollEnable)
{
LgChart.ViewXY.XAxes[0].ScrollPosition = _previousX;
}
//Allow updates again, and update
LgChart.EndUpdate();
}
/// <summary>
/// 批量增加数据的点
/// </summary>
public void AddRangePoint(List<ChartPoint> Data)
{
//Disable updates, to prevent several extra refreshes
LgChart.BeginUpdate();
//Array for 1 point
SeriesPoint[] points = new SeriesPoint[Data.Count];
for (int i = 0; i < Data.Count; i++)
{
//Convert 'Now' to X value
points[i].X = LgChart.ViewXY.XAxes[0].DateTimeToAxisValue(Data[i].Time); ;
points[i].Y = Data[i].Value;
}
//Add the new point into end of first PointLineSeries
ChartPointLineSeries!.AddPoints(points, false);
//Allow updates again, and update
LgChart.EndUpdate();
}
/// <summary>
/// 增加RecordChannelData集合的数据的点
/// </summary>
public void AddPointByDicData(List<RecordChannelData> recordChannelDatas, string Name)
{
var Data = recordChannelDatas.DeepClone();
foreach (var item in Data)
{
if (item.Data!.TryGetValue(Name, out object result))
{
AddPoint(item.CreateTime, Convert.ToDouble(result), false, false);
}
}
}
/// <summary>
/// 增加历史数据的点集合
/// </summary>
/// <param name="chartPoints"></param>
/// <param name="Name"></param>
public void AddRecordPointByName(List<ChartPoint> chartPoints)
{
AddRangePoint(chartPoints);
}
/// <summary>
/// 获取AxisY信息
/// </summary>
/// <param name="AxisName"></param>
/// <returns></returns>
private AxisY GetAxisY(string AxisName)
{
var AxisYs = LgChart.ViewXY.YAxes;
if (AxisYs != null)
{
var findAxis = AxisYs.FindFirst(a => a.Title.Text == AxisName);
if (findAxis != null)
{
return findAxis;
}
else
{
return null;
}
}
else
{
return null;
}
}
/// <summary>
/// 获取PointLineSeries信息
/// </summary>
/// <param name="AxisName"></param>
/// <returns></returns>
private PointLineSeries GetPointLineSeries(string SeriesName)
{
var PointLineSeries = LgChart.ViewXY.PointLineSeries;
if (PointLineSeries != null)
{
var findSeries = PointLineSeries.FindFirst(a => a.Title.Text == SeriesName);
if (findSeries != null)
{
return findSeries;
}
else
{
return null;
}
}
else
{
return null;
}
}
/// <summary>
/// 上层管理集合
/// </summary>
public ObservableCollection<ChartRtSeries> ListChartRtSeries { get; set; }
public ConfigService ConfigService { get; }
/// <summary>
/// 曲线数据
/// </summary>
public PointLineSeries? ChartPointLineSeries { get; set; }
/// <summary>
/// Y轴
/// </summary>
public ConfigChartYAxis? ChartAxisY { get; set; }
/// <summary>
/// Y轴 ConfigChartYAxis Id
/// 用于标记Y轴的配置信息
/// </summary>
public long ConfigChartYAxisId { get; set; }
/// <summary>
/// X轴
/// </summary>
public AxisX? ChartAxisX { get; set; }
/// <summary>
/// LightningChart 实例
/// </summary>
public LightningChart LgChart { get; set; }
/// <summary>
/// 曲线配置信息
/// </summary>
public ChartColor ChartColorInfo { get; set; }
}
}