using Plugin.TestResult_WPF.Model;
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
{
///
/// Chart.xaml 的交互逻辑
///
///
/// Chart.xaml 的交互逻辑
///
public partial class Chart : UserControl
{
private readonly int maxSize;
private readonly Queue xData;
private readonly Queue yData;
private readonly Dictionary> xValues;
private readonly Dictionary> 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 float fontSize = -1;
private Timer timer;
private readonly Dictionary loggers = new Dictionary();
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>();
yValues = new Dictionary>();
//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(maxSize);
yData = new Queue(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;
}
public Chart(string title, bool multi, float titleSize)
{
BaseConfig config = new BaseConfig();
this.title = title;
this.multi = multi;
this.maxSize = config.MaxSize;
this.refreshInterval = config.RefreshInterval;
fontSize = titleSize;
InitializeComponent();
if (this.multi)
{
xValues = new Dictionary>();
yValues = new Dictionary>();
//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 = titleSize - 3;
chart.Plot.Axes.Bottom.TickLabelStyle.FontSize = titleSize - 3;
chart.Plot.Axes.Left.Label.FontSize = titleSize;
}
else
{
singleLogger = InitLogger();
singleLogger.Color = Colors.Red;
xData = new Queue(maxSize);
yData = new Queue(maxSize);
chart.Plot.Axes.Left.TickLabelStyle.FontSize = titleSize - 3;
chart.Plot.Axes.Bottom.TickLabelStyle.FontSize = titleSize - 3;
chart.Plot.Axes.Left.Label.FontSize = titleSize;
}
/// 禁用鼠标
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 "";
}
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();
}
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()
{
bool flag = timer.Enabled;
try
{
timer.Enabled = false;
/// 限制y轴
if (maxYValue > -1)
{
chart.Plot.Axes.SetLimitsY(minYValue > 5 ? minYValue - 5 : 0, maxYValue + 5);
}
else
{
chart.Plot.Axes.SetLimitsY(0, 100);
}
chart.Refresh();
}
finally
{
timer.Enabled = flag;
}
}
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()
.ToList()
.ForEach(m => m.X -= 1);
chart.Plot.GetPlottables()
.Where(m => m.X < 0)
.ToList()
.ForEach(m => chart.Plot.Remove(m));
//RefreshData();
}
public List GetSingleData()
{
bool flag = timer.Enabled;
try
{
timer.Enabled = false;
return yData?.ToList();
}
finally
{
timer.Enabled = flag;
}
}
private void InsertData(Queue xAxis, Queue 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(maxSize);
var yAxis = new Queue(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()
.ToList()
.ForEach(m => m.X -= 1);
chart.Plot.GetPlottables()
.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;
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;
}
}
}
}