Use file-scoped namespaces (#842)
This commit is contained in:
@@ -17,403 +17,402 @@ using OxyPlot.Axes;
|
||||
using OxyPlot.WindowsForms;
|
||||
using OxyPlot.Series;
|
||||
|
||||
namespace LibreHardwareMonitor.UI
|
||||
namespace LibreHardwareMonitor.UI;
|
||||
|
||||
public class PlotPanel : UserControl
|
||||
{
|
||||
public class PlotPanel : UserControl
|
||||
private readonly PersistentSettings _settings;
|
||||
private readonly UnitManager _unitManager;
|
||||
private readonly PlotView _plot;
|
||||
private readonly PlotModel _model;
|
||||
private readonly TimeSpanAxis _timeAxis = new TimeSpanAxis();
|
||||
private readonly SortedDictionary<SensorType, LinearAxis> _axes = new SortedDictionary<SensorType, LinearAxis>();
|
||||
private readonly Dictionary<SensorType, LineAnnotation> _annotations = new Dictionary<SensorType, LineAnnotation>();
|
||||
private UserOption _stackedAxes;
|
||||
private UserOption _showAxesLabels;
|
||||
private UserOption _timeAxisEnableZoom;
|
||||
private UserOption _yAxesEnableZoom;
|
||||
private DateTime _now;
|
||||
private float _dpiX;
|
||||
private float _dpiY;
|
||||
private double _dpiXScale = 1;
|
||||
private double _dpiYScale = 1;
|
||||
private Point _rightClickEnter;
|
||||
private bool _cancelContextMenu = false;
|
||||
|
||||
public PlotPanel(PersistentSettings settings, UnitManager unitManager)
|
||||
{
|
||||
private readonly PersistentSettings _settings;
|
||||
private readonly UnitManager _unitManager;
|
||||
private readonly PlotView _plot;
|
||||
private readonly PlotModel _model;
|
||||
private readonly TimeSpanAxis _timeAxis = new TimeSpanAxis();
|
||||
private readonly SortedDictionary<SensorType, LinearAxis> _axes = new SortedDictionary<SensorType, LinearAxis>();
|
||||
private readonly Dictionary<SensorType, LineAnnotation> _annotations = new Dictionary<SensorType, LineAnnotation>();
|
||||
private UserOption _stackedAxes;
|
||||
private UserOption _showAxesLabels;
|
||||
private UserOption _timeAxisEnableZoom;
|
||||
private UserOption _yAxesEnableZoom;
|
||||
private DateTime _now;
|
||||
private float _dpiX;
|
||||
private float _dpiY;
|
||||
private double _dpiXScale = 1;
|
||||
private double _dpiYScale = 1;
|
||||
private Point _rightClickEnter;
|
||||
private bool _cancelContextMenu = false;
|
||||
_settings = settings;
|
||||
_unitManager = unitManager;
|
||||
|
||||
public PlotPanel(PersistentSettings settings, UnitManager unitManager)
|
||||
SetDpi();
|
||||
_model = CreatePlotModel();
|
||||
|
||||
_plot = new PlotView { Dock = DockStyle.Fill, Model = _model, BackColor = Color.White, ContextMenuStrip = CreateMenu() };
|
||||
_plot.MouseDown += (sender, e) =>
|
||||
{
|
||||
_settings = settings;
|
||||
_unitManager = unitManager;
|
||||
|
||||
SetDpi();
|
||||
_model = CreatePlotModel();
|
||||
|
||||
_plot = new PlotView { Dock = DockStyle.Fill, Model = _model, BackColor = Color.White, ContextMenuStrip = CreateMenu() };
|
||||
_plot.MouseDown += (sender, e) =>
|
||||
if (e.Button == MouseButtons.Right)
|
||||
{
|
||||
if (e.Button == MouseButtons.Right)
|
||||
{
|
||||
_rightClickEnter = e.Location;
|
||||
}
|
||||
};
|
||||
_plot.MouseMove += (sender, e) =>
|
||||
_rightClickEnter = e.Location;
|
||||
}
|
||||
};
|
||||
_plot.MouseMove += (sender, e) =>
|
||||
{
|
||||
if (e.Button == MouseButtons.Right)
|
||||
{
|
||||
if (e.Button == MouseButtons.Right)
|
||||
if (!_cancelContextMenu && e.Location.DistanceTo(_rightClickEnter) > 10.0f)
|
||||
{
|
||||
if (!_cancelContextMenu && e.Location.DistanceTo(_rightClickEnter) > 10.0f)
|
||||
{
|
||||
_cancelContextMenu = true;
|
||||
}
|
||||
_cancelContextMenu = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
UpdateAxesPosition();
|
||||
|
||||
SuspendLayout();
|
||||
Controls.Add(_plot);
|
||||
ResumeLayout(true);
|
||||
}
|
||||
|
||||
public void SetCurrentSettings()
|
||||
{
|
||||
foreach (LinearAxis axis in _axes.Values)
|
||||
{
|
||||
_settings.SetValue("plotPanel.Min" + axis.Key, (float)axis.ActualMinimum);
|
||||
_settings.SetValue("plotPanel.Max" + axis.Key, (float)axis.ActualMaximum);
|
||||
}
|
||||
_settings.SetValue("plotPanel.MinTimeSpan", (float)_timeAxis.ActualMinimum);
|
||||
_settings.SetValue("plotPanel.MaxTimeSpan", (float)_timeAxis.ActualMaximum);
|
||||
}
|
||||
|
||||
private ContextMenuStrip CreateMenu()
|
||||
{
|
||||
ContextMenuStrip menu = new ContextMenuStrip();
|
||||
menu.Opening += (sender, e) =>
|
||||
{
|
||||
if (_cancelContextMenu)
|
||||
{
|
||||
e.Cancel = true;
|
||||
_cancelContextMenu = false;
|
||||
}
|
||||
};
|
||||
|
||||
ToolStripMenuItem stackedAxesMenuItem = new ToolStripMenuItem("Stacked Axes");
|
||||
_stackedAxes = new UserOption("stackedAxes", true, stackedAxesMenuItem, _settings);
|
||||
_stackedAxes.Changed += (sender, e) =>
|
||||
{
|
||||
UpdateAxesPosition();
|
||||
InvalidatePlot();
|
||||
};
|
||||
menu.Items.Add(stackedAxesMenuItem);
|
||||
|
||||
SuspendLayout();
|
||||
Controls.Add(_plot);
|
||||
ResumeLayout(true);
|
||||
}
|
||||
ToolStripMenuItem showAxesLabelsMenuItem = new ToolStripMenuItem("Show Axes Labels");
|
||||
_showAxesLabels = new UserOption("showAxesLabels", true, showAxesLabelsMenuItem, _settings);
|
||||
_showAxesLabels.Changed += (sender, e) =>
|
||||
{
|
||||
if (_showAxesLabels.Value)
|
||||
_model.PlotMargins = new OxyThickness(double.NaN);
|
||||
else
|
||||
_model.PlotMargins = new OxyThickness(0);
|
||||
};
|
||||
menu.Items.Add(showAxesLabelsMenuItem);
|
||||
|
||||
public void SetCurrentSettings()
|
||||
ToolStripMenuItem timeAxisMenuItem = new ToolStripMenuItem("Time Axis");
|
||||
ToolStripMenuItem[] timeAxisMenuItems =
|
||||
{ new ToolStripMenuItem("Enable Zoom"),
|
||||
new ToolStripMenuItem("Auto", null, (s, e) => { TimeAxisZoom(0, double.NaN); }),
|
||||
new ToolStripMenuItem("5 min", null, (s, e) => { TimeAxisZoom(0, 5 * 60); }),
|
||||
new ToolStripMenuItem("10 min", null, (s, e) => { TimeAxisZoom(0, 10 * 60); }),
|
||||
new ToolStripMenuItem("20 min", null, (s, e) => { TimeAxisZoom(0, 20 * 60); }),
|
||||
new ToolStripMenuItem("30 min", null, (s, e) => { TimeAxisZoom(0, 30 * 60); }),
|
||||
new ToolStripMenuItem("45 min", null, (s, e) => { TimeAxisZoom(0, 45 * 60); }),
|
||||
new ToolStripMenuItem("1 h", null, (s, e) => { TimeAxisZoom(0, 60 * 60); }),
|
||||
new ToolStripMenuItem("1.5 h", null, (s, e) => { TimeAxisZoom(0, 1.5 * 60 * 60); }),
|
||||
new ToolStripMenuItem("2 h", null, (s, e) => { TimeAxisZoom(0, 2 * 60 * 60); }),
|
||||
new ToolStripMenuItem("3 h", null, (s, e) => { TimeAxisZoom(0, 3 * 60 * 60); }),
|
||||
new ToolStripMenuItem("6 h", null, (s, e) => { TimeAxisZoom(0, 6 * 60 * 60); }),
|
||||
new ToolStripMenuItem("12 h", null, (s, e) => { TimeAxisZoom(0, 12 * 60 * 60); }),
|
||||
new ToolStripMenuItem("24 h", null, (s, e) => { TimeAxisZoom(0, 24 * 60 * 60); }) };
|
||||
|
||||
foreach (ToolStripItem mi in timeAxisMenuItems)
|
||||
timeAxisMenuItem.DropDownItems.Add(mi);
|
||||
menu.Items.Add(timeAxisMenuItem);
|
||||
|
||||
_timeAxisEnableZoom = new UserOption("timeAxisEnableZoom", true, timeAxisMenuItems[0], _settings);
|
||||
_timeAxisEnableZoom.Changed += (sender, e) =>
|
||||
{
|
||||
_timeAxis.IsZoomEnabled = _timeAxisEnableZoom.Value;
|
||||
};
|
||||
|
||||
ToolStripMenuItem yAxesMenuItem = new ToolStripMenuItem("Value Axes");
|
||||
ToolStripMenuItem[] yAxesMenuItems =
|
||||
{ new ToolStripMenuItem("Enable Zoom"),
|
||||
new ToolStripMenuItem("Autoscale All", null, (s, e) => { AutoscaleAllYAxes(); }) };
|
||||
|
||||
foreach (ToolStripItem mi in yAxesMenuItems)
|
||||
yAxesMenuItem.DropDownItems.Add(mi);
|
||||
menu.Items.Add(yAxesMenuItem);
|
||||
|
||||
_yAxesEnableZoom = new UserOption("yAxesEnableZoom", true, yAxesMenuItems[0], _settings);
|
||||
_yAxesEnableZoom.Changed += (sender, e) =>
|
||||
{
|
||||
foreach (LinearAxis axis in _axes.Values)
|
||||
axis.IsZoomEnabled = _yAxesEnableZoom.Value;
|
||||
};
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
private PlotModel CreatePlotModel()
|
||||
{
|
||||
_timeAxis.Position = AxisPosition.Bottom;
|
||||
_timeAxis.MajorGridlineStyle = LineStyle.Solid;
|
||||
_timeAxis.MajorGridlineThickness = 1;
|
||||
_timeAxis.MajorGridlineColor = OxyColor.FromRgb(192, 192, 192);
|
||||
_timeAxis.MinorGridlineStyle = LineStyle.Solid;
|
||||
_timeAxis.MinorGridlineThickness = 1;
|
||||
_timeAxis.MinorGridlineColor = OxyColor.FromRgb(232, 232, 232);
|
||||
_timeAxis.StartPosition = 1;
|
||||
_timeAxis.EndPosition = 0;
|
||||
_timeAxis.MinimumPadding = 0;
|
||||
_timeAxis.MaximumPadding = 0;
|
||||
_timeAxis.AbsoluteMinimum = 0;
|
||||
_timeAxis.Minimum = 0;
|
||||
_timeAxis.AbsoluteMaximum = 24 * 60 * 60;
|
||||
_timeAxis.Zoom(
|
||||
_settings.GetValue("plotPanel.MinTimeSpan", 0.0f),
|
||||
_settings.GetValue("plotPanel.MaxTimeSpan", 10.0f * 60));
|
||||
_timeAxis.StringFormat = "h:mm";
|
||||
|
||||
var units = new Dictionary<SensorType, string>
|
||||
{
|
||||
{ SensorType.Voltage, "V" },
|
||||
{ SensorType.Current, "A" },
|
||||
{ SensorType.Clock, "MHz" },
|
||||
{ SensorType.Temperature, "°C" },
|
||||
{ SensorType.Load, "%" },
|
||||
{ SensorType.Fan, "RPM" },
|
||||
{ SensorType.Flow, "L/h" },
|
||||
{ SensorType.Control, "%" },
|
||||
{ SensorType.Level, "%" },
|
||||
{ SensorType.Factor, "1" },
|
||||
{ SensorType.Power, "W" },
|
||||
{ SensorType.Data, "GB" },
|
||||
{ SensorType.Frequency, "Hz" },
|
||||
{ SensorType.Energy, "mWh" },
|
||||
{ SensorType.Noise, "dBA" }
|
||||
};
|
||||
|
||||
foreach (SensorType type in Enum.GetValues(typeof(SensorType)))
|
||||
{
|
||||
string typeName = type.ToString();
|
||||
var axis = new LinearAxis
|
||||
{
|
||||
_settings.SetValue("plotPanel.Min" + axis.Key, (float)axis.ActualMinimum);
|
||||
_settings.SetValue("plotPanel.Max" + axis.Key, (float)axis.ActualMaximum);
|
||||
}
|
||||
_settings.SetValue("plotPanel.MinTimeSpan", (float)_timeAxis.ActualMinimum);
|
||||
_settings.SetValue("plotPanel.MaxTimeSpan", (float)_timeAxis.ActualMaximum);
|
||||
Position = AxisPosition.Left,
|
||||
MajorGridlineStyle = LineStyle.Solid,
|
||||
MajorGridlineThickness = 1,
|
||||
MajorGridlineColor = _timeAxis.MajorGridlineColor,
|
||||
MinorGridlineStyle = LineStyle.Solid,
|
||||
MinorGridlineThickness = 1,
|
||||
MinorGridlineColor = _timeAxis.MinorGridlineColor,
|
||||
AxislineStyle = LineStyle.Solid,
|
||||
Title = typeName,
|
||||
Key = typeName,
|
||||
};
|
||||
|
||||
var annotation = new LineAnnotation
|
||||
{
|
||||
Type = LineAnnotationType.Horizontal,
|
||||
ClipByXAxis = false,
|
||||
ClipByYAxis = false,
|
||||
LineStyle = LineStyle.Solid,
|
||||
Color = OxyColors.Black,
|
||||
YAxisKey = typeName,
|
||||
StrokeThickness = 2,
|
||||
};
|
||||
|
||||
axis.AxisChanged += (sender, args) => annotation.Y = axis.ActualMinimum;
|
||||
axis.TransformChanged += (sender, args) => annotation.Y = axis.ActualMinimum;
|
||||
|
||||
axis.Zoom(_settings.GetValue("plotPanel.Min" + axis.Key, float.NaN), _settings.GetValue("plotPanel.Max" + axis.Key, float.NaN));
|
||||
|
||||
if (units.ContainsKey(type))
|
||||
axis.Unit = units[type];
|
||||
|
||||
_axes.Add(type, axis);
|
||||
_annotations.Add(type, annotation);
|
||||
}
|
||||
|
||||
private ContextMenuStrip CreateMenu()
|
||||
var model = new ScaledPlotModel(_dpiXScale, _dpiYScale);
|
||||
model.Axes.Add(_timeAxis);
|
||||
foreach (LinearAxis axis in _axes.Values)
|
||||
model.Axes.Add(axis);
|
||||
model.IsLegendVisible = false;
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
private void SetDpi()
|
||||
{
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266(v=vs.85).aspx
|
||||
const int defaultDpi = 96;
|
||||
Graphics g = CreateGraphics();
|
||||
|
||||
try
|
||||
{
|
||||
ContextMenuStrip menu = new ContextMenuStrip();
|
||||
menu.Opening += (sender, e) =>
|
||||
{
|
||||
if (_cancelContextMenu)
|
||||
{
|
||||
e.Cancel = true;
|
||||
_cancelContextMenu = false;
|
||||
}
|
||||
};
|
||||
|
||||
ToolStripMenuItem stackedAxesMenuItem = new ToolStripMenuItem("Stacked Axes");
|
||||
_stackedAxes = new UserOption("stackedAxes", true, stackedAxesMenuItem, _settings);
|
||||
_stackedAxes.Changed += (sender, e) =>
|
||||
{
|
||||
UpdateAxesPosition();
|
||||
InvalidatePlot();
|
||||
};
|
||||
menu.Items.Add(stackedAxesMenuItem);
|
||||
|
||||
ToolStripMenuItem showAxesLabelsMenuItem = new ToolStripMenuItem("Show Axes Labels");
|
||||
_showAxesLabels = new UserOption("showAxesLabels", true, showAxesLabelsMenuItem, _settings);
|
||||
_showAxesLabels.Changed += (sender, e) =>
|
||||
{
|
||||
if (_showAxesLabels.Value)
|
||||
_model.PlotMargins = new OxyThickness(double.NaN);
|
||||
else
|
||||
_model.PlotMargins = new OxyThickness(0);
|
||||
};
|
||||
menu.Items.Add(showAxesLabelsMenuItem);
|
||||
|
||||
ToolStripMenuItem timeAxisMenuItem = new ToolStripMenuItem("Time Axis");
|
||||
ToolStripMenuItem[] timeAxisMenuItems =
|
||||
{ new ToolStripMenuItem("Enable Zoom"),
|
||||
new ToolStripMenuItem("Auto", null, (s, e) => { TimeAxisZoom(0, double.NaN); }),
|
||||
new ToolStripMenuItem("5 min", null, (s, e) => { TimeAxisZoom(0, 5 * 60); }),
|
||||
new ToolStripMenuItem("10 min", null, (s, e) => { TimeAxisZoom(0, 10 * 60); }),
|
||||
new ToolStripMenuItem("20 min", null, (s, e) => { TimeAxisZoom(0, 20 * 60); }),
|
||||
new ToolStripMenuItem("30 min", null, (s, e) => { TimeAxisZoom(0, 30 * 60); }),
|
||||
new ToolStripMenuItem("45 min", null, (s, e) => { TimeAxisZoom(0, 45 * 60); }),
|
||||
new ToolStripMenuItem("1 h", null, (s, e) => { TimeAxisZoom(0, 60 * 60); }),
|
||||
new ToolStripMenuItem("1.5 h", null, (s, e) => { TimeAxisZoom(0, 1.5 * 60 * 60); }),
|
||||
new ToolStripMenuItem("2 h", null, (s, e) => { TimeAxisZoom(0, 2 * 60 * 60); }),
|
||||
new ToolStripMenuItem("3 h", null, (s, e) => { TimeAxisZoom(0, 3 * 60 * 60); }),
|
||||
new ToolStripMenuItem("6 h", null, (s, e) => { TimeAxisZoom(0, 6 * 60 * 60); }),
|
||||
new ToolStripMenuItem("12 h", null, (s, e) => { TimeAxisZoom(0, 12 * 60 * 60); }),
|
||||
new ToolStripMenuItem("24 h", null, (s, e) => { TimeAxisZoom(0, 24 * 60 * 60); }) };
|
||||
|
||||
foreach (ToolStripItem mi in timeAxisMenuItems)
|
||||
timeAxisMenuItem.DropDownItems.Add(mi);
|
||||
menu.Items.Add(timeAxisMenuItem);
|
||||
|
||||
_timeAxisEnableZoom = new UserOption("timeAxisEnableZoom", true, timeAxisMenuItems[0], _settings);
|
||||
_timeAxisEnableZoom.Changed += (sender, e) =>
|
||||
{
|
||||
_timeAxis.IsZoomEnabled = _timeAxisEnableZoom.Value;
|
||||
};
|
||||
|
||||
ToolStripMenuItem yAxesMenuItem = new ToolStripMenuItem("Value Axes");
|
||||
ToolStripMenuItem[] yAxesMenuItems =
|
||||
{ new ToolStripMenuItem("Enable Zoom"),
|
||||
new ToolStripMenuItem("Autoscale All", null, (s, e) => { AutoscaleAllYAxes(); }) };
|
||||
|
||||
foreach (ToolStripItem mi in yAxesMenuItems)
|
||||
yAxesMenuItem.DropDownItems.Add(mi);
|
||||
menu.Items.Add(yAxesMenuItem);
|
||||
|
||||
_yAxesEnableZoom = new UserOption("yAxesEnableZoom", true, yAxesMenuItems[0], _settings);
|
||||
_yAxesEnableZoom.Changed += (sender, e) =>
|
||||
{
|
||||
foreach (LinearAxis axis in _axes.Values)
|
||||
axis.IsZoomEnabled = _yAxesEnableZoom.Value;
|
||||
};
|
||||
|
||||
return menu;
|
||||
_dpiX = g.DpiX;
|
||||
_dpiY = g.DpiY;
|
||||
}
|
||||
finally
|
||||
{
|
||||
g.Dispose();
|
||||
}
|
||||
|
||||
private PlotModel CreatePlotModel()
|
||||
{
|
||||
_timeAxis.Position = AxisPosition.Bottom;
|
||||
_timeAxis.MajorGridlineStyle = LineStyle.Solid;
|
||||
_timeAxis.MajorGridlineThickness = 1;
|
||||
_timeAxis.MajorGridlineColor = OxyColor.FromRgb(192, 192, 192);
|
||||
_timeAxis.MinorGridlineStyle = LineStyle.Solid;
|
||||
_timeAxis.MinorGridlineThickness = 1;
|
||||
_timeAxis.MinorGridlineColor = OxyColor.FromRgb(232, 232, 232);
|
||||
_timeAxis.StartPosition = 1;
|
||||
_timeAxis.EndPosition = 0;
|
||||
_timeAxis.MinimumPadding = 0;
|
||||
_timeAxis.MaximumPadding = 0;
|
||||
_timeAxis.AbsoluteMinimum = 0;
|
||||
_timeAxis.Minimum = 0;
|
||||
_timeAxis.AbsoluteMaximum = 24 * 60 * 60;
|
||||
_timeAxis.Zoom(
|
||||
_settings.GetValue("plotPanel.MinTimeSpan", 0.0f),
|
||||
_settings.GetValue("plotPanel.MaxTimeSpan", 10.0f * 60));
|
||||
_timeAxis.StringFormat = "h:mm";
|
||||
if (_dpiX > 0)
|
||||
_dpiXScale = _dpiX / defaultDpi;
|
||||
if (_dpiY > 0)
|
||||
_dpiYScale = _dpiY / defaultDpi;
|
||||
}
|
||||
|
||||
var units = new Dictionary<SensorType, string>
|
||||
public void SetSensors(List<ISensor> sensors, IDictionary<ISensor, Color> colors)
|
||||
{
|
||||
_model.Series.Clear();
|
||||
var types = new HashSet<SensorType>();
|
||||
|
||||
|
||||
DataPoint CreateDataPoint(SensorType type, SensorValue value)
|
||||
{
|
||||
float displayedValue;
|
||||
|
||||
if (type == SensorType.Temperature && _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit)
|
||||
{
|
||||
{ SensorType.Voltage, "V" },
|
||||
{ SensorType.Current, "A" },
|
||||
{ SensorType.Clock, "MHz" },
|
||||
{ SensorType.Temperature, "°C" },
|
||||
{ SensorType.Load, "%" },
|
||||
{ SensorType.Fan, "RPM" },
|
||||
{ SensorType.Flow, "L/h" },
|
||||
{ SensorType.Control, "%" },
|
||||
{ SensorType.Level, "%" },
|
||||
{ SensorType.Factor, "1" },
|
||||
{ SensorType.Power, "W" },
|
||||
{ SensorType.Data, "GB" },
|
||||
{ SensorType.Frequency, "Hz" },
|
||||
{ SensorType.Energy, "mWh" },
|
||||
{ SensorType.Noise, "dBA" }
|
||||
displayedValue = UnitManager.CelsiusToFahrenheit(value.Value).Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
displayedValue = value.Value;
|
||||
}
|
||||
|
||||
return new DataPoint((_now - value.Time).TotalSeconds, displayedValue);
|
||||
}
|
||||
|
||||
|
||||
foreach (ISensor sensor in sensors)
|
||||
{
|
||||
var series = new LineSeries
|
||||
{
|
||||
ItemsSource = sensor.Values.Select(value => CreateDataPoint(sensor.SensorType, value)),
|
||||
Color = colors[sensor].ToOxyColor(),
|
||||
StrokeThickness = 1,
|
||||
YAxisKey = _axes[sensor.SensorType].Key,
|
||||
Title = sensor.Hardware.Name + " " + sensor.Name
|
||||
};
|
||||
|
||||
foreach (SensorType type in Enum.GetValues(typeof(SensorType)))
|
||||
{
|
||||
string typeName = type.ToString();
|
||||
var axis = new LinearAxis
|
||||
{
|
||||
Position = AxisPosition.Left,
|
||||
MajorGridlineStyle = LineStyle.Solid,
|
||||
MajorGridlineThickness = 1,
|
||||
MajorGridlineColor = _timeAxis.MajorGridlineColor,
|
||||
MinorGridlineStyle = LineStyle.Solid,
|
||||
MinorGridlineThickness = 1,
|
||||
MinorGridlineColor = _timeAxis.MinorGridlineColor,
|
||||
AxislineStyle = LineStyle.Solid,
|
||||
Title = typeName,
|
||||
Key = typeName,
|
||||
};
|
||||
_model.Series.Add(series);
|
||||
|
||||
var annotation = new LineAnnotation
|
||||
{
|
||||
Type = LineAnnotationType.Horizontal,
|
||||
ClipByXAxis = false,
|
||||
ClipByYAxis = false,
|
||||
LineStyle = LineStyle.Solid,
|
||||
Color = OxyColors.Black,
|
||||
YAxisKey = typeName,
|
||||
StrokeThickness = 2,
|
||||
};
|
||||
|
||||
axis.AxisChanged += (sender, args) => annotation.Y = axis.ActualMinimum;
|
||||
axis.TransformChanged += (sender, args) => annotation.Y = axis.ActualMinimum;
|
||||
|
||||
axis.Zoom(_settings.GetValue("plotPanel.Min" + axis.Key, float.NaN), _settings.GetValue("plotPanel.Max" + axis.Key, float.NaN));
|
||||
|
||||
if (units.ContainsKey(type))
|
||||
axis.Unit = units[type];
|
||||
|
||||
_axes.Add(type, axis);
|
||||
_annotations.Add(type, annotation);
|
||||
}
|
||||
|
||||
var model = new ScaledPlotModel(_dpiXScale, _dpiYScale);
|
||||
model.Axes.Add(_timeAxis);
|
||||
foreach (LinearAxis axis in _axes.Values)
|
||||
model.Axes.Add(axis);
|
||||
model.IsLegendVisible = false;
|
||||
|
||||
return model;
|
||||
types.Add(sensor.SensorType);
|
||||
}
|
||||
|
||||
private void SetDpi()
|
||||
foreach (KeyValuePair<SensorType, LinearAxis> pair in _axes.Reverse())
|
||||
{
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266(v=vs.85).aspx
|
||||
const int defaultDpi = 96;
|
||||
Graphics g = CreateGraphics();
|
||||
|
||||
try
|
||||
{
|
||||
_dpiX = g.DpiX;
|
||||
_dpiY = g.DpiY;
|
||||
}
|
||||
finally
|
||||
{
|
||||
g.Dispose();
|
||||
}
|
||||
|
||||
if (_dpiX > 0)
|
||||
_dpiXScale = _dpiX / defaultDpi;
|
||||
if (_dpiY > 0)
|
||||
_dpiYScale = _dpiY / defaultDpi;
|
||||
LinearAxis axis = pair.Value;
|
||||
SensorType type = pair.Key;
|
||||
axis.IsAxisVisible = types.Contains(type);
|
||||
}
|
||||
|
||||
public void SetSensors(List<ISensor> sensors, IDictionary<ISensor, Color> colors)
|
||||
UpdateAxesPosition();
|
||||
InvalidatePlot();
|
||||
}
|
||||
|
||||
private void UpdateAxesPosition()
|
||||
{
|
||||
if (_stackedAxes.Value)
|
||||
{
|
||||
_model.Series.Clear();
|
||||
var types = new HashSet<SensorType>();
|
||||
|
||||
|
||||
DataPoint CreateDataPoint(SensorType type, SensorValue value)
|
||||
int count = _axes.Values.Count(axis => axis.IsAxisVisible);
|
||||
double start = 0.0;
|
||||
foreach (KeyValuePair<SensorType, LinearAxis> pair in _axes.Reverse())
|
||||
{
|
||||
float displayedValue;
|
||||
|
||||
if (type == SensorType.Temperature && _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit)
|
||||
{
|
||||
displayedValue = UnitManager.CelsiusToFahrenheit(value.Value).Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
displayedValue = value.Value;
|
||||
}
|
||||
|
||||
return new DataPoint((_now - value.Time).TotalSeconds, displayedValue);
|
||||
}
|
||||
|
||||
|
||||
foreach (ISensor sensor in sensors)
|
||||
{
|
||||
var series = new LineSeries
|
||||
{
|
||||
ItemsSource = sensor.Values.Select(value => CreateDataPoint(sensor.SensorType, value)),
|
||||
Color = colors[sensor].ToOxyColor(),
|
||||
StrokeThickness = 1,
|
||||
YAxisKey = _axes[sensor.SensorType].Key,
|
||||
Title = sensor.Hardware.Name + " " + sensor.Name
|
||||
};
|
||||
|
||||
_model.Series.Add(series);
|
||||
|
||||
types.Add(sensor.SensorType);
|
||||
LinearAxis axis = pair.Value;
|
||||
axis.StartPosition = start;
|
||||
double delta = axis.IsAxisVisible ? 1.0 / count : 0;
|
||||
start += delta;
|
||||
axis.EndPosition = start;
|
||||
axis.PositionTier = 0;
|
||||
axis.MajorGridlineStyle = LineStyle.Solid;
|
||||
axis.MinorGridlineStyle = LineStyle.Solid;
|
||||
LineAnnotation annotation = _annotations[pair.Key];
|
||||
annotation.Y = axis.ActualMinimum;
|
||||
if (!_model.Annotations.Contains(annotation))
|
||||
_model.Annotations.Add(annotation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int tier = 0;
|
||||
|
||||
foreach (KeyValuePair<SensorType, LinearAxis> pair in _axes.Reverse())
|
||||
{
|
||||
LinearAxis axis = pair.Value;
|
||||
SensorType type = pair.Key;
|
||||
axis.IsAxisVisible = types.Contains(type);
|
||||
}
|
||||
|
||||
UpdateAxesPosition();
|
||||
InvalidatePlot();
|
||||
}
|
||||
|
||||
private void UpdateAxesPosition()
|
||||
{
|
||||
if (_stackedAxes.Value)
|
||||
{
|
||||
int count = _axes.Values.Count(axis => axis.IsAxisVisible);
|
||||
double start = 0.0;
|
||||
foreach (KeyValuePair<SensorType, LinearAxis> pair in _axes.Reverse())
|
||||
if (axis.IsAxisVisible)
|
||||
{
|
||||
LinearAxis axis = pair.Value;
|
||||
axis.StartPosition = start;
|
||||
double delta = axis.IsAxisVisible ? 1.0 / count : 0;
|
||||
start += delta;
|
||||
axis.EndPosition = start;
|
||||
axis.StartPosition = 0;
|
||||
axis.EndPosition = 1;
|
||||
axis.PositionTier = tier;
|
||||
tier++;
|
||||
}
|
||||
else
|
||||
{
|
||||
axis.StartPosition = 0;
|
||||
axis.EndPosition = 0;
|
||||
axis.PositionTier = 0;
|
||||
axis.MajorGridlineStyle = LineStyle.Solid;
|
||||
axis.MinorGridlineStyle = LineStyle.Solid;
|
||||
LineAnnotation annotation = _annotations[pair.Key];
|
||||
annotation.Y = axis.ActualMinimum;
|
||||
if (!_model.Annotations.Contains(annotation))
|
||||
_model.Annotations.Add(annotation);
|
||||
}
|
||||
axis.MajorGridlineStyle = LineStyle.None;
|
||||
axis.MinorGridlineStyle = LineStyle.None;
|
||||
LineAnnotation annotation = _annotations[pair.Key];
|
||||
if (_model.Annotations.Contains(annotation))
|
||||
_model.Annotations.Remove(_annotations[pair.Key]);
|
||||
}
|
||||
else
|
||||
{
|
||||
int tier = 0;
|
||||
|
||||
foreach (KeyValuePair<SensorType, LinearAxis> pair in _axes.Reverse())
|
||||
{
|
||||
LinearAxis axis = pair.Value;
|
||||
|
||||
if (axis.IsAxisVisible)
|
||||
{
|
||||
axis.StartPosition = 0;
|
||||
axis.EndPosition = 1;
|
||||
axis.PositionTier = tier;
|
||||
tier++;
|
||||
}
|
||||
else
|
||||
{
|
||||
axis.StartPosition = 0;
|
||||
axis.EndPosition = 0;
|
||||
axis.PositionTier = 0;
|
||||
}
|
||||
axis.MajorGridlineStyle = LineStyle.None;
|
||||
axis.MinorGridlineStyle = LineStyle.None;
|
||||
LineAnnotation annotation = _annotations[pair.Key];
|
||||
if (_model.Annotations.Contains(annotation))
|
||||
_model.Annotations.Remove(_annotations[pair.Key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void InvalidatePlot()
|
||||
{
|
||||
_now = DateTime.UtcNow;
|
||||
|
||||
if (_axes != null)
|
||||
{
|
||||
foreach (KeyValuePair<SensorType, LinearAxis> pair in _axes)
|
||||
{
|
||||
LinearAxis axis = pair.Value;
|
||||
SensorType type = pair.Key;
|
||||
if (type == SensorType.Temperature)
|
||||
axis.Unit = _unitManager.TemperatureUnit == TemperatureUnit.Celsius ? "°C" : "°F";
|
||||
|
||||
if (!_stackedAxes.Value)
|
||||
continue;
|
||||
|
||||
var annotation = _annotations[pair.Key];
|
||||
annotation.Y = axis.ActualMaximum;
|
||||
}
|
||||
}
|
||||
|
||||
_plot?.InvalidatePlot(true);
|
||||
}
|
||||
|
||||
public void TimeAxisZoom(double min, double max)
|
||||
{
|
||||
bool timeAxisIsZoomEnabled = _timeAxis.IsZoomEnabled;
|
||||
|
||||
_timeAxis.IsZoomEnabled = true;
|
||||
_timeAxis.Zoom(min, max);
|
||||
InvalidatePlot();
|
||||
_timeAxis.IsZoomEnabled = timeAxisIsZoomEnabled;
|
||||
}
|
||||
|
||||
public void AutoscaleAllYAxes()
|
||||
{
|
||||
foreach (LinearAxis axis in _axes.Values)
|
||||
axis.Zoom(double.NaN, double.NaN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void InvalidatePlot()
|
||||
{
|
||||
_now = DateTime.UtcNow;
|
||||
|
||||
if (_axes != null)
|
||||
{
|
||||
foreach (KeyValuePair<SensorType, LinearAxis> pair in _axes)
|
||||
{
|
||||
LinearAxis axis = pair.Value;
|
||||
SensorType type = pair.Key;
|
||||
if (type == SensorType.Temperature)
|
||||
axis.Unit = _unitManager.TemperatureUnit == TemperatureUnit.Celsius ? "°C" : "°F";
|
||||
|
||||
if (!_stackedAxes.Value)
|
||||
continue;
|
||||
|
||||
var annotation = _annotations[pair.Key];
|
||||
annotation.Y = axis.ActualMaximum;
|
||||
}
|
||||
}
|
||||
|
||||
_plot?.InvalidatePlot(true);
|
||||
}
|
||||
|
||||
public void TimeAxisZoom(double min, double max)
|
||||
{
|
||||
bool timeAxisIsZoomEnabled = _timeAxis.IsZoomEnabled;
|
||||
|
||||
_timeAxis.IsZoomEnabled = true;
|
||||
_timeAxis.Zoom(min, max);
|
||||
InvalidatePlot();
|
||||
_timeAxis.IsZoomEnabled = timeAxisIsZoomEnabled;
|
||||
}
|
||||
|
||||
public void AutoscaleAllYAxes()
|
||||
{
|
||||
foreach (LinearAxis axis in _axes.Values)
|
||||
axis.Zoom(double.NaN, double.NaN);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user