using ScottPlot;
|
using ScottPlot.Plottables;
|
using ScottPlot.TickGenerators;
|
using System;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Timers;
|
using System.Windows.Controls;
|
|
namespace Plugin.TestResult_WPF
|
{
|
/// <summary>
|
/// Chart.xaml 的交互逻辑
|
/// </summary>
|
public partial class Chart : UserControl
|
{
|
private readonly int maxSize;
|
|
private readonly Queue<long> xData;
|
private readonly Queue<double> yData;
|
|
private readonly Dictionary<string, Queue<long>> xValues;
|
private readonly Dictionary<string, Queue<double>> yValues;
|
|
readonly DataLogger singleLogger;
|
|
private readonly string title;
|
private readonly bool multi;
|
private readonly int refreshInterval;
|
|
private double maxYValue = -1;
|
private double minYValue = double.MaxValue;
|
|
private Timer timer;
|
|
private readonly Dictionary<string, DataLogger> loggers = new Dictionary<string, DataLogger>();
|
|
private DataLogger InitLogger()
|
{
|
DataLogger logger = chart.Plot.Add.DataLogger();
|
//logger.ViewSlide(maxSize * 5);
|
logger.ViewFull();
|
//logger.Add(new Coordinates(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), 0));
|
return logger;
|
}
|
|
public Chart(string title, bool multi, int maxSize, int refreshInterval)
|
{
|
this.title = title;
|
this.maxSize = maxSize;
|
this.multi = multi;
|
this.refreshInterval = refreshInterval;
|
|
|
InitializeComponent();
|
if (this.multi)
|
{
|
xValues = new Dictionary<string, Queue<long>>();
|
yValues = new Dictionary<string, Queue<double>>();
|
//chart.Plot.ShowLegend(Alignment.UpperLeft, Orientation.Vertical);
|
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.UserInputProcessor.Disable();
|
//chart.Plot.Layout.Frameless();
|
|
|
//Streamer1 = chart.Plot.Add.DataStreamer(maxSize);
|
//Streamer1.ViewScrollLeft();
|
//Streamer1.Color = Colors.Green;
|
|
//chart.Plot.Add.Scatter(xData.ToArray(), yData.ToArray());
|
|
|
|
|
//string CustomFormatter(DateTime dt)
|
//{
|
// return dt.ToString("HH:mm:ss.fff");
|
//}
|
//var axis = chart.Plot.Axes.DateTimeTicksBottom();
|
//var tickGen = (DateTimeAutomatic)axis.TickGenerator;
|
//tickGen.LabelFormatter = CustomFormatter;
|
|
//chart.Plot.Axes.Bottom.TickGenerator = new DateTimeAutomatic();
|
//chart.Plot.Axes.DateTimeTicksBottom();
|
//chart.Plot.RenderManager.RenderStarting += (s, e) =>
|
//{
|
// try
|
// {
|
// Tick[] ticks = chart.Plot.Axes.Bottom.TickGenerator.Ticks;
|
// for (int i = 0; i < ticks.Length; i++)
|
// {
|
// long ms = ticks[i].Position < 0 ? 0 : (long)ticks[i].Position;
|
// DateTime dt = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)).AddMilliseconds(ms);
|
// string label = $"{dt:hh:mm:ss.fff}";
|
// ticks[i] = new Tick(ticks[i].Position, label);
|
// }
|
// }
|
// catch (Exception ex)
|
// {
|
|
// }
|
//};
|
|
string CustomFormatter(double position)
|
{
|
if (position > 0)
|
return TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)).AddMilliseconds(position).ToString("HH:mm:ss");
|
return "";
|
}
|
EvenlySpacedMinorTickGenerator minorTickGen = new EvenlySpacedMinorTickGenerator(10);
|
NumericAutomatic myTickGenerator = new NumericAutomatic()
|
{
|
LabelFormatter = CustomFormatter,
|
MinorTickGenerator = minorTickGen
|
};
|
chart.Plot.Axes.Bottom.TickGenerator = myTickGenerator;
|
if (!string.IsNullOrEmpty(this.title))
|
{
|
chart.Plot.Axes.Left.Label.Text = this.title;
|
chart.Plot.Axes.Left.Label.Bold = false;
|
chart.Plot.Font.Automatic();
|
//RefreshData();
|
}
|
|
/// 设置刷新定时器
|
//refreshTimer = new System.Timers.Timer() { Interval = this.refreshInterval, AutoReset = true };
|
//refreshTimer.Elapsed += RefreshTimer_Elapsed;
|
|
//chart.Plot.DataBackground.Color = new Color(0, 0, 0);
|
//chart.Plot.Grid.MajorLineColor = Colors.Green.WithOpacity(.6);
|
//chart.Plot.Grid.MajorLineWidth = 1;
|
//chart.Plot.Grid.MinorLineColor = Colors.Gray.WithOpacity(.3);
|
//chart.Plot.Grid.MinorLineWidth = 1;
|
|
//chart.Plot.Axes.Bottom.TickLabelStyle.IsVisible = false;
|
//chart.Plot.Axes.Bottom.MajorTickStyle.Length = 0;
|
//chart.Plot.Axes.Left.TickLabelStyle.IsVisible = false;
|
//chart.Plot.Axes.Left.MajorTickStyle.Length = 0;
|
|
//chart.Plot.Axes.Bottom.FrameLineStyle.Width = 0;
|
//chart.Plot.Axes.Left.FrameLineStyle.Width = 0;
|
//chart.Plot.Axes.Top.FrameLineStyle.Width = 0;
|
//chart.Plot.Axes.Right.FrameLineStyle.Width = 0;
|
|
timer = new Timer();
|
timer.Interval = this.refreshInterval;
|
timer.Elapsed += Timer_Elapsed;
|
}
|
|
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
|
{
|
if (maxYValue > 0)
|
{
|
RefreshData();
|
}
|
}
|
|
public void RefreshData()
|
{
|
/// 限制y轴
|
if (maxYValue > -1)
|
{
|
chart.Plot.Axes.SetLimitsY(minYValue > 5 ? minYValue - 5 : 0, maxYValue + 5);
|
}
|
else
|
{
|
chart.Plot.Axes.SetLimitsY(0, 100);
|
}
|
chart.Refresh();
|
}
|
|
public void Clear()
|
{
|
this.maxYValue = -1;
|
this.minYValue = double.MaxValue;
|
if (this.multi)
|
{
|
foreach (var name in loggers.Keys)
|
{
|
loggers[name].Clear();
|
xValues[name].Clear();
|
yValues[name].Clear();
|
}
|
chart.Refresh();
|
return;
|
}
|
singleLogger.Clear();
|
xData.Clear();
|
yData.Clear();
|
chart.Refresh();
|
}
|
|
public void AddData(double y)
|
{
|
if (this.multi)
|
{
|
return;
|
}
|
|
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();
|
}
|
|
private void InsertData(Queue<long> xAxis, Queue<double> yAxis, long x, double y)
|
{
|
if (xAxis.Count >= maxSize)
|
{
|
xAxis.Dequeue();
|
yAxis.Dequeue();
|
}
|
xAxis.Enqueue(x);
|
yAxis.Enqueue(y);
|
}
|
|
public void AddData(string name, double y)
|
{
|
if (!this.multi)
|
{
|
return;
|
}
|
|
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);
|
}
|
|
//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();
|
}
|
|
private void UserControl_Loaded(object sender, System.Windows.RoutedEventArgs e)
|
{
|
//refreshTimer.Start();
|
timer?.Start();
|
}
|
|
private void UserControl_Unloaded(object sender, System.Windows.RoutedEventArgs e)
|
{
|
timer?.Stop();
|
}
|
|
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);
|
}
|
}
|
}
|