| | |
| | | using ScottPlot; |
| | | using log4net.Repository.Hierarchy; |
| | | using Plugin.TestResult_WPF.Model; |
| | | using ScottPlot; |
| | | using ScottPlot.Plottables; |
| | | using ScottPlot.TickGenerators; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Data.SqlTypes; |
| | | using System.Linq; |
| | | using System.Text; |
| | | using System.Timers; |
| | | using System.Windows.Controls; |
| | | using System.Windows.Documents; |
| | | using System.Xml.Linq; |
| | | |
| | | namespace Plugin.TestResult_WPF |
| | | { |
| | | /// <summary> |
| | | /// Chart.xaml 的交互逻辑 |
| | | /// </summary> |
| | | /// <summary> |
| | | /// Chart.xaml 的交互逻辑 |
| | | /// </summary> |
| | |
| | | private readonly Dictionary<string, Queue<long>> xValues; |
| | | private readonly Dictionary<string, Queue<double>> yValues; |
| | | |
| | | readonly DataLogger singleLogger; |
| | | private readonly Dictionary<DataLogger, double> maxValue = new Dictionary<DataLogger, double>(); |
| | | private readonly Dictionary<DataLogger, double> minValue = new Dictionary<DataLogger, double>(); |
| | | |
| | | private readonly string title; |
| | | private readonly bool multi; |
| | |
| | | |
| | | private double maxYValue = -1; |
| | | private double minYValue = double.MaxValue; |
| | | private float fontSize = -1; |
| | | |
| | | private Timer timer; |
| | | |
| | | private LinePlot[] childrenPlot; |
| | | |
| | | private readonly Dictionary<string, DataLogger> loggers = new Dictionary<string, DataLogger>(); |
| | | |
| | |
| | | return logger; |
| | | } |
| | | |
| | | public Chart(string title, bool multi, int maxSize, int refreshInterval) |
| | | public Chart(string title, bool multi, float titleSize) |
| | | { |
| | | BaseConfig config = new BaseConfig(); |
| | | this.title = title; |
| | | this.maxSize = maxSize; |
| | | this.maxSize = config.MaxSize; |
| | | this.multi = multi; |
| | | this.refreshInterval = refreshInterval; |
| | | this.refreshInterval = config.RefreshInterval; |
| | | this.fontSize = titleSize; |
| | | |
| | | |
| | | InitializeComponent(); |
| | |
| | | var legend = chart.Plot.ShowLegend(Edge.Top); |
| | | legend.Alignment = Alignment.UpperLeft; |
| | | legend.Padding = new PixelPadding(0); |
| | | |
| | | |
| | | chart.Plot.Axes.Left.TickLabelStyle.FontSize = 12; |
| | | chart.Plot.Axes.Bottom.TickLabelStyle.FontSize = 12; |
| | | chart.Plot.Axes.Left.Label.FontSize = 15; |
| | | } |
| | | else |
| | | { |
| | | singleLogger = InitLogger(); |
| | | singleLogger.Color = Colors.Red; |
| | | xData = new Queue<long>(maxSize); |
| | | yData = new Queue<double>(maxSize); |
| | | chart.Plot.Axes.Left.TickLabelStyle.FontSize = (float)FontSizeConverter.CountFontSize(12, ActualHeight, 92); |
| | | chart.Plot.Axes.Bottom.TickLabelStyle.FontSize = (float)FontSizeConverter.CountFontSize(12, ActualHeight, 92); |
| | | chart.Plot.Axes.Left.Label.FontSize = (float)FontSizeConverter.CountFontSize(15, ActualHeight, 92); |
| | | } |
| | | |
| | | chart.Plot.Axes.Left.TickLabelStyle.FontSize = 12; |
| | | chart.Plot.Axes.Left.Label.FontSize = 15; |
| | | chart.Plot.Axes.Bottom.TickLabelStyle.FontSize = 12; |
| | | chart.Plot.Axes.Bottom.TickLabelStyle.IsVisible = false; |
| | | chart.Plot.Axes.Bottom.MajorTickStyle.Color = Colors.Transparent; |
| | | chart.Plot.Axes.Bottom.MinorTickStyle.Color = Colors.Transparent; |
| | | |
| | | /// 禁用鼠标 |
| | | chart.UserInputProcessor.Disable(); |
| | |
| | | timer.Elapsed += Timer_Elapsed; |
| | | } |
| | | |
| | | public Chart(string title, string[] serials, float titleSize) |
| | | { |
| | | BaseConfig config = new BaseConfig(); |
| | | this.title = title; |
| | | this.multi = true; |
| | | this.maxSize = config.MaxSize; |
| | | this.refreshInterval = config.RefreshInterval; |
| | | fontSize = titleSize; |
| | | |
| | | childrenPlot = new LinePlot[serials.Length]; |
| | | |
| | | InitializeComponent(); |
| | | |
| | | xValues = new Dictionary<string, Queue<long>>(); |
| | | yValues = new Dictionary<string, Queue<double>>(); |
| | | //chart.Plot.ShowLegend(Alignment.UpperLeft, Orientation.Vertical); |
| | | var panel = chart.Plot.ShowLegend(Edge.Top); |
| | | panel.Alignment = Alignment.UpperLeft; |
| | | panel.Padding = new PixelPadding(0); |
| | | |
| | | chart.Plot.Axes.Left.TickLabelStyle.FontSize = titleSize - 3; |
| | | chart.Plot.Axes.Left.Label.FontSize = titleSize; |
| | | |
| | | chart.Plot.Axes.Right.TickLabelStyle.FontSize = titleSize - 3; |
| | | chart.Plot.Axes.Right.Label.FontSize = titleSize; |
| | | |
| | | chart.Plot.Axes.Bottom.TickLabelStyle.FontSize = titleSize - 3; |
| | | chart.Plot.Axes.Bottom.TickLabelStyle.IsVisible = false; |
| | | chart.Plot.Axes.Bottom.MajorTickStyle.Color = Colors.Transparent; |
| | | chart.Plot.Axes.Bottom.MinorTickStyle.Color = Colors.Transparent; |
| | | |
| | | /// 禁用鼠标 |
| | | chart.UserInputProcessor.Disable(); |
| | | |
| | | string CustomFormatter(double position) |
| | | { |
| | | if (position > 0) |
| | | return TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)).AddMilliseconds(position).ToString("HH:mm:ss"); |
| | | return ""; |
| | | } |
| | | chart.Plot.HideLegend(); |
| | | |
| | | EvenlySpacedMinorTickGenerator minorTickGen = new EvenlySpacedMinorTickGenerator(10); |
| | | NumericAutomatic myTickGenerator = new NumericAutomatic() |
| | | { |
| | | LabelFormatter = CustomFormatter, |
| | | MinorTickGenerator = minorTickGen |
| | | }; |
| | | chart.Plot.Axes.Bottom.TickGenerator = myTickGenerator; |
| | | if (!string.IsNullOrEmpty(serials[0])) |
| | | { |
| | | var newLine = chart.Plot.Add.Line(Coordinates.NaN, Coordinates.NaN); |
| | | newLine.Axes.YAxis = chart.Plot.Axes.Left; |
| | | newLine.Axes.XAxis = chart.Plot.Axes.Bottom; |
| | | |
| | | childrenPlot[0] = newLine; |
| | | chart.Plot.Axes.Left.Label.Text = serials[0]; |
| | | chart.Plot.Axes.Left.Label.Bold = false; |
| | | chart.Plot.Font.Automatic(); |
| | | } |
| | | |
| | | if (!string.IsNullOrEmpty(serials[1])) |
| | | { |
| | | var newLine = chart.Plot.Add.Line(Coordinates.NaN, Coordinates.NaN); |
| | | newLine.Axes.YAxis = chart.Plot.Axes.Right; |
| | | newLine.Axes.XAxis = chart.Plot.Axes.Bottom; |
| | | |
| | | childrenPlot[1] = newLine; |
| | | chart.Plot.Axes.Right.Label.Text = serials[1]; |
| | | chart.Plot.Axes.Right.Label.Bold = false; |
| | | chart.Plot.Font.Automatic(); |
| | | } |
| | | |
| | | timer = new Timer(); |
| | | timer.Interval = this.refreshInterval; |
| | | timer.Elapsed += Timer_Elapsed; |
| | | } |
| | | |
| | | private void Timer_Elapsed(object sender, ElapsedEventArgs e) |
| | | { |
| | | if (maxYValue > 0) |
| | |
| | | } |
| | | } |
| | | |
| | | private DataLogger GetLogger(string name, out bool isNew, string legend = null) |
| | | { |
| | | isNew = false; |
| | | if (!loggers.ContainsKey(name)) |
| | | { |
| | | var logger = InitLogger(); |
| | | if (legend != null) logger.LegendText = name; |
| | | loggers.Add(name, logger); |
| | | isNew = true; |
| | | } |
| | | return loggers[name]; |
| | | } |
| | | |
| | | public void RefreshData() |
| | | { |
| | | /// 限制y轴 |
| | | if (maxYValue > -1) |
| | | bool flag = timer.Enabled; |
| | | try |
| | | { |
| | | chart.Plot.Axes.SetLimitsY(minYValue > 5 ? minYValue - 5 : 0, maxYValue + 5); |
| | | timer.Enabled = false; |
| | | foreach (var logger in loggers.Values) |
| | | { |
| | | logger.ViewFull(); |
| | | } |
| | | |
| | | /// 限制y轴 |
| | | if (maxYValue > -1) |
| | | { |
| | | chart.Plot.Axes.SetLimitsY(minYValue > 5 ? minYValue - 5 : 0, maxYValue + 5); |
| | | } |
| | | else |
| | | { |
| | | chart.Plot.Axes.SetLimitsY(0, 100); |
| | | } |
| | | chart.Refresh(); |
| | | } |
| | | else |
| | | finally |
| | | { |
| | | chart.Plot.Axes.SetLimitsY(0, 100); |
| | | timer.Enabled = flag; |
| | | } |
| | | chart.Refresh(); |
| | | } |
| | | |
| | | public void Clear() |
| | | { |
| | | this.maxYValue = -1; |
| | | this.minYValue = double.MaxValue; |
| | | if (this.multi) |
| | | foreach (var name in loggers.Keys) |
| | | { |
| | | foreach (var name in loggers.Keys) |
| | | { |
| | | loggers[name].Clear(); |
| | | xValues[name].Clear(); |
| | | yValues[name].Clear(); |
| | | } |
| | | chart.Refresh(); |
| | | return; |
| | | loggers[name].Clear(); |
| | | xValues?[name]?.Clear(); |
| | | yValues?[name]?.Clear(); |
| | | } |
| | | singleLogger.Clear(); |
| | | xData.Clear(); |
| | | yData.Clear(); |
| | | xData?.Clear(); |
| | | yData?.Clear(); |
| | | chart.Refresh(); |
| | | } |
| | | |
| | | public void AddData(double y) |
| | | public List<double> GetSingleData() |
| | | { |
| | | if (this.multi) |
| | | bool flag = timer.Enabled; |
| | | try |
| | | { |
| | | return; |
| | | timer.Enabled = false; |
| | | return yData?.ToList(); |
| | | } |
| | | |
| | | this.maxYValue = y > maxYValue ? y : maxYValue; |
| | | this.minYValue = y < minYValue ? y : minYValue; |
| | | |
| | | var nowTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); |
| | | InsertData(xData, yData, nowTime, y); |
| | | |
| | | singleLogger.Add(new Coordinates(nowTime, y)); |
| | | //Streamer1.Add(new Coordinates(DateTimeOffset.Now.ToUnixTimeSeconds(), y)); |
| | | |
| | | chart.Plot.GetPlottables<Marker>() |
| | | .ToList() |
| | | .ForEach(m => m.X -= 1); |
| | | chart.Plot.GetPlottables<Marker>() |
| | | .Where(m => m.X < 0) |
| | | .ToList() |
| | | .ForEach(m => chart.Plot.Remove(m)); |
| | | //RefreshData(); |
| | | finally |
| | | { |
| | | timer.Enabled = flag; |
| | | } |
| | | } |
| | | |
| | | private void InsertData(Queue<long> xAxis, Queue<double> yAxis, long x, double y) |
| | |
| | | yAxis.Enqueue(y); |
| | | } |
| | | |
| | | public void AddData(string name, double y) |
| | | public void AddData(double y) |
| | | { |
| | | if (!this.multi) |
| | | if (this.multi) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | var commonName = "Single"; |
| | | this.maxYValue = y > maxYValue ? y : maxYValue; |
| | | this.minYValue = y < minYValue ? y : minYValue; |
| | | |
| | | if (loggers.ContainsKey(name)) |
| | | { |
| | | var logger = loggers[name]; |
| | | var x = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); |
| | | logger.Add(new Coordinates(x, y)); |
| | | InsertData(xValues[name], yValues[name], x, y); |
| | | } |
| | | else |
| | | { |
| | | var logger = InitLogger(); |
| | | logger.LegendText = name; |
| | | loggers.Add(name, logger); |
| | | var xAxis = new Queue<long>(maxSize); |
| | | var yAxis = new Queue<double>(maxSize); |
| | | |
| | | xValues.Add(name, xAxis); |
| | | yValues.Add(name, yAxis); |
| | | |
| | | var x = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); |
| | | logger.Add(new Coordinates(x, y)); |
| | | InsertData(xAxis, yAxis, x, y); |
| | | } |
| | | var nowTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); |
| | | DataLogger singleLogger = GetLogger(commonName, out _); |
| | | singleLogger.Color = Colors.Red; |
| | | InsertData(xData, yData, nowTime, y); |
| | | singleLogger.Add(new Coordinates(nowTime, y)); |
| | | |
| | | //Streamer1.Add(new Coordinates(DateTimeOffset.Now.ToUnixTimeSeconds(), y)); |
| | | |
| | |
| | | .Where(m => m.X < 0) |
| | | .ToList() |
| | | .ForEach(m => chart.Plot.Remove(m)); |
| | | //RefreshData(); |
| | | } |
| | | |
| | | public void AddData(string name, double y) |
| | | { |
| | | if (!this.multi) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | this.maxYValue = y > maxYValue ? y : maxYValue; |
| | | this.minYValue = y < minYValue ? y : minYValue; |
| | | DataLogger logger = null; |
| | | if (loggers.ContainsKey(name)) |
| | | { |
| | | logger = loggers[name]; |
| | | } |
| | | else |
| | | { |
| | | logger = InitLogger(); |
| | | logger.LegendText = name; |
| | | loggers.Add(name, logger); |
| | | var xAxis = new Queue<long>(maxSize); |
| | | var yAxis = new Queue<double>(maxSize); |
| | | |
| | | xValues.Add(name, xAxis); |
| | | yValues.Add(name, yAxis); |
| | | } |
| | | |
| | | var x = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); |
| | | logger.Add(new Coordinates(x, y)); |
| | | InsertData(xValues[name], yValues[name], x, y); |
| | | |
| | | //Streamer1.Add(new Coordinates(DateTimeOffset.Now.ToUnixTimeSeconds(), y)); |
| | | |
| | | chart.Plot.GetPlottables<Marker>() |
| | | .ToList() |
| | | .ForEach(m => m.X -= 1); |
| | | chart.Plot.GetPlottables<Marker>() |
| | | .Where(m => m.X < 0) |
| | | .ToList() |
| | | .ForEach(m => chart.Plot.Remove(m)); |
| | | } |
| | | |
| | | public void AddData(int serials, string name, double y) |
| | | { |
| | | if (!this.multi) |
| | | { |
| | | return; |
| | | } |
| | | var plot = childrenPlot[serials]; |
| | | |
| | | DataLogger logger = GetLogger(name, out bool isNew, name); |
| | | this.maxYValue = y > maxYValue ? y : maxYValue; |
| | | this.minYValue = y < minYValue ? y : minYValue; |
| | | |
| | | logger.Axes.YAxis = plot.Axes.YAxis; |
| | | logger.Axes.XAxis = plot.Axes.XAxis; |
| | | if (name == "水箱温度") |
| | | { |
| | | logger.Color = Colors.Red; |
| | | } |
| | | else if (name == "回水温度") |
| | | { |
| | | logger.Color = Colors.Blue; |
| | | } |
| | | else |
| | | { |
| | | logger.Color = Colors.Green; |
| | | } |
| | | |
| | | if (isNew) |
| | | { |
| | | var xAxis = new Queue<long>(maxSize); |
| | | var yAxis = new Queue<double>(maxSize); |
| | | |
| | | xValues.Add(name, xAxis); |
| | | yValues.Add(name, yAxis); |
| | | } |
| | | |
| | | var x = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); |
| | | logger.Add(new Coordinates(x, y)); |
| | | InsertData(xValues[name], yValues[name], x, y); |
| | | |
| | | //Streamer1.Add(new Coordinates(DateTimeOffset.Now.ToUnixTimeSeconds(), y)); |
| | | |
| | | chart.Plot.GetPlottables<Marker>() |
| | | .ToList() |
| | | .ForEach(m => m.X -= 1); |
| | | chart.Plot.GetPlottables<Marker>() |
| | | .Where(m => m.X < 0) |
| | | .ToList() |
| | | .ForEach(m => chart.Plot.Remove(m)); |
| | | } |
| | | |
| | | private void UserControl_Loaded(object sender, System.Windows.RoutedEventArgs e) |
| | |
| | | private void UserControl_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e) |
| | | { |
| | | if (this.multi) return; |
| | | chart.Plot.Axes.Left.Label.FontSize = (float)FontSizeConverter.CountFontSize(15, ActualHeight, 92); |
| | | chart.Plot.Axes.Left.TickLabelStyle.FontSize = (float)FontSizeConverter.CountFontSize(10, ActualHeight, 92); |
| | | chart.Plot.Axes.Bottom.TickLabelStyle.FontSize = (float)FontSizeConverter.CountFontSize(10, ActualHeight, 92); |
| | | if (fontSize < 0) |
| | | { |
| | | chart.Plot.Axes.Left.Label.FontSize = (float)FontSizeConverter.CountFontSize(15, ActualHeight, 92); |
| | | chart.Plot.Axes.Left.TickLabelStyle.FontSize = (float)FontSizeConverter.CountFontSize(10, ActualHeight, 92); |
| | | chart.Plot.Axes.Bottom.TickLabelStyle.FontSize = (float)FontSizeConverter.CountFontSize(10, ActualHeight, 92); |
| | | } |
| | | else |
| | | { |
| | | chart.Plot.Axes.Left.Label.FontSize = fontSize - 3; |
| | | chart.Plot.Axes.Left.TickLabelStyle.FontSize = fontSize - 3; |
| | | chart.Plot.Axes.Bottom.TickLabelStyle.FontSize = fontSize; |
| | | } |
| | | } |
| | | } |
| | | } |