using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; namespace RealTimeGraphEx.FastGraphs { public class RealTimeGraphExLineErase : RealTimeGraphExLineScroll, INotifyPropertyChanged { #region Cross Thread Fields protected Color _markerColor; protected bool _showMarker; protected bool _endReached; protected int _currentReplaceIndex; protected bool _enableMarkerPosition; protected double lastVirtualValue; protected int lastMaxPoints; #endregion #region Properties /// /// Gets or sets the graph marker color. /// public Color MarkerColor { get { return (Color)GetValue(MarkerColorProperty); } set { SetValue(MarkerColorProperty, value); } } public static readonly DependencyProperty MarkerColorProperty = DependencyProperty.Register("MarkerBrush", typeof(Color), typeof(RealTimeGraphExLineErase), new PropertyMetadata(Colors.Red, new PropertyChangedCallback(CrossModelChanged))); /// /// Gets or sets whether to display the marker on the graph. /// public bool ShowMarker { get { return (bool)GetValue(ShowMarkerProperty); } set { SetValue(ShowMarkerProperty, value); } } public static readonly DependencyProperty ShowMarkerProperty = DependencyProperty.Register("ShowMarker", typeof(bool), typeof(RealTimeGraphExLineErase), new PropertyMetadata(true, new PropertyChangedCallback(CrossModelChanged))); /// /// Gets or sets a value indicating whether to enable the MarkerPosition property to be updated. (Affects performance). /// public bool EnableMarkerPosition { get { return (bool)GetValue(EnableMarkerPositionProperty); } set { SetValue(EnableMarkerPositionProperty, value); } } public static readonly DependencyProperty EnableMarkerPositionProperty = DependencyProperty.Register("EnableMarkerPosition", typeof(bool), typeof(RealTimeGraphExLineErase), new PropertyMetadata(false, new PropertyChangedCallback(CrossModelChanged))); /// /// Gets the current marker position on the graph. /// private Point markerPosition; public Point MarkerPosition { private get { return markerPosition; } set { markerPosition = value; RaisePropertyChanged("MarkerPosition"); } } #endregion #region Constructors public RealTimeGraphExLineErase() : base() { } #endregion #region Override Method protected override void OnSetCrossThreadFields() { base.OnSetCrossThreadFields(); this.Dispatcher.Invoke(() => { _markerColor = MarkerColor; _showMarker = ShowMarker; _enableMarkerPosition = EnableMarkerPosition; if (lastMaxPoints > _maxPoints && graphPolygon.Count > (lastMaxPoints - _maxPoints)) { graphPolygon.RemoveFromStart(lastMaxPoints - _maxPoints); } lastMaxPoints = _maxPoints; }, System.Windows.Threading.DispatcherPriority.Send); } protected internal override void OnRenderGraph() { if (_graphController != null && _graphController.dataSeries != null && _graphController.dataSeries.Points != null && _graphController.dataSeries.Points.Count > 0 && _width > 1 && _height > 1) { var points = _graphController.dataSeries.Points.GetAndClearAllPoints(); if (_useAutoRange && points.Count > 0) { Dispatcher.Invoke(() => { Maximum = points.Concat(graphPolygon.GetPoints()).Max(); Minimum = points.Concat(graphPolygon.GetPoints()).Min(); }); } if (!_isPaused) { for (int i = 0; i < points.Count; i++) //Match { double value = points[i]; NormalizeValue(ref value); lastVirtualValue = value; if (graphPolygon.Count > _maxPoints) { graphPolygon.Replace(value, _currentReplaceIndex++); for (int k = 0; k < _markers.Count; k++) { if (_markers[k] == _currentReplaceIndex) { _markers.RemoveAt(k); k--; } } } else { graphPolygon.Add(value); } xValueCounter += _scaleFactor; if (_currentReplaceIndex == graphPolygon.Count - 1) { xValueCounter = 0; _currentReplaceIndex = 0; } } } updateCounter++; if (updateCounter >= 1) { updateCounter = 0; if (!_disableRendering) { WriteableBitmap bmp = BitmapFactory.New((int)_mainWidth, (int)_mainHeight); bmp.Clear(Colors.Transparent); OnDrawVisuals(bmp); bmp.Freeze(); img.Dispatcher.BeginInvoke(new Action(() => { img.Source = bmp; }), System.Windows.Threading.DispatcherPriority.Send); } } } } protected override void OnDrawVisuals(WriteableBitmap bmp) { if (_graphController == null) return; Color stroke = _graphController.dataSeries.GetStrokeColor() != null ? _graphController.dataSeries.GetStrokeColor().Value : _stroke; Color fill = _graphController.dataSeries.GetFillColor() != null ? _graphController.dataSeries.GetFillColor().Value : _fill; double scale = GetPolygonScaleFactor(); double currentWidth = _endReached ? _width : xValueCounter; if (_fillGraph) //Fill Graph { bmp.FillPolygon(graphPolygon.ToPolygonPointsFill(_offSetX, _offSetY, _mainWidth, _mainHeight, scale, ConvertYToImageYFliped), fill); } DrawPolyline(bmp, graphPolygon.ToPolygonPoints(_offSetX, _offSetY, scale, ConvertYToImageYFliped), stroke); //Draw marker if (_showMarker) { if (_currentReplaceIndex > 0) { try { double x = (((_currentReplaceIndex - 1) * scale) + _offSetX); bmp.DrawLine((int)x, 0, (int)x, (int)_mainHeight, _markerColor); } catch { Debug.WriteLine("[RealTimeGraphExLineErase] [OnDrawVisuals] Error on drawing marker!"); } } } for (int j = 0; j < _markers.Count; j++) { int x = (int)(((_markers[j] - 1) * scale) + _offSetX); bmp.DrawLine(x, 0, x, (int)_mainHeight, Colors.Silver); } if (_enableMarkerPosition) { MarkerPosition = new Point((_currentReplaceIndex * scale) + _offSetX, ConvertYToImageYFliped(lastVirtualValue) + _offSetY); } } protected override void OnClearGraph() { base.OnClearGraph(); _currentReplaceIndex = 0; _endReached = false; MarkerPosition = new Point(0, 0); } protected override void OnPushMarker() { if (_currentReplaceIndex != 0) { _markers.Add(_currentReplaceIndex); } } #endregion #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; public void RaisePropertyChanged(String propName) { this.Dispatcher.Invoke(() => { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propName)); }); } #endregion } }