using RealTimeGraphEx.Controllers;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace RealTimeGraphEx.ReachGraphs
{
public class RealTimeGraphExReachVUMeter : RealTimeGraphExBase
{
#region Protected Fields
protected int updateCounter;
protected Rectangle rectangle;
protected double lastValue;
#endregion
#region Cross Thread Fields
protected Brush _stroke;
protected Brush _fill;
protected GraphController _graphController;
#endregion
#region Properties
///
/// Gets or sets the graph strokes color.
///
public Brush Stroke
{
get { return (Brush)GetValue(StrokeProperty); }
set { SetValue(StrokeProperty, value); }
}
public static readonly DependencyProperty StrokeProperty =
DependencyProperty.Register("Stroke", typeof(Brush), typeof(RealTimeGraphExReachVUMeter), new PropertyMetadata(Brushes.Black, new PropertyChangedCallback(CrossModelChanged)));
///
/// Gets or sets the graph fill color.
///
public Brush Fill
{
get { return (Brush)GetValue(FillProperty); }
set { SetValue(FillProperty, value); }
}
public static readonly DependencyProperty FillProperty =
DependencyProperty.Register("Fill", typeof(Brush), typeof(RealTimeGraphExReachVUMeter), new PropertyMetadata(Brushes.Gray, new PropertyChangedCallback(CrossModelChanged)));
///
/// Gets or sets the IDataSeries used to push data points to the graph.
///
public GraphController Controller
{
get { return (GraphController)GetValue(ControllerProperty); }
set { SetValue(ControllerProperty, value); }
}
public static readonly DependencyProperty ControllerProperty =
DependencyProperty.Register("Controller", typeof(GraphController), typeof(RealTimeGraphExReachVUMeter), new PropertyMetadata(null, new PropertyChangedCallback(GraphControllerChanged)));
private static void GraphControllerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as RealTimeGraphExReachVUMeter;
if (control.Controller != null)
{
control.Controller.RegisterMethods(control.ClearGraph, control.StartPushThread, control.SetPaused,control.ChangeRenderMode,null);
control._graphController = control.Controller;
}
}
///
/// Gets or sets the collection of VU range data determines how to fill the VU graph.
///
public ObservableCollection Ranges
{
get { return (ObservableCollection)GetValue(RangesProperty); }
set { SetValue(RangesProperty, value); }
}
public static readonly DependencyProperty RangesProperty =
DependencyProperty.Register("Ranges", typeof(ObservableCollection), typeof(RealTimeGraphExReachVUMeter), new PropertyMetadata(null));
///
/// Gets or sets whether to animate the VU when when it's value doens not change.
///
public bool Animate
{
get { return (bool)GetValue(AnimateProperty); }
set { SetValue(AnimateProperty, value); }
}
public static readonly DependencyProperty AnimateProperty =
DependencyProperty.Register("Animate", typeof(bool), typeof(RealTimeGraphExReachVUMeter), new PropertyMetadata(false));
///
/// Gets or sets the height value to animate when the Animate property is set to true.
///
public double AnimationAmount
{
get { return (double)GetValue(AnimationAmountProperty); }
set { SetValue(AnimationAmountProperty, value); }
}
public static readonly DependencyProperty AnimationAmountProperty =
DependencyProperty.Register("AnimationAmount", typeof(double), typeof(RealTimeGraphExReachVUMeter), new PropertyMetadata(10.0));
///
/// Gets or sets the duration of the animation when the Animate property is set to true.
///
public Duration AnimationDuration
{
get { return (Duration)GetValue(AnimationDurationProperty); }
set { SetValue(AnimationDurationProperty, value); }
}
public static readonly DependencyProperty AnimationDurationProperty =
DependencyProperty.Register("AnimationDuration", typeof(Duration), typeof(RealTimeGraphExReachVUMeter), new PropertyMetadata(new Duration(TimeSpan.FromMilliseconds(500))));
#endregion
#region Constructors
public RealTimeGraphExReachVUMeter()
: base()
{
Ranges = new ObservableCollection();
}
#endregion
#region Override Methods
protected override void Initialize()
{
base.Initialize();
if (rectangle == null)
{
rectangle = new Rectangle() { Tag = "Default" };
rectangle.Height = 0;
}
gridLinesAndImageWrapperGrid.Children.Remove(img);
if (!gridLinesAndImageWrapperGrid.Children.Contains(rectangle))
{
gridLinesAndImageWrapperGrid.Children.Add(rectangle);
}
//TODO: Base on developer selection vertical/horizontal VU.
rectangle.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
rectangle.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
}
protected override void OnSetCrossThreadFields()
{
base.OnSetCrossThreadFields();
this.Dispatcher.Invoke(() =>
{
_graphController = Controller;
_stroke = Stroke;
_fill = Fill;
if (rectangle.Tag != null && rectangle.Tag.ToString() == "Default")
{
rectangle.Fill = Fill;
rectangle.Stroke = Stroke;
}
if (_graphController != null && _graphController.dataSeries != null && _graphController.dataSeries.useFillandStroke)
{
rectangle.Fill = _graphController.dataSeries.fill;
rectangle.Stroke = _graphController.dataSeries.stroke;
}
}, DispatcherPriority.Send);
}
protected override void OnClearGraph()
{
base.OnClearGraph();
this.Dispatcher.Invoke(() =>
{
rectangle.BeginAnimation(Rectangle.HeightProperty, null);
rectangle.Height = 0;
});
}
protected internal override void OnRenderGraph()
{
if (_graphController != null && _graphController.dataSeries.Points != null && _graphController.dataSeries.Points.Count > 0 && _width > 1 && _height > 1)
{
double value = _graphController.dataSeries.Points[_graphController.dataSeries.Points.Count - 1]; //Get last value.
if (value == lastValue)
{
_graphController.ClearPoints();
return;
}
lastValue = value;
double valuePrecentage = ConvertYToImageY(value);
updateCounter++;
if (updateCounter >= 1 && !_isPaused)
{
updateCounter = 0;
OnDrawVisuals(valuePrecentage);
}
_graphController.ClearPoints();
}
}
#endregion
#region Virtual Methods
protected virtual void OnDrawVisuals(double valuePrecentage)
{
this.Dispatcher.Invoke(() =>
{
rectangle.BeginAnimation(Rectangle.HeightProperty, null);
rectangle.Height = valuePrecentage;
rectangle.Fill = GetRectangleBrush();
if (Animate)
{
DoubleAnimation ani = new DoubleAnimation();
ani.CurrentTimeInvalidated += (x, y) =>
{
rectangle.Fill = GetRectangleBrush();
};
ani.To = rectangle.Height - AnimationAmount;
ani.From = rectangle.Height;
ani.RepeatBehavior = RepeatBehavior.Forever;
ani.AutoReverse = true;
ani.Duration = AnimationDuration;
rectangle.BeginAnimation(HeightProperty, ani);
}
});
}
private Brush GetRectangleBrush()
{
if (Ranges != null && Ranges.Count > 0)
{
LinearGradientBrush brush = new LinearGradientBrush();
brush.MappingMode = BrushMappingMode.Absolute;
brush.StartPoint = new Point(0, _height - rectangle.Height);
brush.EndPoint = new Point(0, (rectangle.Height * -1));
brush.Transform = new RotateTransform() { Angle = 180 };
for (int i = Ranges.Count - 1; i >= 0; i--)
{
var range = Ranges[i];
double rangeValuePrecentage = ConvertYToImageY(range.Value);
GradientStop stop = new GradientStop();
stop.Color = range.Color;
stop.Offset = ((rangeValuePrecentage * 100) / _height) / 100;
brush.GradientStops.Add(stop);
}
return brush;
}
else
{
return Fill;
}
}
#endregion
}
}