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 { /// /// 曲线管理 /// 实现对一个Chart实例进行管理 /// public class ChartManager : BindableBase { /// /// 实例化函数 /// 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(); ListConfigChart = new List(); 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().Subscribe(UpdateRecordData, ThreadOption.UIThread); _EventAggregator.GetEvent().Subscribe(ChartSetEventCall); _EventAggregator.GetEvent().Subscribe(ChartSetEnableEventCall); _EventAggregator.GetEvent().Subscribe(ChartRtSeriesActionEventCall); _EventAggregator.GetEvent().Subscribe(ChartTabGroupSwitchCall); } else { _EventAggregator.GetEvent().Subscribe(ChartSetEventCall); _EventAggregator.GetEvent().Subscribe(ChartSetEnableEventCall); _EventAggregator.GetEvent().Subscribe(ChartRtSeriesActionEventCall); _EventAggregator.GetEvent().Subscribe(ChartTabGroupSwitchCall); _EventAggregator.GetEvent().Subscribe(HistoryDataToChartCall, ThreadOption.UIThread); } //Y轴对任何的曲线都适用 _EventAggregator.GetEvent().Subscribe(ChartYAxisConfigEventCall); //初始化曲线 InitChart(); } /// /// LightningChart 通知、错误和异常处理 /// /// /// 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}"); } /// /// 更新Y轴的信息 /// /// private void ChartYAxisConfigEventCall(ChartYAxisConfigMsg msg) { UpdateChartAxisY(msg.ConfigChartYAxes); } #region 历史曲线数据 /// /// 历史数据 /// private List CurHistoryData { get; set; } /// /// 历史数据加载到Chart的信息 /// /// private void HistoryDataToChartCall(HistoryDataToChartMsg msg) { if (msg.Machine != CurSelectedMachine) { //选择了其他的机械的话,则也是没有被激活 IsActivated = false; return; } CurHistoryData = msg.Data; LoadHistoryDataChart(); } Stopwatch stopwatch = new Stopwatch(); /// /// 加载历史数据到曲线中 /// 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(); } /// /// 根据名称获取Point数据 /// /// private List GetChartPointByName(string Name, List 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 "COND循环水温[℃]": return CurHistoryData.Select(a => new ChartPoint() { Value = a.Cond1Temp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList(); case "SUBCOOL出口温度[℃]": return CurHistoryData.Select(a => new ChartPoint() { Value = a.LubePress, Time = a.CreateTime }).OrderBy(a => a.Time).ToList(); case "吸气混合器出口温度[℃]": 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 "H1出口温度[℃]": return CurHistoryData.Select(a => new ChartPoint() { Value = a.OS2Temp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList(); case "H5吸气混合器温度[℃]": 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 /// /// 更新Y轴的信息,最大值和最小值 /// private void UpdateChartAxisY(List 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(); } /// /// 切换Tab,是不是当前的Tab信息 /// /// private void ChartTabGroupSwitchCall(ChartTabGroupSwitchMsg msg) { if (msg.Machine != CurSelectedMachine) { //选择了其他的机械的话,则也是没有被激活 IsActivated = false; return; } //当前的系列 if (msg.GroupTabIndex == CurSelectedGroupTabIndex) { IsActivated = true; } else { IsActivated = false; } } /// /// 事件聚合器 /// private IEventAggregator _EventAggregator { get; set; } public TagManager TagManager { get; } private DataRecordService DatRecordService { get; set; } public IFreeSql FreeSql { get; } /// /// 当前的Chart所属的TabIndex /// private int CurSelectedGroupTabIndex { get; set; } /// /// 当前选中的Machine /// private string CurSelectedMachine { get; set; } /// /// 当前曲线是否被激活 /// 当前被查看的Chart控件 /// private bool IsActivated { get; set; } = false; /// /// 初始化Ok了吗 /// private bool IsInitOk { get; set; } = false; /// /// 是否为实时曲线 /// 默认为实时曲线 /// 否则为历史数据曲线 /// private bool IsRealTimeChart { get; set; } = true; public ILogService LogService { get; } public ConfigService ConfigService { get; } /// /// Chart曲线的实例 /// public LightningChart LgChart { get; set; } /// /// 是否为双游标 /// private bool IsDoubleCurson { get; set; } = false; /// /// 曲线名称 /// public string ChartName { get; set; } private ObservableCollection _ListChartRtSeries; /// /// 曲线数据系列集合 /// public ObservableCollection ListChartRtSeries { get { return _ListChartRtSeries; } set { _ListChartRtSeries = value; RaisePropertyChanged(); } } ///// ///// 曲线数据系列集合 ///// //public List ListChartRtSeries { get; set; } /// /// Chart显示哪些参数配置 业务相关 /// public List ListConfigChart { get; set; } /// /// 曲线配置 /// public ChartColor ChartColorInfo { get; set; } = new ChartColor(); ///// ///// Chart图表X轴的跨度-秒 ///// //public int ChartXDateTimeRange { get; set; } = 3600_8; /// /// X轴滚动 /// public bool IsScrollEnable { get; set; } = true; /// /// 隐藏图例 /// public bool IsLegendHide { get; set; } = false; /// /// 是否删除之前的数据 /// public bool IsDeleteBefore { get; set; } = true; /// /// X轴 /// public AxisX? ChartAxisX { get; set; } /// /// 第一个光标 /// 单双光标时使用 /// public LineSeriesCursor FirstLineSeriesCursor { get; set; } /// /// 第一个光标的X轴时间 /// public DateTime FirstCursorDatetime { get; set; } /// /// 第二个光标 /// 双光标时使用 /// public LineSeriesCursor SecondLineSeriesCursor { get; set; } /// /// 第二个光标的X轴时间 /// public DateTime SecondCursorDatetime { get; set; } /// /// Annotations 注释 /// public AnnotationXY CursorValueDisplay { get; set; } /// /// 当前的图例 /// public LegendBoxXY LegendBox { get; set; } /// /// 卡尺 注释 没有使用 /// public AnnotationXY Caliper { get; set; } /// /// Chart初始化 /// 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; } /// /// 获取订阅的的数据 /// 确保和数据记录的数据是一致的,并且是同一个时刻 /// /// /// 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 } } } /// /// 曲线个数 /// private int ChartSeriesCount { get; set; } = 0; /// /// 更新图表信息 /// 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(); } } /// /// 根据名称获取曲线所需的数据 /// 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(); } /// /// 第一个光标位置变化 /// /// /// private void FirstCursor_PositionChanged(object sender, PositionChangedEventArgs e) { e.CancelRendering = true; if (!IsInitOk) return; FirstUpdateCursorResult(sender); } /// /// 光标位置变化 /// /// /// private void SecondCursor_PositionChanged(object sender, PositionChangedEventArgs e) { e.CancelRendering = true; if (!IsInitOk) return; SecondUpdateCursorResult(sender); } /// /// Update cursor texts. /// 更新光标的注释信息 /// 使用AnnotationXY进行展示,已经舍弃 /// 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(); } /// /// Update cursor texts. /// 更新到ListView中 /// 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(); } /// /// Update cursor texts. /// 第一个游标更新位置,更新结果 /// 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(); } /// /// Update cursor texts. /// 第二个游标更新位置,更新结果 /// 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(); } /// /// 计算数据 /// /// 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); // 返回默认值 } /// /// 计算历史数据 /// 历史曲线 /// /// 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); // 返回默认值 } /// /// Solve value from series data points array. Accurate method, but slower than SolveValueCoarse /// /// Series /// X value /// Output Y value /// Success status 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; } } /// /// Solve value from screen coordinates. Faster method, but not less accurateValue than SolveValueAccurate /// /// Series /// X value /// Output Y value /// Success status 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; } /// /// 增加Y轴 /// /// /// /// 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--; } } /// /// 删除系列 /// 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)); } /// /// Chart设置事件 /// /// /// 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; } //} } /// /// 设置控件的 /// 启用的信息 /// /// /// 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; } //} } /// /// 实时曲线更改的动作调用 /// /// private void ChartRtSeriesActionEventCall(ChartRtSeriesActionMsg msg) { if (msg.Machine != CurSelectedMachine) { return; } if (IsRealTimeChart)//实时曲线数据 { //当前的系列 if (msg.GroupTabIndex == CurSelectedGroupTabIndex) { var ChartSelectedData = FreeSql.Select().Where(a => a.Machine == CurSelectedMachine && a.GroupTabIndex == CurSelectedGroupTabIndex).Include(a => a.ConfigChartYAxis).ToList(); if (ChartSelectedData.Count > 0) { LoadChartConfig(ChartSelectedData); } } } else//历史曲线数据 { var ChartSelectedData = FreeSql.Select().Where(a => a.Machine == CurSelectedMachine && a.GroupTabIndex == CurSelectedGroupTabIndex).Include(a => a.ConfigChartYAxis).ToList(); if (ChartSelectedData.Count > 0) { LoadHistoryChartConfig(ChartSelectedData); } } } /// /// 加载曲线配置信息到当前曲线的实例中 /// public void LoadChartConfig(List 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 { //存在就不需要操作 } } } /// /// 加载曲线配置信息到当前曲线的实例中 /// public void LoadHistoryChartConfig(List 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 { //存在就不需要操作 } } } /// /// 返回两个时间差的中间时刻 /// /// /// public DateTime returnMidTime(DateTime dateTimeMin, DateTime dateTimeMax)//返回随机时间 { TimeSpan ts = dateTimeMax - dateTimeMin; var cur = ts.TotalSeconds / 2; return dateTimeMin.AddSeconds(cur); } /// /// 获取区间数据的比值 第二个光标 /// /// /// public DateTime returnSecondMidTime(DateTime dateTimeMin, DateTime dateTimeMax)//返回随机时间 { TimeSpan ts = dateTimeMax - dateTimeMin; var cur = (ts.TotalSeconds / 2) + ts.TotalSeconds * 0.15; return dateTimeMin.AddSeconds(cur); } /// /// 获取保存文件的路径 /// /// 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 } }