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 "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();
case "液冷媒流量[kg/h]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.LiqRefFlow, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "干度流量[kg/h]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.DryFlow, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "H5吸气混合器温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.H5InhMixTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "COND循环水温[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.CONDCirWaterTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "SUBCOOL出口温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.SubcoolOutTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "吸气混合器出口温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.InhMixOutTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "H1出口温度[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.H1OutTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "S.C循环水温[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.SCCirWaterTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "EVAP循环水温[℃]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.EvapCirWaterTemp, Time = a.CreateTime }).OrderBy(a => a.Time).ToList();
case "吸气混合器出口压力[BarA]":
return CurHistoryData.Select(a => new ChartPoint() { Value = a.InhMixOutPress, 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
}
}