Files
CapMachine/CapMachine.Wpf/Models/LightChart/ChartManager.cs

1817 lines
74 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Arction.Wpf.Charting;
using Arction.Wpf.Charting.Annotations;
using Arction.Wpf.Charting.Axes;
using Arction.Wpf.Charting.SeriesXY;
using Arction.Wpf.Charting.Views.View3D;
using Arction.Wpf.Charting.Views.ViewXY;
using CapMachine.Model;
using CapMachine.Wpf.ChannelModel;
using CapMachine.Wpf.Models.Tag;
using CapMachine.Wpf.PrismEvent;
using CapMachine.Wpf.Services;
using ImTools;
using Microsoft.Win32;
using NPOI.HSSF.Record.CF;
using NPOI.SS.Formula.Functions;
using NPOI.SS.UserModel;
using NPOI.SS.UserModel.Charts;
using Prism.Events;
using Prism.Mvvm;
using Prism.Services.Dialogs;
using System.Collections;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.ExceptionServices;
using System.Text;
using System.Windows.Input;
using System.Windows.Interop;
namespace CapMachine.Wpf.Models.LightChart
{
/// <summary>
/// 曲线管理
/// 实现对一个Chart实例进行管理
/// </summary>
public class ChartManager : BindableBase
{
/// <summary>
/// 实例化函数
/// </summary>
public ChartManager(IEventAggregator eventAggregator, TagManager tagManager, DataRecordService datRecordService, IFreeSql freeSql,
LightningChart lightningChart,
string Name,
int TabIndex,
string Machine,
bool isRealTimeChart, ILogService logService, ConfigService configService)
{
ListChartRtSeries = new ObservableCollection<ChartRtSeries>();
ListConfigChart = new List<ConfigChart>();
CurSelectedGroupTabIndex = TabIndex;
CurSelectedMachine = Machine;
//实例化函数
LgChart = lightningChart;
ChartName = Name;
LgChart.ChartRenderOptions.GPUPreference = GPUPreference.SystemSetting;
//LgChart.ChartMessage += LgChart_ChartMessage;
//事件服务
_EventAggregator = eventAggregator;
TagManager = tagManager;
DatRecordService = datRecordService;
FreeSql = freeSql;
IsRealTimeChart = isRealTimeChart;
LogService = logService;
ConfigService = configService;
if (IsRealTimeChart)
{
//实时曲线就订阅实时数据
_EventAggregator.GetEvent<RecordDataEvent>().Subscribe(UpdateRecordData, ThreadOption.UIThread);
_EventAggregator.GetEvent<ChartSetEvent>().Subscribe(ChartSetEventCall);
_EventAggregator.GetEvent<ChartSetEnableEvent>().Subscribe(ChartSetEnableEventCall);
_EventAggregator.GetEvent<ChartRtSeriesActionEvent>().Subscribe(ChartRtSeriesActionEventCall);
_EventAggregator.GetEvent<ChartTabGroupSwitchEvent>().Subscribe(ChartTabGroupSwitchCall);
}
else
{
_EventAggregator.GetEvent<HistoryChartSetEvent>().Subscribe(ChartSetEventCall);
_EventAggregator.GetEvent<HistoryChartSetEnableEvent>().Subscribe(ChartSetEnableEventCall);
_EventAggregator.GetEvent<HistoryChartRtSeriesActionEvent>().Subscribe(ChartRtSeriesActionEventCall);
_EventAggregator.GetEvent<HistoryChartTabGroupSwitchEvent>().Subscribe(ChartTabGroupSwitchCall);
_EventAggregator.GetEvent<HistoryDataToChartEvent>().Subscribe(HistoryDataToChartCall, ThreadOption.UIThread);
}
//Y轴对任何的曲线都适用
_EventAggregator.GetEvent<ChartYAxisConfigEvent>().Subscribe(ChartYAxisConfigEventCall);
//初始化曲线
InitChart();
}
/// <summary>
/// LightningChart 通知、错误和异常处理
/// </summary>
/// <param name="info"></param>
/// <exception cref="NotImplementedException"></exception>
private void LgChart_ChartMessage(ChartMessageInfo info)
{
//
//var InternalErrorMsg = "";
//if (info.InternalError != null)
//{
// InternalErrorMsg = info.InternalError.Message;
//}
//LogService.Info($"{ChartName}" +
// $"-是否实时IsRealTimeChart{IsRealTimeChart.ToString()}" +
// $"-消息严重程度:{info.MessageSeverity.ToString()}" +
// $"-MessageType{info.MessageType.ToString()}" +
// $"-Description{info.Description}" +
// $"-Source{info.Source.ToString()}" +
// $"-StackTrace{info.StackTrace}" +
// $"-InternalError{InternalErrorMsg}" +
// $"-Details{info.Details}");
}
/// <summary>
/// 更新Y轴的信息
/// </summary>
/// <param name="msg"></param>
private void ChartYAxisConfigEventCall(ChartYAxisConfigMsg msg)
{
UpdateChartAxisY(msg.ConfigChartYAxes);
}
#region 线
/// <summary>
/// 历史数据
/// </summary>
private List<CsvRecordModel> CurHistoryData { get; set; }
/// <summary>
/// 历史数据加载到Chart的信息
/// </summary>
/// <param name="msg"></param>
private void HistoryDataToChartCall(HistoryDataToChartMsg msg)
{
if (msg.Machine != CurSelectedMachine)
{
//选择了其他的机械的话,则也是没有被激活
IsActivated = false;
return;
}
CurHistoryData = msg.Data;
LoadHistoryDataChart();
}
Stopwatch stopwatch = new Stopwatch();
/// <summary>
/// 加载历史数据到曲线中
/// </summary>
private void LoadHistoryDataChart()
{
if (CurHistoryData == null || CurHistoryData.Count == 0) return;
////第一次计时
stopwatch.Start(); //启动Stopwatch
//var Tags = TagManager.DicTags.Values.ToList();
foreach (var ChartRtSerie in ListChartRtSeries)
{
//var SeriesData = CurHistoryData.Select(a => new ChartPoint() { Value = a.Speed, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
var SeriesData = GetChartPointByName(ChartRtSerie.Name, CurHistoryData);
ChartRtSerie.ChartPointLineSeries!.Clear();
//批量增加数据
ChartRtSerie.AddRangePoint(SeriesData);
//foreach (var item in SeriesData)
//{
// ChartRtSerie.AddPoint(item.Time, (double)item.Value, false, false);
//}
}
//到当前的界面
ChartAxisX.ScrollPosition = ChartAxisX.DateTimeToAxisValue(CurHistoryData.LastOrDefault()!.CreateTime);
stopwatch.Stop(); //停止Stopwatch
Console.WriteLine("加载到曲线耗时::{0}--{1}", stopwatch.Elapsed.TotalSeconds.ToString(), CurSelectedGroupTabIndex.ToString());
stopwatch.Reset();
}
/// <summary>
/// 根据名称获取Point数据
/// </summary>
/// <returns></returns>
private List<ChartPoint> GetChartPointByName(string Name, List<CsvRecordModel> CurHistoryData)
{
switch (Name)
{
case "转速[rpm]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.Speed, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "排气压力[BarA]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.ExPress, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "吸气压力[BarA]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.InhPress, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "吸气温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.InhTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "COND1温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.Cond1Temp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "润滑油压力[BarA]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.LubePress, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "COND2压力[BarA]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.Cond2Press, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "OCR[%]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.OCR, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "HV[V]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.HV, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "HV[A]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.HVCur, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "HV[W]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.HVPw, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "LV[V]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.LV, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "LV[A]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.LVCur, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "环境温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.EnvTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "环境湿度[%]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.EnvRH, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "OS1温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.OS1Temp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "OS2温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.OS2Temp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "COND2温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.Cond2Temp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "EVAP出口温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.EVAPExpTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "冷媒流量[L/min]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.VRV, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "润滑油流量[L/min]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.LubeFlow, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "排气温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.ExTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "膨胀阀前压力[BarA]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.TxvFrPress, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "膨胀阀前温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.TxvFrTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "EVAP出口压力[BarA]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.EVAPExpPress, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "腔内压力[BarA]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.IntrplPress, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "压缩机表面温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.CapSurfTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "PTC流量[L/min]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.PTCFlow, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "PTC入水温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.PTCEntTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "PTC出水温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.PTCExpTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "AT04_01[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.AT04_01Temp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "AT04_02[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.AT04_02Temp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "通讯Cmp母线电流[A]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.ComCapBusCur, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "通讯Cmp母线电压[V]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.ComCapBusVol, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "通讯Cmp逆变器温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.ComCapInvTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "通讯Cmp相电流[A]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.ComCapPhCur, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "通讯Cmp功率[W]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.ComCapPw, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "通讯Cmp芯片温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.ComCapChipTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "通讯PTC入水温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.ComPTCEntTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "通讯PTC出水温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.ComPTCExpTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "通讯PTC峰值电流[A]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.ComPTCPeakCur, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "通讯PTC母线电流[A]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.ComPTCBusCur, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "通讯PTC膜温[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.ComPTCFlmTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "通讯PTC模块温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.ComPTCMdTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
default:
return CurHistoryData.Select(a => new ChartPoint() { Value = a.Speed, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
break;
}
}
#endregion
/// <summary>
/// 更新Y轴的信息最大值和最小值
/// </summary>
private void UpdateChartAxisY(List<ConfigChartYAxis> configChartYAxes)
{
LgChart.BeginUpdate();
//只更改最大值和最小值 如果改动名称需要从Id入手
foreach (var item in LgChart.ViewXY.YAxes)
{
var FindData = configChartYAxes.Find(a => a.Name == item.Title.Text);
if (FindData != null)
{
item.Minimum = FindData.Min;
item.Maximum = FindData.Max;
}
}
LgChart.EndUpdate();
}
/// <summary>
/// 切换Tab是不是当前的Tab信息
/// </summary>
/// <param name="msg"></param>
private void ChartTabGroupSwitchCall(ChartTabGroupSwitchMsg msg)
{
if (msg.Machine != CurSelectedMachine)
{
//选择了其他的机械的话,则也是没有被激活
IsActivated = false;
return;
}
//当前的系列
if (msg.GroupTabIndex == CurSelectedGroupTabIndex)
{
IsActivated = true;
}
else
{
IsActivated = false;
}
}
/// <summary>
/// 事件聚合器
/// </summary>
private IEventAggregator _EventAggregator { get; set; }
public TagManager TagManager { get; }
private DataRecordService DatRecordService { get; set; }
public IFreeSql FreeSql { get; }
/// <summary>
/// 当前的Chart所属的TabIndex
/// </summary>
private int CurSelectedGroupTabIndex { get; set; }
/// <summary>
/// 当前选中的Machine
/// </summary>
private string CurSelectedMachine { get; set; }
/// <summary>
/// 当前曲线是否被激活
/// 当前被查看的Chart控件
/// </summary>
private bool IsActivated { get; set; } = false;
/// <summary>
/// 初始化Ok了吗
/// </summary>
private bool IsInitOk { get; set; } = false;
/// <summary>
/// 是否为实时曲线
/// 默认为实时曲线
/// 否则为历史数据曲线
/// </summary>
private bool IsRealTimeChart { get; set; } = true;
public ILogService LogService { get; }
public ConfigService ConfigService { get; }
/// <summary>
/// Chart曲线的实例
/// </summary>
public LightningChart LgChart { get; set; }
/// <summary>
/// 是否为双游标
/// </summary>
private bool IsDoubleCurson { get; set; } = false;
/// <summary>
/// 曲线名称
/// </summary>
public string ChartName { get; set; }
private ObservableCollection<ChartRtSeries> _ListChartRtSeries;
/// <summary>
/// 曲线数据系列集合
/// </summary>
public ObservableCollection<ChartRtSeries> ListChartRtSeries
{
get { return _ListChartRtSeries; }
set { _ListChartRtSeries = value; RaisePropertyChanged(); }
}
///// <summary>
///// 曲线数据系列集合
///// </summary>
//public List<ChartRtSeries> ListChartRtSeries { get; set; }
/// <summary>
/// Chart显示哪些参数配置 业务相关
/// </summary>
public List<ConfigChart> ListConfigChart { get; set; }
/// <summary>
/// 曲线配置
/// </summary>
public ChartColor ChartColorInfo { get; set; } = new ChartColor();
///// <summary>
///// Chart图表X轴的跨度-秒
///// </summary>
//public int ChartXDateTimeRange { get; set; } = 3600_8;
/// <summary>
/// X轴滚动
/// </summary>
public bool IsScrollEnable { get; set; } = true;
/// <summary>
/// 隐藏图例
/// </summary>
public bool IsLegendHide { get; set; } = false;
/// <summary>
/// 是否删除之前的数据
/// </summary>
public bool IsDeleteBefore { get; set; } = true;
/// <summary>
/// X轴
/// </summary>
public AxisX? ChartAxisX { get; set; }
/// <summary>
/// 第一个光标
/// 单双光标时使用
/// </summary>
public LineSeriesCursor FirstLineSeriesCursor { get; set; }
/// <summary>
/// 第一个光标的X轴时间
/// </summary>
public DateTime FirstCursorDatetime { get; set; }
/// <summary>
/// 第二个光标
/// 双光标时使用
/// </summary>
public LineSeriesCursor SecondLineSeriesCursor { get; set; }
/// <summary>
/// 第二个光标的X轴时间
/// </summary>
public DateTime SecondCursorDatetime { get; set; }
/// <summary>
/// Annotations 注释
/// </summary>
public AnnotationXY CursorValueDisplay { get; set; }
/// <summary>
/// 当前的图例
/// </summary>
public LegendBoxXY LegendBox { get; set; }
/// <summary>
/// 卡尺 注释 没有使用
/// </summary>
public AnnotationXY Caliper { get; set; }
/// <summary>
/// Chart初始化
/// </summary>
public void InitChart()
{
//Disable rendering, strongly recommended before updating chart properties
LgChart.BeginUpdate();
//性能设置
//Sync default: 图表同步更新。图表在最后一次 EndUpdate调用后更新或者
// 当设置属性(或调用一个 method会改变图表时更新。属性的改变没有
// BeginUpdate…EndUpdate会引发即时渲染新帧。
//Async: 图表以异步方式更新。图表在属性改变后将尽快更新,但是图表将在随后的某
//个的点渲染一个新帧。这也许让图表在某些情况下更方便使用。
//LimitedFrameRate: 帧率受限于在 FrameRateLimit 属性中规定的值。0 = 无限制。例
//如如果想要最大每秒刷新10次则设置值为10。这与Async选项类似但会防止在
//第一个帧之后立即渲染新的帧,如此以来,减少帧率,但节省了系统资源。
//注意! 确保在LimitedFrameRate和 Async模式下正确的线程处理。如果异步更新图表
//并且图表属性也同时更新,可能会引发冲突,导致图表或应用程序奔溃。
LgChart.ChartRenderOptions.UpdateType = ChartUpdateTypes.Async;
LgChart.ChartRenderOptions.FrameRateLimit = 0;
//Reduce memory usage and increase performance. Destroys out-scrolled data.
LgChart.ViewXY.DropOldSeriesData = false;
//多个Y曲线摆放形式
LgChart.ViewXY.AxisLayout.YAxesLayout = YAxesLayout.Layered;
//网格带
LgChart.ViewXY.AxisLayout.AxisGridStrips = XYAxisGridStrips.X;
//y轴的在左边还是右边
LgChart.ViewXY.AxisLayout.YAxisAutoPlacement = YAxisAutoPlacement.AllLeft;
//LgChart.Parent = this.panel1;
//LgChart.Name = "Temperature measurement _chart";
LgChart.Title.Text = "";
//LgChart.ViewXY.
//LgChart.Dock = DockStyle.Fill;
//清除Y轴系列
LgChart.ViewXY.YAxes.Clear();
var InitAxisY = new AxisY(LgChart.ViewXY);
InitAxisY.Visible = false;
InitAxisY.ZoomingEnabled = false;
LgChart.ViewXY.YAxes.Add(InitAxisY);
//Configure x-axis
AxisX xAxis = LgChart.ViewXY.XAxes[0];
xAxis.ValueType = AxisValueType.DateTime;
xAxis.Title.Text = "时间";
xAxis.AutoFormatLabels = true;
xAxis.LabelsTimeFormat = "MM/dd \n HH:mm.ss";
//xAxis.LabelsTimeFormat = "dd/MM/yyyy\nHH:mm.ss";
xAxis.LabelsAngle = 45;
//xAxis.SteppingInterval = 0.1;
//xAxis.ScrollingGap = 15;
ChartAxisX = xAxis;
//xAxis.AllowScaling = true;
xAxis.ScrollMode = XAxisScrollMode.Scrolling;
xAxis.ZoomingEnabled = true;
//Convert DateTime values to axis values
DateTime now = DateTime.Now;
double minX = xAxis.DateTimeToAxisValue(now);
double maxX = xAxis.DateTimeToAxisValue(now.AddMinutes(60));
xAxis.SetRange(minX, maxX);
//DateTime now = DateTime.Now;
//xAxis.SetDateTimeRange(now,now.AddMinutes(60));
//Add an annotation to show the cursor values
//AnnotationXY cursorValueDisplay = new AnnotationXY();
//光标注释数据
CursorValueDisplay = new AnnotationXY(LgChart.ViewXY, LgChart.ViewXY.XAxes[0], LgChart.ViewXY.YAxes[0]);
//显示光标数据的内容的载体
CursorValueDisplay.Text = "";
CursorValueDisplay.Style = AnnotationStyle.Rectangle;//注释是矩形框显示
CursorValueDisplay.LocationCoordinateSystem = CoordinateSystem.ScreenCoordinates;//屏幕的位置
//CursorValueDisplay.LocationRelativeOffset.X = 130;
//CursorValueDisplay.LocationRelativeOffset.Y = -100;
//光标注释相对的位置 右上侧
//CursorValueDisplay.LocationScreenCoords.Y = 45;
//CursorValueDisplay.LocationScreenCoords.X = 1480;
//光标注释相对的位置 左上侧
CursorValueDisplay.LocationScreenCoords.Y = 35;
CursorValueDisplay.LocationScreenCoords.X = 1380;
//CursorValueDisplay.TargetAxisValues.X = 0;
//CursorValueDisplay.TargetAxisValues.Y = 0;
CursorValueDisplay.Sizing = AnnotationXYSizing.Automatic;
//cursorValueDisplay.TextStyle.Font = new WpfFont("Lucida console", 10f, FontStyle.Regular);
CursorValueDisplay.TextStyle.Color = System.Windows.Media.Color.FromRgb(102, 255, 51);
CursorValueDisplay.Fill.Style = RectFillStyle.ColorOnly;
CursorValueDisplay.Fill.Color = System.Windows.Media.Color.FromArgb(150, 48, 48, 48);//带透明度
CursorValueDisplay.Fill.GradientColor = System.Windows.Media.Color.FromRgb(48, 48, 48);//渐变色
CursorValueDisplay.BorderVisible = false;
CursorValueDisplay.AllowTargetMove = false;
CursorValueDisplay.AllowDragging = false;//是否允许拖动
CursorValueDisplay.AllowResize = false;//是否允许用户改变大小
CursorValueDisplay.Visible = false;
LgChart.ViewXY.Annotations.Add(CursorValueDisplay);
//第一个光标 cursor
FirstLineSeriesCursor = new LineSeriesCursor(LgChart.ViewXY, LgChart.ViewXY.XAxes[0]);
LgChart.ViewXY.LineSeriesCursors.Add(FirstLineSeriesCursor);
FirstLineSeriesCursor.PositionChanged += FirstCursor_PositionChanged;
FirstLineSeriesCursor.ValueAtXAxis = LgChart.ViewXY.XAxes[0].DateTimeToAxisValue(DateTime.Now.AddMinutes(30));
FirstLineSeriesCursor.LineStyle.Color = System.Windows.Media.Color.FromRgb(100, 200, 200);
FirstLineSeriesCursor.SnapToPoints = false;
FirstLineSeriesCursor.TrackPoint.Color1 = System.Windows.Media.Color.FromRgb(255, 255, 255);
FirstLineSeriesCursor.Style = CursorStyle.PointTracking;
//第二个光标 cursor
SecondLineSeriesCursor = new LineSeriesCursor(LgChart.ViewXY, LgChart.ViewXY.XAxes[0]);
LgChart.ViewXY.LineSeriesCursors.Add(SecondLineSeriesCursor);
SecondLineSeriesCursor.PositionChanged += SecondCursor_PositionChanged;
SecondLineSeriesCursor.ValueAtXAxis = LgChart.ViewXY.XAxes[0].DateTimeToAxisValue(DateTime.Now.AddMinutes(30));
SecondLineSeriesCursor.LineStyle.Color = System.Windows.Media.Color.FromRgb(0, 191, 255);
SecondLineSeriesCursor.SnapToPoints = false;
SecondLineSeriesCursor.TrackPoint.Color1 = System.Windows.Media.Color.FromRgb(255, 255, 255);
SecondLineSeriesCursor.Style = CursorStyle.PointTracking;
SecondLineSeriesCursor.Visible = false;
//两个光标的卡纸信息
//Caliper = new AnnotationXY(LgChart.ViewXY, LgChart.ViewXY.XAxes[0], LgChart.ViewXY.YAxes[0]);
//Caliper.Style = AnnotationStyle.Arrow;
//Caliper.ArrowStyleBegin = ArrowStyle.Caliper;
//Caliper.ArrowStyleEnd = ArrowStyle.Caliper;
//Caliper.ArrowLineStyle.Width = 5;
//Caliper.ArrowLineStyle.Pattern = LinePattern.Dash;
//Caliper.LocationCoordinateSystem = CoordinateSystem.AxisValues;
//Caliper.TargetCoordinateSystem = AnnotationTargetCoordinates.AxisValues;
////double dCaliperY = yAxisTemperature.Maximum - (yAxisTemperature.Maximum - yAxisTemperature.Minimum) * 0.10;
//double dCaliperY = 0.1;
//Caliper.LocationAxisValues.SetValues(FirstLineSeriesCursor.ValueAtXAxis, dCaliperY);
//Caliper.TargetAxisValues.SetValues(SecondLineSeriesCursor.ValueAtXAxis, dCaliperY);
//Caliper.TextStyle.Visible = false;
//LgChart.ViewXY.Annotations.Add(Caliper);
LgChart.Loaded += LgChart_Loaded;
LgChart.SizeChanged += LgChart_SizeChanged;
//LgChart.Resize += new EventHandler(_chart_Resize);
////清除Y轴系列
//LgChart.ViewXY.YAxes.Clear();
//图例框
LgChart.ViewXY.LegendBoxes[0].Visible = true;
LgChart.ViewXY.LegendBoxes[0].Position = LegendBoxPositionXY.TopRight;
//LgChart.ViewXY.AutoSpaceLegendBoxes = true;
LgChart.ViewXY.LegendBoxes[0].Layout = LegendBoxLayout.Vertical;//排列方式
LgChart.ViewXY.LegendBoxes[0].AllowDragging = false;
LgChart.ViewXY.LegendBoxes[0].Offset = new PointIntXY(0, 16);
LgChart.ViewXY.LegendBoxes[0].CheckBoxSize = 14;
LgChart.ViewXY.LegendBoxes[0].ValueLabelFont = new WpfFont(16);
LgChart.ViewXY.LegendBoxes[0].Fill.Color = System.Windows.Media.Color.FromArgb(0, 180, 180, 180); ;//带透明度
LegendBox = LgChart.ViewXY.LegendBoxes[0];
//Allow chart rendering
LgChart.EndUpdate();
IsInitOk = true;
}
/// <summary>
/// 获取订阅的的数据
/// 确保和数据记录的数据是一致的,并且是同一个时刻
/// </summary>
/// <param name="data"></param>
/// <exception cref="NotImplementedException"></exception>
private void UpdateRecordData(RecordChannelData data)
{
if (data.Data != null)
{
foreach (var item in data.Data)
{
//var FindData= ListChartRtSeries.Where(a=>a.Name==item.Key);
//判断是否存在
//if (ListChartRtSeries.Exists(a => a.Name == item.Key))
if (ListChartRtSeries.Where(a => a.Name == item.Key).Any())
{
var Data = ListChartRtSeries.FindFirst(a => a.Name == item.Key);
Data.Value = Convert.ToDouble(item.Value);
Data.AddPointByCache(data.CreateTime, Data.Value, IsDeleteBefore, IsScrollEnable);
}
//ListConfigChart
}
}
}
/// <summary>
/// 曲线个数
/// </summary>
private int ChartSeriesCount { get; set; } = 0;
/// <summary>
/// 更新图表信息
/// </summary>
public void UpdateChartData()
{
//timeStamp = timeStamp.AddSeconds(-60);
foreach (var item in LgChart.ViewXY.PointLineSeries)
{
//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.Now);
points[0].X = _previousX;
points[0].Y = GetChartRtValue(item.Title.Text);
//Add the new point into end of first PointLineSeries
item.AddPoints(points, false);
item.DeletePointsBeforeX(_previousX - ConfigService.ChartRtDataCacheTimeSec);
//item.DeletePointsBeforeX(_previousX - 100);
if (IsScrollEnable)
{
LgChart.ViewXY.XAxes[0].ScrollPosition = _previousX;
}
//Allow updates again, and update
LgChart.EndUpdate();
}
}
/// <summary>
/// 根据名称获取曲线所需的数据
/// </summary>
private double GetChartRtValue(string Name)
{
try
{
//var Data = ListChartRtValue.Find(a => a.Name == Name);
//if (Data != null)
//{
// return Data.Value;
//}
return 0;
}
catch (Exception ex)
{
//logger.Error(String.Format("ErrSource : {0} ErrMsg : {1}", ex.StackTrace.ToString(), ex.Message.ToString()));
return 0;
}
finally
{
}
}
private void LgChart_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e)
{
//UpdateCursorResult();
}
private void LgChart_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
//UpdateCursorResult();
}
/// <summary>
/// 第一个光标位置变化
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void FirstCursor_PositionChanged(object sender, PositionChangedEventArgs e)
{
e.CancelRendering = true;
if (!IsInitOk) return;
FirstUpdateCursorResult(sender);
}
/// <summary>
/// 光标位置变化
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SecondCursor_PositionChanged(object sender, PositionChangedEventArgs e)
{
e.CancelRendering = true;
if (!IsInitOk) return;
SecondUpdateCursorResult(sender);
}
/// <summary>
/// Update cursor texts.
/// 更新光标的注释信息
/// 使用AnnotationXY进行展示已经舍弃
/// </summary>
private void UpdateCursorResult()
{
bool showNextToCursor = true;
//Disable rendering, strongly recommended before updating chart properties
LgChart.BeginUpdate();
//Get cursor 光标
LineSeriesCursor cursor = LgChart.ViewXY.LineSeriesCursors[0];
//Get annotation 注释
AnnotationXY cursorValueDisplay = LgChart.ViewXY.Annotations[0];
//Set annotation target. The location is relative to target.
//Use graph bottom as target Y value.
float targetYCoord = (float)LgChart.ViewXY.GetMarginsRect().Bottom;
double y;
LgChart.ViewXY.YAxes[0].CoordToValue(targetYCoord, out y);
//设置注释的位置
//cursorValueDisplay.TargetAxisValues.X = cursor.ValueAtXAxis;
//cursorValueDisplay.TargetAxisValues.Y = y;
cursorValueDisplay.TargetAxisValues.X = 0;
cursorValueDisplay.TargetAxisValues.Y = 0;
double seriesYValue = 0;
StringBuilder sb = new StringBuilder();
int seriesIndex = 1;
//string channelStringFormat = "Mill {0}: {1,12:#####.###} {2}";
string channelStringFormat = "{0}: {1}";
bool labelVisible = false;
bool accurateValue = false;
string value = "";
foreach (PointLineSeries pointLineSeries in LgChart.ViewXY.PointLineSeries)
{
//show series titles and cursor values in them, on the right side of the chart,
//if cursor values are not shown next to the cursor in an annotation
pointLineSeries.Title.Visible = !showNextToCursor;
//pointLineSeries.Title.Visible = true;
bool resolved = false;
value = "";
if (accurateValue)
resolved = SolveValueAccurate(pointLineSeries, cursor.ValueAtXAxis, out seriesYValue);
else
resolved = SolveValueCoarse(pointLineSeries, cursor.ValueAtXAxis, out seriesYValue);
AxisY axisY = LgChart.ViewXY.YAxes[pointLineSeries.AssignYAxisIndex];
if (resolved)
{
labelVisible = true;
//value = string.Format(channelStringFormat, seriesIndex, seriesYValue.ToString("0.000"), axisY.Units.Text);
value = string.Format(channelStringFormat, pointLineSeries.Title.Text, seriesYValue.ToString("0.000"));
}
else
{
//value = string.Format(channelStringFormat, seriesIndex, "---", axisY.Units.Text);
value = string.Format(channelStringFormat, pointLineSeries.Title.Text, "---");
}
sb.AppendLine(value);
//这个会改变曲线标题的名称,影响曲线的定位、删除等操作
//pointLineSeries.Title.Text = value;
seriesIndex++;
}
//sb.AppendLine("");
//sb.AppendLine("时间: " + LgChart.ViewXY.XAxes[0].TimeString(cursor.ValueAtXAxis, "HH:mm:ss.ffff"));
////Set text
cursorValueDisplay.Text = sb.ToString();
////Show the label only if it selected to be shown 是否显示
cursorValueDisplay.Visible = labelVisible && showNextToCursor;
//cursorValueDisplay.Visible = true;
//Allow chart rendering
LgChart.EndUpdate();
}
/// <summary>
/// Update cursor texts.
/// 更新到ListView中
/// </summary>
private void UpdateCursorResultToLv(object sender)
{
bool showNextToCursor = true;
//拖动的Cursor
LineSeriesCursor DraggedCursor = (LineSeriesCursor)sender;
//Disable rendering, strongly recommended before updating chart properties
LgChart.BeginUpdate();
// 判断这个拖动的Cursor是左侧的还是右侧的,防止左侧的越过右侧
if (DraggedCursor == FirstLineSeriesCursor)
{
if (DraggedCursor.ValueAtXAxis > SecondLineSeriesCursor.ValueAtXAxis - 1)
{
DraggedCursor.ValueAtXAxis = SecondLineSeriesCursor.ValueAtXAxis - 1;
}
}
else if (DraggedCursor == SecondLineSeriesCursor)
{
if (DraggedCursor.ValueAtXAxis < FirstLineSeriesCursor.ValueAtXAxis + 1)
{
DraggedCursor.ValueAtXAxis = FirstLineSeriesCursor.ValueAtXAxis + 1;
}
}
//Get cursor 光标
LineSeriesCursor cursor = LgChart.ViewXY.LineSeriesCursors[0];
//Get annotation 注释
AnnotationXY cursorValueDisplay = LgChart.ViewXY.Annotations[0];
//Set annotation target. The location is relative to target.
//Use graph bottom as target Y value.
float targetYCoord = (float)LgChart.ViewXY.GetMarginsRect().Bottom;
double y;
LgChart.ViewXY.YAxes[0].CoordToValue(targetYCoord, out y);
//设置注释的位置
//cursorValueDisplay.TargetAxisValues.X = cursor.ValueAtXAxis;
//cursorValueDisplay.TargetAxisValues.Y = y;
cursorValueDisplay.TargetAxisValues.X = 0;
cursorValueDisplay.TargetAxisValues.Y = 0;
//Y轴的值
double seriesYValue = 0;
StringBuilder sb = new StringBuilder();
int seriesIndex = 1;
//string channelStringFormat = "Mill {0}: {1,12:#####.###} {2}";
string channelStringFormat = "{0}: {1}";
bool labelVisible = false;
bool accurateValue = false;
string value = "";
foreach (ChartRtSeries chartRtSeries in ListChartRtSeries)
{
//show series titles and cursor values in them, on the right side of the chart,
//if cursor values are not shown next to the cursor in an annotation
chartRtSeries.ChartPointLineSeries!.Title.Visible = !showNextToCursor;
//pointLineSeries.Title.Visible = true;
bool resolved = false;
value = "";
if (accurateValue)
resolved = SolveValueAccurate(chartRtSeries.ChartPointLineSeries!, cursor.ValueAtXAxis, out seriesYValue);
else
resolved = SolveValueCoarse(chartRtSeries.ChartPointLineSeries!, cursor.ValueAtXAxis, out seriesYValue);
AxisY axisY = LgChart.ViewXY.YAxes[chartRtSeries.ChartPointLineSeries!.AssignYAxisIndex];
//已经计算出值了
chartRtSeries.LeftCursorValue = seriesYValue;
if (resolved)
{
labelVisible = true;
//value = string.Format(channelStringFormat, seriesIndex, seriesYValue.ToString("0.000"), axisY.Units.Text);
value = string.Format(channelStringFormat, chartRtSeries.ChartPointLineSeries!.Title.Text, seriesYValue.ToString("0.000"));
}
else
{
//value = string.Format(channelStringFormat, seriesIndex, "---", axisY.Units.Text);
value = string.Format(channelStringFormat, chartRtSeries.ChartPointLineSeries!.Title.Text, "---");
}
sb.AppendLine(value);
//这个会改变曲线标题的名称,影响曲线的定位、删除等操作
//pointLineSeries.Title.Text = value;
seriesIndex++;
}
//sb.AppendLine("");
//sb.AppendLine("时间: " + LgChart.ViewXY.XAxes[0].TimeString(cursor.ValueAtXAxis, "HH:mm:ss.ffff"));
////Set text
cursorValueDisplay.Text = sb.ToString();
////Show the label only if it selected to be shown 是否显示
cursorValueDisplay.Visible = labelVisible && showNextToCursor;
//cursorValueDisplay.Visible = true;
//Allow chart rendering
LgChart.EndUpdate();
}
/// <summary>
/// Update cursor texts.
/// 第一个游标更新位置,更新结果
/// </summary>
private void FirstUpdateCursorResult(object sender)
{
bool showNextToCursor = true;
//拖动的Cursor
LineSeriesCursor DraggedCursor = (LineSeriesCursor)sender;
//Disable rendering, strongly recommended before updating chart properties
LgChart.BeginUpdate();
//左侧的游标,在双游标时才会被限制,单游标时不做处理
if (IsDoubleCurson)
{
// 判断这个拖动的Cursor是左侧的还是右侧的,防止左侧的越过右侧
if (DraggedCursor == FirstLineSeriesCursor)
{
if (DraggedCursor.ValueAtXAxis > SecondLineSeriesCursor.ValueAtXAxis - 1)
{
DraggedCursor.ValueAtXAxis = SecondLineSeriesCursor.ValueAtXAxis - 1;
}
}
else if (DraggedCursor == SecondLineSeriesCursor)
{
if (DraggedCursor.ValueAtXAxis < FirstLineSeriesCursor.ValueAtXAxis + 1)
{
DraggedCursor.ValueAtXAxis = FirstLineSeriesCursor.ValueAtXAxis + 1;
}
}
}
//设置注释的位置
//cursorValueDisplay.TargetAxisValues.X = cursor.ValueAtXAxis;
//cursorValueDisplay.TargetAxisValues.Y = y;
CursorValueDisplay.TargetAxisValues.X = 0;
CursorValueDisplay.TargetAxisValues.Y = 0;
//Y轴的值
double seriesYValue = 0;
StringBuilder Strb = new StringBuilder();
string channelStringFormat = "{0}: {1}";
//算法的选择
bool accurateValue = false;
string value = "";
FirstCursorDatetime = ChartAxisX!.AxisValueToDateTime(FirstLineSeriesCursor.ValueAtXAxis);
foreach (ChartRtSeries chartRtSeries in ListChartRtSeries)
{
//show series titles and cursor values in them, on the right side of the chart,
//if cursor values are not shown next to the cursor in an annotation
//chartRtSeries.ChartPointLineSeries!.Title.Visible = !showNextToCursor;
//pointLineSeries.Title.Visible = true;
bool resolved = false;
value = "";
if (accurateValue)
resolved = SolveValueAccurate(chartRtSeries.ChartPointLineSeries!, FirstLineSeriesCursor.ValueAtXAxis, out seriesYValue);
else
resolved = SolveValueCoarse(chartRtSeries.ChartPointLineSeries!, FirstLineSeriesCursor.ValueAtXAxis, out seriesYValue);
//已经计算出值了
chartRtSeries.LeftCursorValue = seriesYValue;
//双游标需要统计数据
if (IsDoubleCurson)
{
if (IsRealTimeChart)
{
var StatisValue = CalcStatis(chartRtSeries.Name);
chartRtSeries.MaxValue = StatisValue.Max;
chartRtSeries.MinValue = StatisValue.Min;
chartRtSeries.AveValue = StatisValue.Ave;
}
else
{
var StatisValue = CalcHistoryStatis(chartRtSeries.Name);
chartRtSeries.MaxValue = StatisValue.Max;
chartRtSeries.MinValue = StatisValue.Min;
chartRtSeries.AveValue = StatisValue.Ave;
}
}
//不需要光标位置处的数据
//if (resolved)
//{
// value = string.Format(channelStringFormat, chartRtSeries.ChartPointLineSeries!.Title.Text, seriesYValue.ToString("0.000"));
//}
//else
//{
// value = string.Format(channelStringFormat, chartRtSeries.ChartPointLineSeries!.Title.Text, "---");
//}
//Strb.AppendLine(value);
}
//sb.AppendLine("");
//sb.AppendLine("时间: " + LgChart.ViewXY.XAxes[0].TimeString(cursor.ValueAtXAxis, "HH:mm:ss.ffff"));
////Set text
//CursorValueDisplay.Text = Strb.ToString();
CursorValueDisplay.Text = $"左光标:{FirstCursorDatetime.ToString("MM-dd HH:mm:ss")}";
////Show the label only if it selected to be shown 是否显示
CursorValueDisplay.Visible = true;
//Allow chart rendering
LgChart.EndUpdate();
}
/// <summary>
/// Update cursor texts.
/// 第二个游标更新位置,更新结果
/// </summary>
private void SecondUpdateCursorResult(object sender)
{
bool showNextToCursor = true;
//拖动的Cursor
LineSeriesCursor DraggedCursor = (LineSeriesCursor)sender;
//Disable rendering, strongly recommended before updating chart properties
LgChart.BeginUpdate();
// 判断这个拖动的Cursor是左侧的还是右侧的,防止左侧的越过右侧
if (DraggedCursor == FirstLineSeriesCursor)
{
if (DraggedCursor.ValueAtXAxis > SecondLineSeriesCursor.ValueAtXAxis - 1)
{
DraggedCursor.ValueAtXAxis = SecondLineSeriesCursor.ValueAtXAxis - 1;
}
}
else if (DraggedCursor == SecondLineSeriesCursor)
{
if (DraggedCursor.ValueAtXAxis < FirstLineSeriesCursor.ValueAtXAxis + 1)
{
DraggedCursor.ValueAtXAxis = FirstLineSeriesCursor.ValueAtXAxis + 1;
}
}
//设置注释的位置
//cursorValueDisplay.TargetAxisValues.X = cursor.ValueAtXAxis;
//cursorValueDisplay.TargetAxisValues.Y = y;
CursorValueDisplay.TargetAxisValues.X = 0;
CursorValueDisplay.TargetAxisValues.Y = 0;
//Y轴的值
double seriesYValue = 0;
StringBuilder Strb = new StringBuilder();
string channelStringFormat = "{0}: {1}";
//算法的选择
bool accurateValue = false;
string value = "";
SecondCursorDatetime = ChartAxisX!.AxisValueToDateTime(SecondLineSeriesCursor.ValueAtXAxis);
foreach (ChartRtSeries chartRtSeries in ListChartRtSeries)
{
//show series titles and cursor values in them, on the right side of the chart,
//if cursor values are not shown next to the cursor in an annotation
//chartRtSeries.ChartPointLineSeries!.Title.Visible = !showNextToCursor;
//pointLineSeries.Title.Visible = true;
bool resolved = false;
value = "";
if (accurateValue)
resolved = SolveValueAccurate(chartRtSeries.ChartPointLineSeries!, SecondLineSeriesCursor.ValueAtXAxis, out seriesYValue);
else
resolved = SolveValueCoarse(chartRtSeries.ChartPointLineSeries!, SecondLineSeriesCursor.ValueAtXAxis, out seriesYValue);
//已经计算出值
chartRtSeries.RightCursorValue = seriesYValue;
//双游标需要统计数据
if (IsDoubleCurson)
{
if (IsRealTimeChart)
{
var StatisValue = CalcStatis(chartRtSeries.Name);
chartRtSeries.MaxValue = StatisValue.Max;
chartRtSeries.MinValue = StatisValue.Min;
chartRtSeries.AveValue = StatisValue.Ave;
}
else
{
var StatisValue = CalcHistoryStatis(chartRtSeries.Name);
chartRtSeries.MaxValue = StatisValue.Max;
chartRtSeries.MinValue = StatisValue.Min;
chartRtSeries.AveValue = StatisValue.Ave;
}
}
//不需要光标位置处的数据
//if (resolved)
//{
//value = string.Format(channelStringFormat, chartRtSeries.ChartPointLineSeries!.Title.Text, seriesYValue.ToString("0.000"));
//}
//else
//{
// value = string.Format(channelStringFormat, chartRtSeries.ChartPointLineSeries!.Title.Text, "---");
//}
//Strb.AppendLine(value);
}
//sb.AppendLine("");
//sb.AppendLine("时间: " + LgChart.ViewXY.XAxes[0].TimeString(cursor.ValueAtXAxis, "HH:mm:ss.ffff"));
////Set text
//CursorValueDisplay.Text = Strb.ToString();
CursorValueDisplay.Text = $"右光标:{SecondCursorDatetime.ToString("MM-dd HH:mm:ss")}";
////Show the label only if it selected to be shown 是否显示
CursorValueDisplay.Visible = true;
//Allow chart rendering
LgChart.EndUpdate();
}
/// <summary>
/// 计算数据
/// </summary>
/// <returns></returns>
private (double Max, double Min, double Ave) CalcStatis(string Name)
{
if (FirstCursorDatetime < SecondCursorDatetime)
{
var datas = DatRecordService.CacheRecordData
.Where(a => a.CreateTime >= FirstCursorDatetime && a.CreateTime <= SecondCursorDatetime)
.Where(a => a.Data != null && a.Data.ContainsKey(Name))
.Select(a => Convert.ToDouble(a.Data[Name]))
.ToList();
if (!datas.Any())
{
return (0, 0, 0); // 返回默认值
}
return (datas.Max(), datas.Min(), datas.Average());
}
return (0, 0, 0); // 返回默认值
}
/// <summary>
/// 计算历史数据
/// 历史曲线
/// </summary>
/// <returns></returns>
private (double Max, double Min, double Ave) CalcHistoryStatis(string Name)
{
if (FirstCursorDatetime < SecondCursorDatetime)
{
////第一次计时
stopwatch.Start(); //启动Stopwatch
if (CurHistoryData == null || CurHistoryData.Count == 0)
{
return (0, 0, 0); // 返回默认值
}
var TimeRangeData = CurHistoryData
.Where(a => a.CreateTime >= FirstCursorDatetime && a.CreateTime <= SecondCursorDatetime)
.ToList();
if (!TimeRangeData.Any())
{
return (0, 0, 0); // 返回默认值
}
var Data = GetChartPointByName(Name, TimeRangeData);
stopwatch.Stop(); //停止Stopwatch
Console.WriteLine("历史数据统计耗时::{0}--{1}", stopwatch.Elapsed.TotalSeconds.ToString(), CurSelectedGroupTabIndex.ToString());
stopwatch.Reset();
return (Data.Max(a => a.Value), Data.Min(a => a.Value), Data.Average(a => a.Value));
}
return (0, 0, 0); // 返回默认值
}
/// <summary>
/// Solve value from series data points array. Accurate method, but slower than SolveValueCoarse
/// </summary>
/// <param name="series">Series</param>
/// <param name="xValue">X value</param>
/// <param name="yValue">Output Y value</param>
/// <returns>Success status</returns>
private bool SolveValueAccurate(PointLineSeries series, double xValue, out double yValue)
{
AxisY axisY = LgChart.ViewXY.YAxes[series.AssignYAxisIndex];
yValue = 0;
LineSeriesValueSolveResult result = series.SolveYValueAtXValue(xValue);
if (result.SolveStatus == LineSeriesSolveStatus.OK)
{
//PointLineSeries may have two or more points at same X value. If so, center it between min and max
yValue = (result.YMax + result.YMin) / 2.0;
return true;
}
else
{
return false;
}
}
/// <summary>
/// Solve value from screen coordinates. Faster method, but not less accurateValue than SolveValueAccurate
/// </summary>
/// <param name="series">Series</param>
/// <param name="xValue">X value</param>
/// <param name="yValue">Output Y value</param>
/// <returns>Success status</returns>
private bool SolveValueCoarse(PointLineSeries series, double xValue, out double yValue)
{
AxisY axisY = LgChart.ViewXY.YAxes[series.AssignYAxisIndex];
float coordX = LgChart.ViewXY.XAxes[0].ValueToCoord(xValue);
float coordY;
yValue = 0;
LineSeriesCoordinateSolveResult result = series.SolveYCoordAtXCoord(coordX);
if (result.SolveStatus == LineSeriesSolveStatus.OK)
{
coordY = (result.CoordBottom + result.CoordTop) / 2f;
if (axisY.CoordToValue((int)Math.Round(coordY), out yValue) == false)
{
return false;
}
}
else
{
return false;
}
return true;
}
/// <summary>
/// 增加Y轴
/// </summary>
/// <param name="Name"></param>
/// <param name="MaxVal"></param>
/// <param name="MinVal"></param>
private void AddYAxis(string Name, double MinVal, double MaxVal)
{
LgChart.BeginUpdate();
var CreateAxisY = new AxisY();
CreateAxisY.Title.Text = Name;
CreateAxisY.Title.AllowDragging = false;
CreateAxisY.SetRange(MinVal, MaxVal);
CreateAxisY.MajorGrid.Visible = false;
//取消滚轮缩放
CreateAxisY.ZoomingEnabled = false;
LgChart.ViewXY.YAxes.Add(CreateAxisY);
//Configure and add series to the chart
PointLineSeries CreateSeries = new PointLineSeries(LgChart.ViewXY, LgChart.ViewXY.XAxes[0], CreateAxisY);
CreateSeries.Title.Text = Name;
CreateSeries.LineStyle.Color = ChartColorInfo.ListColor[LgChart.ViewXY.YAxes.Count + 1];
CreateSeries.AllowUserInteraction = false;
LgChart.ViewXY.PointLineSeries.Add(CreateSeries);
LgChart.EndUpdate();
ChartSeriesCount++;
}
private void DeleteYAxis(string TitleName)
{
LgChart.BeginUpdate();
for (int i = 0; i < LgChart.ViewXY.YAxes.Count; i++)
{
if (LgChart.ViewXY.YAxes[i].Title.Text == TitleName)
{
LgChart.ViewXY.YAxes.RemoveAt(i);
break;
}
}
LgChart.EndUpdate();
if (ChartSeriesCount <= 0)
{
ChartSeriesCount = 0;
}
else
{
ChartSeriesCount--;
}
}
/// <summary>
/// 删除系列
/// </summary>
public void DeleteSeries(string SeriesName)
{
LgChart.BeginUpdate();
//LgChart.ViewXY.PointLineSeries.Remove(ChartPointLineSeries);
for (int i = 0; i < LgChart.ViewXY.PointLineSeries.Count; i++)
{
if (LgChart.ViewXY.PointLineSeries[i].Title.Text == SeriesName)
{
LgChart.ViewXY.PointLineSeries.RemoveAt(i);
break;
}
}
LgChart.EndUpdate();
ListChartRtSeries.Remove(ListChartRtSeries.FindFirst(a => a.Name == SeriesName));
}
/// <summary>
/// Chart设置事件
/// </summary>
/// <param name="obj"></param>
/// <exception cref="NotImplementedException"></exception>
private void ChartSetEventCall(ChartSetMsg par)
{
if (par.Machine != CurSelectedMachine)
{
return;
}
////当前是否是给自己的指令的信息
//if (par.GroupTabIndex == CurSelectedGroupTabIndex)
//{
//chart 的配置操作
switch (par.ChartSetInfo)
{
case "单游标":
SecondLineSeriesCursor.Visible = false;
IsDoubleCurson = false;
if (IsDoubleCurson)//双光标
{
FirstLineSeriesCursor.ValueAtXAxis = ChartAxisX!.DateTimeToAxisValue(returnMidTime(ChartAxisX.MinimumDateTime, ChartAxisX.MaximumDateTime));
SecondLineSeriesCursor.ValueAtXAxis = ChartAxisX!.DateTimeToAxisValue(returnSecondMidTime(ChartAxisX.MinimumDateTime, ChartAxisX.MaximumDateTime));
}
else//单光标
{
FirstLineSeriesCursor.ValueAtXAxis = ChartAxisX!.DateTimeToAxisValue(returnMidTime(ChartAxisX.MinimumDateTime, ChartAxisX.MaximumDateTime));
//把右侧的游标放的远一点,不然会挡住左侧游标
//SecondLineSeriesCursor.ValueAtXAxis = ChartAxisX!.DateTimeToAxisValue(returnMidTime(ChartAxisX.MinimumDateTime, ChartAxisX.MaximumDateTime))*1.1;
}
break;
case "双游标":
SecondLineSeriesCursor.Visible = true;
IsDoubleCurson = true;
if (IsDoubleCurson)//双光标
{
FirstLineSeriesCursor.ValueAtXAxis = ChartAxisX!.DateTimeToAxisValue(returnMidTime(ChartAxisX.MinimumDateTime, ChartAxisX.MaximumDateTime));
SecondLineSeriesCursor.ValueAtXAxis = ChartAxisX!.DateTimeToAxisValue(returnSecondMidTime(ChartAxisX.MinimumDateTime, ChartAxisX.MaximumDateTime));
}
else//单光标
{
FirstLineSeriesCursor.ValueAtXAxis = ChartAxisX!.DateTimeToAxisValue(returnMidTime(ChartAxisX.MinimumDateTime, ChartAxisX.MaximumDateTime));
//把右侧的游标放的远一点,不然会挡住左侧游标
//SecondLineSeriesCursor.ValueAtXAxis = ChartAxisX!.DateTimeToAxisValue(returnMidTime(ChartAxisX.MinimumDateTime, ChartAxisX.MaximumDateTime))*1.1;
}
break;
case "游标置中":
if (IsDoubleCurson)//双光标
{
FirstLineSeriesCursor.ValueAtXAxis = ChartAxisX!.DateTimeToAxisValue(returnMidTime(ChartAxisX.MinimumDateTime, ChartAxisX.MaximumDateTime));
SecondLineSeriesCursor.ValueAtXAxis = ChartAxisX!.DateTimeToAxisValue(returnSecondMidTime(ChartAxisX.MinimumDateTime, ChartAxisX.MaximumDateTime));
}
else//单光标
{
FirstLineSeriesCursor.ValueAtXAxis = ChartAxisX!.DateTimeToAxisValue(returnMidTime(ChartAxisX.MinimumDateTime, ChartAxisX.MaximumDateTime));
//把右侧的游标放的远一点,不然会挡住左侧游标
//SecondLineSeriesCursor.ValueAtXAxis = ChartAxisX!.DateTimeToAxisValue(returnMidTime(ChartAxisX.MinimumDateTime, ChartAxisX.MaximumDateTime))*1.1;
}
break;
case "游标放大":
break;
case "保存照片":
//只保存当前TabIndex的图片截图
if (par.GroupTabIndex == CurSelectedGroupTabIndex)
{
//临时屏蔽状态,保存会执行两次
if (ConfigService.ChartSavePageTempState)
{
ConfigService.ChartSavePageTempState = false;
}
else
{
return;
}
var PicPath = GetFilePath();
if (PicPath != null)
{
LgChart.SaveToFile(PicPath);
}
}
//
break;
default: break;
}
//}
}
/// <summary>
/// 设置控件的
/// 启用的信息
/// </summary>
/// <param name="msg"></param>
/// <exception cref="NotImplementedException"></exception>
private void ChartSetEnableEventCall(ChartSetEnableMsg par)
{
if (par.Machine != CurSelectedMachine)
{
return;
}
////当前是否是给自己的指令的信息
//if (par.GroupTabIndex == CurSelectedGroupTabIndex)
//{
//chart 的配置操作
switch (par.ChartSetInfo)
{
case "实时滚动":
IsScrollEnable = par.Enable;
break;
case "隐藏图例":
IsLegendHide = par.Enable;
LegendBox.Visible = !par.Enable;
break;
default: break;
}
//}
}
/// <summary>
/// 实时曲线更改的动作调用
/// </summary>
/// <param name="msg"></param>
private void ChartRtSeriesActionEventCall(ChartRtSeriesActionMsg msg)
{
if (msg.Machine != CurSelectedMachine)
{
return;
}
if (IsRealTimeChart)//实时曲线数据
{
//当前的系列
if (msg.GroupTabIndex == CurSelectedGroupTabIndex)
{
var ChartSelectedData = FreeSql.Select<ConfigChart>().Where(a => a.Machine == CurSelectedMachine
&& a.GroupTabIndex == CurSelectedGroupTabIndex).Include(a => a.ConfigChartYAxis).ToList();
if (ChartSelectedData.Count > 0)
{
LoadChartConfig(ChartSelectedData);
}
}
}
else//历史曲线数据
{
var ChartSelectedData = FreeSql.Select<HistoryConfigChart>().Where(a => a.Machine == CurSelectedMachine
&& a.GroupTabIndex == CurSelectedGroupTabIndex).Include(a => a.ConfigChartYAxis).ToList();
if (ChartSelectedData.Count > 0)
{
LoadHistoryChartConfig(ChartSelectedData);
}
}
}
/// <summary>
/// 加载曲线配置信息到当前曲线的实例中
/// </summary>
public void LoadChartConfig(List<ConfigChart> configChartSelects)
{
//从配置入手对比目前的状态,针对配置新增
foreach (var itemConfig in configChartSelects)
{
//判断当前是否已经存在,不存在的话,则新增
var data = ListChartRtSeries.FindFirst(a => a.Name == itemConfig.Name);
if (data == null)
{
var TagDecimalPoint = TagManager.DicTags.FindFirst(a => a.Key == itemConfig.Name).Value.DecimalPoint;
//新增系列曲线数据
var NewChartRtSeries = new ChartRtSeries(LgChart, ChartColorInfo, ListChartRtSeries, itemConfig, ConfigService, TagDecimalPoint);
//新增的曲线加载初始的数据 DatRecordService.CacheRecordData.
NewChartRtSeries.AddPointByDicData(DatRecordService.CacheRecordData, itemConfig.Name);
ListChartRtSeries.Add(NewChartRtSeries);
}
else
{
//修改 已经存在当前的曲线信息
}
}
////从目前的状态对比配置,针对删除项目
//foreach (var itemSeries in ListChartRtSeries)
//{
// var data = configChartSelects.FindFirst(a => a.Name == itemSeries.Name);
// if (data == null)
// {
// //查找删除的系列的Y轴是否还有其他的配置使用
// var configChartYAxis = configChartSelects.Find(a => a.ConfigChartYAxis.Name == itemSeries.ChartAxisY.Name);
// if (configChartYAxis == null)
// {
// //Y轴没有使用则删除
// itemSeries.DeleteAxisY();
// }
// //未找到,则删除
// ListChartRtSeries.Remove(itemSeries);
// }
// else
// {
// //存在就不需要操作
// }
//}
//从目前的状态对比配置,针对删除项目
for (var index = ListChartRtSeries.Count - 1; index >= 0; index--)
{
var data = configChartSelects.FindFirst(a => a.Name == ListChartRtSeries[index].Name);
if (data == null)
{
//查找删除的系列的Y轴是否还有其他的配置使用-先删除Y轴
var configChartYAxis = configChartSelects.Find(a => a.ConfigChartYAxis.Name == ListChartRtSeries[index].ChartAxisY.Name);
if (configChartYAxis == null)
{
//Y轴没有使用则删除
DeleteYAxis(ListChartRtSeries[index].ChartAxisY.Name);
//ListChartRtSeries[i].DeleteAxisY();
}
//未找到,则删除 曲线实例删除
DeleteSeries(ListChartRtSeries[index].Name);
}
else
{
//存在就不需要操作
}
}
}
/// <summary>
/// 加载曲线配置信息到当前曲线的实例中
/// </summary>
public void LoadHistoryChartConfig(List<HistoryConfigChart> configChartSelects)
{
//从配置入手对比目前的状态,针对配置新增
foreach (var itemConfig in configChartSelects)
{
//判断当前是否已经存在,不存在的话,则新增
var data = ListChartRtSeries.FindFirst(a => a.Name == itemConfig.Name);
if (data == null)
{
var TagDecimalPoint = TagManager.DicTags.FindFirst(a => a.Key == itemConfig.Name).Value.DecimalPoint;
//新增系列曲线数据
var NewChartRtSeries = new ChartRtSeries(LgChart, ChartColorInfo, ListChartRtSeries, itemConfig, ConfigService, TagDecimalPoint);
//新增的曲线加载初始的数据 CurHistoryData.
//历史数据需要增加使用历史的数据集
if (CurHistoryData != null && CurHistoryData.Count > 0)
{
//数据集更改
var SeriesData = GetChartPointByName(itemConfig.Name, CurHistoryData);
//批量增加数据
NewChartRtSeries.AddRangePoint(SeriesData);
}
ListChartRtSeries.Add(NewChartRtSeries);
}
else
{
//修改 已经存在当前的曲线信息
}
}
////从目前的状态对比配置,针对删除项目
//foreach (var itemSeries in ListChartRtSeries)
//{
// var data = configChartSelects.FindFirst(a => a.Name == itemSeries.Name);
// if (data == null)
// {
// //查找删除的系列的Y轴是否还有其他的配置使用
// var configChartYAxis = configChartSelects.Find(a => a.ConfigChartYAxis.Name == itemSeries.ChartAxisY.Name);
// if (configChartYAxis == null)
// {
// //Y轴没有使用则删除
// itemSeries.DeleteAxisY();
// }
// //未找到,则删除
// ListChartRtSeries.Remove(itemSeries);
// }
// else
// {
// //存在就不需要操作
// }
//}
//从目前的状态对比配置,针对删除项目
for (var index = ListChartRtSeries.Count - 1; index >= 0; index--)
{
var data = configChartSelects.FindFirst(a => a.Name == ListChartRtSeries[index].Name);
if (data == null)
{
//查找删除的系列的Y轴是否还有其他的配置使用-先删除Y轴
var configChartYAxis = configChartSelects.Find(a => a.ConfigChartYAxis.Name == ListChartRtSeries[index].ChartAxisY.Name);
if (configChartYAxis == null)
{
//Y轴没有使用则删除
DeleteYAxis(ListChartRtSeries[index].ChartAxisY.Name);
//ListChartRtSeries[i].DeleteAxisY();
}
//未找到,则删除 曲线实例删除
DeleteSeries(ListChartRtSeries[index].Name);
}
else
{
//存在就不需要操作
}
}
}
/// <summary>
/// 返回两个时间差的中间时刻
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public DateTime returnMidTime(DateTime dateTimeMin, DateTime dateTimeMax)//返回随机时间
{
TimeSpan ts = dateTimeMax - dateTimeMin;
var cur = ts.TotalSeconds / 2;
return dateTimeMin.AddSeconds(cur);
}
/// <summary>
/// 获取区间数据的比值 第二个光标
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public DateTime returnSecondMidTime(DateTime dateTimeMin, DateTime dateTimeMax)//返回随机时间
{
TimeSpan ts = dateTimeMax - dateTimeMin;
var cur = (ts.TotalSeconds / 2) + ts.TotalSeconds * 0.15;
return dateTimeMin.AddSeconds(cur);
}
/// <summary>
/// 获取保存文件的路径
/// </summary>
/// <returns></returns>
public string GetFilePath()
{
SaveFileDialog saveFileDialog = new SaveFileDialog
{
//CheckFileExists = true,
Filter = "Image Files (*.png;*.jpg;*.bmp)|*.png;*.jpg;*.bmp", // 设置文件类型过滤
Title = "保存图片文件",
CheckPathExists = true,
ValidateNames = true
};
bool? result = saveFileDialog.ShowDialog();
if (result == true)
{
return saveFileDialog.FileName;
}
return null;
}
#region ListView数据操作
#endregion
}
}