using guoke; using LiveCharts; using LiveCharts.Wpf; using System.Windows.Threading; namespace WpfApp.Services; public class ChartManager { private readonly Dispatcher dispatcher; private readonly LogService log; private readonly DatabaseService db; private readonly EventService even; private const string SENSOR_DATA_EVENT = "SensorDataUpdate"; // 最大保留点数 private const int MAX_POINTS = 20; // 每个图表的数据封装 private class ChartData { public ColumnSeries ColumnSeries; public ChartValues StandardMin = new ChartValues(); public ChartValues StandardAvg = new ChartValues(); public ChartValues StandardMax = new ChartValues(); public List Labels = new List(); } // 管理多个图表 private Dictionary charts = new Dictionary(); public ChartManager(Dispatcher uiDispatcher, LogService logService, DatabaseService databaseService, EventService eventService) { dispatcher = uiDispatcher; log = logService; db = databaseService; even = eventService; SubscribeToSensorDataEvents(); } /// /// 初始化图表(一次性设置标准线和柱状图) /// public void InitChart(CartesianChart chart) { dispatcher.Invoke(() => { if (chart == null) return; // 如果已经初始化过,先清除 if (charts.ContainsKey(chart)) { charts.Remove(chart); } var data = new ChartData(); data.ColumnSeries = new ColumnSeries { Title = "实时值", Values = new ChartValues() }; var line1 = new LineSeries { Title = "标准下限", Values = data.StandardMin }; var line2 = new LineSeries { Title = "标准均值", Values = data.StandardAvg }; var line3 = new LineSeries { Title = "标准上限", Values = data.StandardMax }; chart.Series = new SeriesCollection { data.ColumnSeries, line1, line2, line3 }; chart.AxisX.Clear(); chart.AxisY.Clear(); chart.AxisX.Add(new Axis { Title = "时间", Labels = data.Labels }); chart.AxisY.Add(new Axis { Title = "数值" }); charts[chart] = data; }); } /// /// 接收到传感器实时数据(单点更新) /// private void OnSensorDataReceived(object sender, GeneralEventArgs e) { if (e is SensorDataEventArgs sensorArgs) { string chartTitle = sensorArgs.ChartTitle; // 例如 "myChart1" double value = sensorArgs.SensorValue; string timeLabel = DateTime.Now.ToString("HH:mm:ss"); // 找到对应图表并更新 foreach (var chart in charts.Keys) { if (chart.Name == chartTitle) { UpdateChartPoint(chart, timeLabel, value); break; } } } } /// /// 更新单个图表的数据点(柱状图 + 标准线 + X轴标签) /// public void UpdateChartPoint(CartesianChart chart, string label, double value) { if (chart == null || !charts.TryGetValue(chart, out var data)) return; dispatcher.Invoke(() => { // 保留四位小数 double roundedValue = Math.Round(value, 4); data.ColumnSeries.Values.Add(roundedValue); // 对标准线固定值,强制 double data.StandardMin.Add(Math.Round((double)5, 4)); data.StandardAvg.Add(Math.Round((double)10, 4)); data.StandardMax.Add(Math.Round((double)30, 4)); data.Labels.Add(label); // 超过最大点数时,移除最旧的数据 if (data.ColumnSeries.Values.Count > MAX_POINTS) { data.ColumnSeries.Values.RemoveAt(0); data.StandardMin.RemoveAt(0); data.StandardAvg.RemoveAt(0); data.StandardMax.RemoveAt(0); data.Labels.RemoveAt(0); } // 刷新 X 轴标签 chart.AxisX[0].Labels = new List(data.Labels); }); } /// /// 手动添加数据到指定图表 /// public void AddData(CartesianChart chart, double value, string label) { UpdateChartPoint(chart, label, value); } /// /// 手动清除指定图表的数据 /// public void ClearChart(CartesianChart chart) { if (chart == null || !charts.TryGetValue(chart, out var data)) return; dispatcher.Invoke(() => { data.ColumnSeries.Values.Clear(); data.StandardMin.Clear(); data.StandardAvg.Clear(); data.StandardMax.Clear(); data.Labels.Clear(); chart.AxisX[0].Labels.Clear(); }); } /// /// 清除所有图表 /// public void ClearAllCharts() { foreach (var chart in charts.Keys) { ClearChart(chart); } } /// /// 订阅传感器数据事件 /// private void SubscribeToSensorDataEvents() { even?.AddEventHandler(SENSOR_DATA_EVENT, OnSensorDataReceived); } }