From 9d1660270272180cd71147d6ddd53d1382643d2e Mon Sep 17 00:00:00 2001
From: wenxiangchao <wenxiangchao@ihengxin.com.cn>
Date: 星期一, 02 十一月 2026 18:00:14 +0800
Subject: [PATCH] merge: 并入远程 Initial commit 作为历史根节点

---
 Plugin.TestResult/Chart.xaml.cs |  496 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 496 insertions(+), 0 deletions(-)

diff --git a/Plugin.TestResult/Chart.xaml.cs b/Plugin.TestResult/Chart.xaml.cs
new file mode 100644
index 0000000..ffd5c46
--- /dev/null
+++ b/Plugin.TestResult/Chart.xaml.cs
@@ -0,0 +1,496 @@
+锘縰sing 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>
+    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;
+
+        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 readonly int refreshInterval;
+
+        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>();
+
+        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, float titleSize)
+        {
+            BaseConfig config = new BaseConfig();
+            this.title = title;
+            this.maxSize = config.MaxSize;
+            this.multi = multi;
+            this.refreshInterval = config.RefreshInterval;
+            this.fontSize = titleSize;
+
+
+            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);
+            }
+            else
+            {
+                xData = new Queue<long>(maxSize);
+                yData = new Queue<double>(maxSize);
+            }
+
+            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();
+            //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, 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)
+            {
+                RefreshData();
+            }
+        }
+
+        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()
+        {
+            bool flag = timer.Enabled;
+            try
+            {
+                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();
+            }
+            finally
+            {
+                timer.Enabled = flag;
+            }
+        }
+
+        public void Clear()
+        {
+            this.maxYValue = -1;
+            this.minYValue = double.MaxValue;
+            foreach (var name in loggers.Keys)
+            {
+                loggers[name].Clear();
+                xValues?[name]?.Clear();
+                yValues?[name]?.Clear();
+            }
+            xData?.Clear();
+            yData?.Clear();
+            chart.Refresh();
+        }
+
+        public List<double> GetSingleData()
+        {
+            bool flag = timer.Enabled;
+            try
+            {
+                timer.Enabled = false;
+                return yData?.ToList();
+            }
+            finally
+            {
+                timer.Enabled = flag;
+            }
+        }
+
+        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(double y)
+        {
+            if (this.multi)
+            {
+                return;
+            }
+            var commonName = "Single";
+            this.maxYValue = y > maxYValue ? y : maxYValue;
+            this.minYValue = y < minYValue ? y : minYValue;
+
+            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));
+
+            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(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)
+        {
+            //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;
+            }
+        }
+    }
+}

--
Gitblit v1.9.1