using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; using System.Windows.Threading; namespace OpenFaceDemo { public class DataPoint { public DataPoint() { Time = TimeSeriesPlot.CurrentTime; } public DateTime Time { get; set; } public Dictionary values = new Dictionary(); public double Confidence { get; set; } } /// /// Interaction logic for TimeSeriesPlot.xaml /// public partial class TimeSeriesPlot : UserControl { #region High-Resolution Timing static DateTime startTime; static Stopwatch sw = new Stopwatch(); static TimeSeriesPlot() { startTime = DateTime.Now; sw.Start(); } public static DateTime CurrentTime { get { return startTime + sw.Elapsed; } } #endregion public Orientation Orientation { get; set; } public bool ShowLegend { get; set; } Queue dataPoints = new Queue(); TimeSpan historyLength = TimeSpan.FromSeconds(10); Dictionary brushes = new Dictionary(); Dictionary brush_thicknesses = new Dictionary(); Dictionary line_names = new Dictionary(); Dictionary brush_colors = new Dictionary(); public TimeSeriesPlot() { InitializeComponent(); ShowLegend = false; ClipToBounds = true; DispatcherTimer dt = new DispatcherTimer(TimeSpan.FromMilliseconds(20), DispatcherPriority.Background, Timer_Tick, Dispatcher); } private void PruneData() { lock (dataPoints) { while (dataPoints.Count > 0 && dataPoints.Peek().Time < CurrentTime - historyLength - TimeSpan.FromSeconds(2)) dataPoints.Dequeue(); } } public void AddDataPoint(DataPoint dp) { lock (dataPoints) dataPoints.Enqueue(dp); } private void Timer_Tick(object sender, EventArgs e) { PruneData(); if (this.IsVisible) InvalidateVisual(); } private FormattedText FT(string text, int size) { return new FormattedText(text, System.Globalization.CultureInfo.CurrentCulture, System.Windows.FlowDirection.LeftToRight, new Typeface("Verdana"), size, Brushes.Black); } public void AssocColor(int seriesId, Color b) { Color bTransparent = b; bTransparent.A = 0; GradientStopCollection gs = new GradientStopCollection(); gs.Add(new GradientStop(bTransparent, 0)); gs.Add(new GradientStop(b, 0.2)); LinearGradientBrush g = new LinearGradientBrush(gs, new Point(0, 0), Orientation == System.Windows.Controls.Orientation.Horizontal ? new Point(ActualWidth, 0) : new Point(0, ActualHeight)); g.MappingMode = BrushMappingMode.Absolute; g.Freeze(); brushes[seriesId] = g; brush_colors[seriesId] = b; } public void AssocThickness(int seriesId, int thickness) { brush_thicknesses[seriesId] = thickness; } public void AssocName(int seriesId, String name) { line_names[seriesId] = name; } protected override void OnRender(DrawingContext dc) { base.OnRender(dc); DataPoint[] localPoints; lock (dataPoints) localPoints = dataPoints.ToArray(); var pfs = new Dictionary(); for (int i = 0; i < localPoints.Length; i++) { var ptTime = localPoints[i].Time; var ptAge = (DateTime.Now - ptTime).TotalSeconds; foreach (var kvp in localPoints[i].values) { var seriesId = kvp.Key; double v = Math.Min(Math.Max(kvp.Value, 0), 1); double x = 0; double y = 0; if (Orientation == System.Windows.Controls.Orientation.Horizontal) { x = ActualWidth - (CurrentTime - localPoints[i].Time).TotalMilliseconds * (ActualWidth / historyLength.TotalMilliseconds); y = ActualHeight - ActualHeight * v; } else { y = ActualHeight - (CurrentTime - localPoints[i].Time).TotalMilliseconds * (ActualHeight / historyLength.TotalMilliseconds); x = ActualWidth * v; } if (!pfs.ContainsKey(seriesId)) { pfs[seriesId] = new PathFigure(); pfs[seriesId].IsClosed = false; pfs[seriesId].StartPoint = new Point(x, y); } else { pfs[seriesId].Segments.Add(new LineSegment(new Point(x, y), true)); } } } foreach (var kvp in pfs) { var seriesId = kvp.Key; var pf = kvp.Value; Brush b = brushes.ContainsKey(seriesId) ? brushes[seriesId] : Brushes.Black; int thickness = brush_thicknesses.ContainsKey(seriesId) ? brush_thicknesses[seriesId] : 2; PathGeometry pg = new PathGeometry(new PathFigure[] { pf }); Pen p = new Pen(b, thickness); if (line_names.ContainsKey(seriesId) && line_names[seriesId].CompareTo("State rapport") == 0) { double[] dashValues = { 5.0, 5.0, 5.0 }; p.DashStyle = new System.Windows.Media.DashStyle(dashValues, 0); } dc.DrawGeometry(null, p, pg); } if (ShowLegend && line_names.Count > 0) { int height_one = 18; int height = height_one * line_names.Count; Pen p = new Pen(Brushes.Black, 1); Brush legend_b = new SolidColorBrush(Color.FromRgb(255, 255, 255)); dc.DrawRectangle(legend_b, p, new Rect(0, 1, 100, height)); int i = 0; foreach (var key_name_pair in line_names) { var line_name = key_name_pair.Value; FormattedText ft = FT(line_name, 11); // Draw the text dc.DrawText(ft, new Point(15, 1 + height_one * i)); // Draw example lines Brush legend_c = new SolidColorBrush(brush_colors[key_name_pair.Key]); Pen p_line = new Pen(legend_c, brush_thicknesses[key_name_pair.Key]); dc.DrawLine(p_line, new Point(0, 1 + height_one * i + height_one / 2), new Point(14, 1 + height_one * i + height_one / 2)); i++; } } } } }