GUI/PlotPanel.cs
author moel.mich
Sun, 09 Jun 2013 16:53:16 +0000
changeset 398 ac9b3b647906
parent 397 243b6d5afa7c
child 400 f4e2e3e69651
permissions -rw-r--r--
Small correction to the plot with multiple axes.
     1 /*
     2  
     3   This Source Code Form is subject to the terms of the Mozilla Public
     4   License, v. 2.0. If a copy of the MPL was not distributed with this
     5   file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  
     7   Copyright (C) 2009-2013 Michael Möller <mmoeller@openhardwaremonitor.org>
     8 	
     9 */
    10 
    11 using System;
    12 using System.Collections.Generic;
    13 using System.Drawing;
    14 using System.Linq;
    15 using System.Windows.Forms;
    16 using OpenHardwareMonitor.Hardware;
    17 using OxyPlot;
    18 using OxyPlot.Axes;
    19 using OxyPlot.WindowsForms;
    20 using OxyPlot.Series;
    21 using OpenHardwareMonitor.Collections;
    22 
    23 namespace OpenHardwareMonitor.GUI {
    24   public class PlotPanel : UserControl {
    25 
    26     private PersistentSettings settings;
    27 
    28     private readonly Plot plot;
    29     private readonly PlotModel model;
    30     private readonly TimeSpanAxis timeAxis = new TimeSpanAxis();
    31     private readonly SortedDictionary<SensorType, LinearAxis> axes =
    32       new SortedDictionary<SensorType, LinearAxis>();
    33 
    34     private UserOption stackedAxes;
    35 
    36     private DateTime now;
    37 
    38     public PlotPanel(PersistentSettings settings) {
    39       this.settings = settings;
    40       this.model = CreatePlotModel();
    41 
    42       this.plot = new Plot();
    43       this.plot.Dock = DockStyle.Fill;
    44       this.plot.Model = model;
    45       this.plot.BackColor = Color.White;
    46       this.plot.ContextMenu = CreateMenu();
    47 
    48       UpdateAxesPosition();
    49 
    50       this.SuspendLayout();
    51       this.Controls.Add(plot);
    52       this.ResumeLayout(true);
    53     }
    54 
    55     public void SetCurrentSettings() {
    56       settings.SetValue("plotPanel.MinTimeSpan", (float)timeAxis.ViewMinimum);
    57       settings.SetValue("plotPanel.MaxTimeSpan", (float)timeAxis.ViewMaximum);
    58 
    59       foreach (var axis in axes.Values) {
    60         settings.SetValue("plotPanel.Min" + axis.Key, (float)axis.ViewMinimum);
    61         settings.SetValue("plotPanel.Max" + axis.Key, (float)axis.ViewMaximum);
    62       }
    63     }
    64 
    65     private ContextMenu CreateMenu() {
    66       ContextMenu menu = new ContextMenu();
    67 
    68       MenuItem stackedAxesMenuItem = new MenuItem("Stacked Axes");
    69       stackedAxes = new UserOption("stackedAxes", true,
    70         stackedAxesMenuItem, settings);
    71       stackedAxes.Changed += (sender, e) => {
    72         UpdateAxesPosition();
    73         InvalidatePlot();
    74       };
    75       menu.MenuItems.Add(stackedAxesMenuItem);
    76 
    77       MenuItem timeWindow = new MenuItem("Time Window");
    78       MenuItem[] timeWindowMenuItems =
    79         { new MenuItem("Auto", 
    80             (s, e) => { timeAxis.Zoom(0, double.NaN); InvalidatePlot(); }),
    81           new MenuItem("5 min", 
    82             (s, e) => { timeAxis.Zoom(0, 5 * 60); InvalidatePlot(); }),
    83           new MenuItem("10 min", 
    84             (s, e) => { timeAxis.Zoom(0, 10 * 60); InvalidatePlot(); }),
    85           new MenuItem("20 min", 
    86             (s, e) => { timeAxis.Zoom(0, 20 * 60); InvalidatePlot(); }),
    87           new MenuItem("30 min", 
    88             (s, e) => { timeAxis.Zoom(0, 30 * 60); InvalidatePlot(); }),
    89           new MenuItem("45 min", 
    90             (s, e) => { timeAxis.Zoom(0, 45 * 60); InvalidatePlot(); }),
    91           new MenuItem("1 h", 
    92             (s, e) => { timeAxis.Zoom(0, 60 * 60); InvalidatePlot(); }),
    93           new MenuItem("1.5 h", 
    94             (s, e) => { timeAxis.Zoom(0, 1.5 * 60 * 60); InvalidatePlot(); }),
    95           new MenuItem("2 h", 
    96             (s, e) => { timeAxis.Zoom(0, 2 * 60 * 60); InvalidatePlot(); }),
    97           new MenuItem("3 h", 
    98             (s, e) => { timeAxis.Zoom(0, 3 * 60 * 60); InvalidatePlot(); }),
    99           new MenuItem("6 h", 
   100             (s, e) => { timeAxis.Zoom(0, 6 * 60 * 60); InvalidatePlot(); }),
   101           new MenuItem("12 h", 
   102             (s, e) => { timeAxis.Zoom(0, 12 * 60 * 60); InvalidatePlot(); }),
   103           new MenuItem("24 h", 
   104             (s, e) => { timeAxis.Zoom(0, 24 * 60 * 60); InvalidatePlot(); }) };
   105       foreach (MenuItem mi in timeWindowMenuItems)
   106         timeWindow.MenuItems.Add(mi);
   107       menu.MenuItems.Add(timeWindow);
   108 
   109       return menu;
   110     }
   111 
   112     private PlotModel CreatePlotModel() {
   113 
   114       timeAxis.Position = AxisPosition.Bottom;
   115       timeAxis.MajorGridlineStyle = LineStyle.Solid;
   116       timeAxis.MajorGridlineThickness = 1;
   117       timeAxis.MajorGridlineColor = OxyColor.FromRgb(192, 192, 192);
   118       timeAxis.MinorGridlineStyle = LineStyle.Solid;
   119       timeAxis.MinorGridlineThickness = 1;
   120       timeAxis.MinorGridlineColor = OxyColor.FromRgb(232, 232, 232);
   121       timeAxis.StartPosition = 1;
   122       timeAxis.EndPosition = 0;
   123       timeAxis.MinimumPadding = 0;
   124       timeAxis.MaximumPadding = 0;
   125       timeAxis.AbsoluteMinimum = 0;
   126       timeAxis.Minimum = 0;
   127       timeAxis.AbsoluteMaximum = 24 * 60 * 60;
   128       timeAxis.Zoom(
   129         settings.GetValue("plotPanel.MinTimeSpan", 0.0f),
   130         settings.GetValue("plotPanel.MaxTimeSpan", 10.0f * 60));
   131       timeAxis.StringFormat = "h:mm";
   132 
   133       var units = new Dictionary<SensorType, string>();
   134       units.Add(SensorType.Voltage, "V");
   135       units.Add(SensorType.Clock, "MHz");
   136       units.Add(SensorType.Temperature, "°C");
   137       units.Add(SensorType.Load, "%");
   138       units.Add(SensorType.Fan, "RPM");
   139       units.Add(SensorType.Flow, "L/h");
   140       units.Add(SensorType.Control, "%");
   141       units.Add(SensorType.Level, "%");
   142       units.Add(SensorType.Factor, "1");
   143       units.Add(SensorType.Power, "W");
   144       units.Add(SensorType.Data, "GB");
   145 
   146       foreach (SensorType type in Enum.GetValues(typeof(SensorType))) {
   147         var axis = new LinearAxis();
   148         axis.Position = AxisPosition.Left;
   149         axis.MajorGridlineStyle = LineStyle.Solid;
   150         axis.MajorGridlineThickness = 1;
   151         axis.MajorGridlineColor = timeAxis.MajorGridlineColor;
   152         axis.MinorGridlineStyle = LineStyle.Solid;
   153         axis.MinorGridlineThickness = 1;
   154         axis.MinorGridlineColor = timeAxis.MinorGridlineColor;
   155         axis.AxislineStyle = LineStyle.Solid;
   156         axis.Title = type.ToString();
   157         axis.Key = type.ToString();
   158 
   159         axis.Zoom(
   160           settings.GetValue("plotPanel.Min" + axis.Key, float.NaN),
   161           settings.GetValue("plotPanel.Max" + axis.Key, float.NaN));
   162 
   163         if (units.ContainsKey(type))
   164           axis.Unit = units[type];
   165         axes.Add(type, axis);
   166       }
   167 
   168       var model = new PlotModel();
   169       model.Axes.Add(timeAxis);
   170       foreach (var axis in axes.Values)
   171         model.Axes.Add(axis);
   172       model.PlotMargins = new OxyThickness(0);
   173       model.IsLegendVisible = false;
   174 
   175       return model;
   176     }
   177 
   178     public void SetSensors(List<ISensor> sensors,
   179       IDictionary<ISensor, Color> colors) {
   180       this.model.Series.Clear();
   181 
   182       ListSet<SensorType> types = new ListSet<SensorType>();
   183 
   184       foreach (ISensor sensor in sensors) {
   185         var series = new LineSeries();
   186         series.ItemsSource = sensor.Values.Select(value => new DataPoint {
   187           X = (now - value.Time).TotalSeconds, Y = value.Value
   188         });
   189         series.Color = colors[sensor].ToOxyColor();
   190         series.StrokeThickness = 1;
   191         series.YAxisKey = axes[sensor.SensorType].Key;
   192         series.Title = sensor.Hardware.Name + " " + sensor.Name;
   193         this.model.Series.Add(series);
   194 
   195         types.Add(sensor.SensorType);
   196       }
   197 
   198       foreach (var pair in axes.Reverse()) {
   199         var axis = pair.Value;
   200         var type = pair.Key;
   201         axis.IsAxisVisible = types.Contains(type);     
   202       } 
   203 
   204       UpdateAxesPosition();
   205       InvalidatePlot();
   206     }
   207 
   208     private void UpdateAxesPosition() {
   209       if (stackedAxes.Value) {
   210         var count = axes.Values.Count(axis => axis.IsAxisVisible);
   211         var start = 0.0;
   212         foreach (var pair in axes.Reverse()) {
   213           var axis = pair.Value;
   214           var type = pair.Key;
   215           axis.StartPosition = start;
   216           var delta = axis.IsAxisVisible ? 1.0 / count : 0;
   217           start += delta;
   218           axis.EndPosition = start;
   219           axis.PositionTier = 0;
   220           axis.MajorGridlineStyle = LineStyle.Solid;
   221           axis.MinorGridlineStyle = LineStyle.Solid;   
   222         }
   223       } else {
   224         var tier = 0;
   225         foreach (var pair in axes.Reverse()) {
   226           var axis = pair.Value;
   227           var type = pair.Key;
   228           axis.StartPosition = 0;
   229           axis.EndPosition = 1;
   230           axis.PositionTier = axis.IsAxisVisible ? tier : 0;
   231           if (axis.IsAxisVisible)
   232             tier++;
   233           axis.MajorGridlineStyle = LineStyle.None;
   234           axis.MinorGridlineStyle = LineStyle.None;          
   235         }
   236       }
   237 
   238     }
   239 
   240     public void InvalidatePlot() {
   241       this.now = DateTime.UtcNow;
   242       this.plot.InvalidatePlot(true);
   243     }
   244 
   245   }
   246 }