internal void Draw() { if (!IsControlLaoded) return; //No cache for you gauge :( kill and redraw please foreach (var child in Canvas.Children .Where(x => !Equals(x, Stick) && !(x is AngularSection) && !(x is PieSlice)).ToArray()) Canvas.Children.Remove(child); Wedge = Wedge > 360 ? 360 : (Wedge < 0 ? 0 : Wedge); var fromAlpha = (360-Wedge)*.5; var toAlpha = 360 - fromAlpha; var d = ActualWidth < ActualHeight ? ActualWidth : ActualHeight; Stick.Height = d*.5*.8; Stick.Width = Stick.Height*.2; Canvas.SetLeft(Stick, ActualWidth*.5 - Stick.Width*.5); Canvas.SetTop(Stick, ActualHeight*.5 - Stick.Height*.9); var ticksHi = d*.5; var ticksHj = d*.47; var labelsHj = d*.44; foreach (var section in Sections) { PieSlice slice; section.Owner = this; if (!Slices.TryGetValue(section, out slice)) { slice = new PieSlice(); Slices[section] = slice; } var p = (Canvas) section.Parent; p?.Children.Remove(section); Canvas.Children.Add(section); var ps = (Canvas) slice.Parent; ps?.Children.Remove(slice); Canvas.Children.Add(slice); } UpdateSections(); for (var i = FromValue; i <= ToValue; i += TicksStep) { var alpha = LinearInterpolation(fromAlpha, toAlpha, FromValue, ToValue, i) + 90; var tick = new Line { X1 = ActualWidth*.5 + ticksHi*Math.Cos(alpha*Math.PI/180), X2 = ActualWidth*.5 + ticksHj*Math.Cos(alpha*Math.PI/180), Y1 = ActualHeight*.5 + ticksHi*Math.Sin(alpha*Math.PI/180), Y2 = ActualHeight*.5 + ticksHj*Math.Sin(alpha*Math.PI/180) }; Canvas.Children.Add(tick); tick.SetBinding(Shape.StrokeProperty, new Binding {Path = new PropertyPath("TicksForeground"), Source = this}); tick.SetBinding(Shape.StrokeThicknessProperty, new Binding { Path = new PropertyPath("TicksStrokeThickness"), Source = this }); } for (var i = FromValue; i <= ToValue; i += LabelsStep) { var alpha = LinearInterpolation(fromAlpha, toAlpha, FromValue, ToValue, i) + 90; var tick = new Line { X1 = ActualWidth*.5 + ticksHi*Math.Cos(alpha*Math.PI/180), X2 = ActualWidth*.5 + labelsHj*Math.Cos(alpha*Math.PI/180), Y1 = ActualHeight*.5 + ticksHi*Math.Sin(alpha*Math.PI/180), Y2 = ActualHeight*.5 + labelsHj*Math.Sin(alpha*Math.PI/180) }; Canvas.Children.Add(tick); var label = new TextBlock { Text = LabelFormatter(i) }; //label.SetBinding(EffectProperty, //new Binding {Path = new PropertyPath("LabelsEffect"), Source = this}); Canvas.Children.Add(label); label.UpdateLayout(); Canvas.SetLeft(label, alpha < 270 ? tick.X2 : (Math.Abs(alpha - 270) < 4 ? tick.X2 - label.ActualWidth*.5 : tick.X2 - label.ActualWidth)); Canvas.SetTop(label, tick.Y2); tick.SetBinding(Shape.StrokeProperty, new Binding { Path = new PropertyPath("TicksForeground"), Source = this }); tick.SetBinding(Shape.StrokeThicknessProperty, new Binding { Path = new PropertyPath("TicksStrokeThickness"), Source = this }); } MoveStick(); }
/// <summary> /// Clears existing content then calculates new UI elements of the <see cref="Graph"/> /// for the current <see cref="BarometerTestUIModel.Graph"/>. /// </summary> private void DrawGraph() { // Initialize Graph.Children.Clear(); // Calculate range and average var count = Model.Graph.Count; if (count == 0) { // Nothing to draw return; } var pressureMin = (double?)null; var pressureMax = (double?)null; var temperatureMin = (double?)null; var temperatureMax = (double?)null; var pressureTotal = (double?)null; var temperatureTotal = (double?)null; foreach (var point in Model.Graph) { var pressure = point.Pressure; if (!pressureMax.HasValue || pressure > pressureMax) pressureMax = pressure; if (!pressureMin.HasValue || pressure < pressureMin) pressureMin = pressure; pressureTotal = (pressureTotal ?? 0) + pressure; var temperature = point.Temperature; if (!temperatureMax.HasValue || temperature > temperatureMax) temperatureMax = temperature; if (!temperatureMin.HasValue || temperature < temperatureMin) temperatureMin = temperature; temperatureTotal = (temperatureTotal ?? 0) + temperature; } var pressureRange = (pressureMax ?? 0) - (pressureMin ?? 0); var pressureAverage = pressureTotal / count; var temperatureRange = (temperatureMax ?? 0) - (temperatureMin ?? 0); var temperatureAverage = temperatureTotal / count; // Calculate metrics Graph.UpdateLayout(); var height = Graph.ActualHeight; var drawHeight = height - (GraphPadding * 2); var width = Graph.ActualWidth; var drawWidth = width - (GraphPadding * 2); var graphYMax = GraphPadding + drawHeight; Func<double, double, double, double> calculateGraphY = (double value, double minimum, double range) => { if (range > 0) { // Relative within range return graphYMax - (drawHeight * ((value - minimum) / range)); } else { // Middle when flat line return graphYMax - (drawHeight / 2); } }; // Get resources var pressureBrush = (SolidColorBrush)Resources["GraphPressureBrush"]; var temperatureBrush = (SolidColorBrush)Resources["GraphTemperatureBrush"]; // Draw pressure average lines var pressureAverageY = calculateGraphY(pressureAverage.Value, pressureMin.Value, pressureRange); Graph.Children.Add(new Line { Stroke = pressureBrush, StrokeThickness = 1, X1 = GraphPadding, Y1 = pressureAverageY, X2 = GraphPadding + drawWidth, Y2 = pressureAverageY }); // Draw temperature average line var temperatureAverageY = calculateGraphY(temperatureAverage.Value, temperatureMin.Value, temperatureRange); Graph.Children.Add(new Line { Stroke = temperatureBrush, StrokeThickness = 1, X1 = GraphPadding, Y1 = temperatureAverageY, X2 = GraphPadding + drawWidth, Y2 = temperatureAverageY }); // Plot graph points var graphX = GraphPadding; var pressureLine = new Polyline { Stroke = pressureBrush, StrokeThickness = 1 }; var temperatureLine = new Polyline { Stroke = temperatureBrush, StrokeThickness = 1 }; for (var index = Model.Graph.Count - 1; index >= 0; index--) { // Iterate backwards so we start with latest measurement var point = Model.Graph[index]; // Calculate relative pressure point var pressureY = calculateGraphY(point.Pressure, pressureMin.Value, pressureRange); var pressurePoint = new Point(graphX, pressureY); pressureLine.Points.Add(pressurePoint); // Calculate relative temperature point var temperatureY = calculateGraphY(point.Temperature, temperatureMin.Value, temperatureRange); var temperaturePoint = new Point(graphX, temperatureY); temperatureLine.Points.Add(temperaturePoint); // Move X for next point... graphX += GraphZoom; if (graphX > width) { // Stop when outside view break; } } Graph.Children.Add(pressureLine); Graph.Children.Add(temperatureLine); // Draw average text var pressureAverageString = string.Format(CultureInfo.CurrentCulture, "Pressure: {0}mbar", pressureAverage.Value); var pressureAverageText = new TextBlock { Foreground = pressureBrush, Text = pressureAverageString }; Graph.Children.Add(pressureAverageText); var temperatureAverageString = string.Format(CultureInfo.CurrentCulture, "Temperature: {0}°c", temperatureAverage.Value); var temperatureAverageText = new TextBlock { Foreground = temperatureBrush, Text = temperatureAverageString }; Graph.Children.Add(temperatureAverageText); // Position average text so that it does not overlap pressureAverageText.UpdateLayout(); temperatureAverageText.UpdateLayout(); Canvas.SetTop(pressureAverageText, pressureAverageY - pressureAverageText.ActualHeight); Canvas.SetLeft(pressureAverageText, width - pressureAverageText.ActualWidth - GraphPadding - temperatureAverageText.ActualWidth - GraphPadding); Canvas.SetTop(temperatureAverageText, temperatureAverageY - temperatureAverageText.ActualHeight); Canvas.SetLeft(temperatureAverageText, width - temperatureAverageText.ActualWidth - GraphPadding); }