using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; using RealTimeGraphEx.Models; using RealTimeGraphEx.DataSeries; using RealTimeGraphEx.Controllers; using RealTimeGraphEx.Enums; namespace RealTimeGraphEx.FastGraphs { public class RealTimeGraphExShapeScroll : RealTimeGraphExLineScroll { #region Cross Thread Fields protected ShapeTypeEnum _shapeType; protected int _shapeWidth; protected int _shapeGap; protected OpacityTypeEnum _opacityAnimationType; protected RealTimeGraphColumnsCollection graphColumns; protected int currentColumnIndex; #endregion #region Properties public ShapeTypeEnum ShapeType { get { return (ShapeTypeEnum)GetValue(ShapeTypeProperty); } set { SetValue(ShapeTypeProperty, value); } } public static readonly DependencyProperty ShapeTypeProperty = DependencyProperty.Register("ShapeType", typeof(ShapeTypeEnum), typeof(RealTimeGraphExShapeScroll), new PropertyMetadata(ShapeTypeEnum.Column, new PropertyChangedCallback(CrossModelChanged))); public int ShapeWidth { get { return (int)GetValue(ShapeWidthProperty); } set { SetValue(ShapeWidthProperty, value); } } public static readonly DependencyProperty ShapeWidthProperty = DependencyProperty.Register("ShapeWidth", typeof(int), typeof(RealTimeGraphExShapeScroll), new PropertyMetadata(5, new PropertyChangedCallback(CrossModelChanged))); public int ShapeGap { get { return (int)GetValue(ShapeGapProperty); } set { SetValue(ShapeGapProperty, value); } } public static readonly DependencyProperty ShapeGapProperty = DependencyProperty.Register("ShapeGap", typeof(int), typeof(RealTimeGraphExShapeScroll), new PropertyMetadata(1, new PropertyChangedCallback(CrossModelChanged))); public OpacityTypeEnum OpacityAnimationType { get { return (OpacityTypeEnum)GetValue(OpacityAnimationTypeProperty); } set { SetValue(OpacityAnimationTypeProperty, value); } } public static readonly DependencyProperty OpacityAnimationTypeProperty = DependencyProperty.Register("OpacityAnimationType", typeof(OpacityTypeEnum), typeof(RealTimeGraphExShapeScroll), new PropertyMetadata(OpacityTypeEnum.None, new PropertyChangedCallback(CrossModelChanged))); #endregion #region Constructors public RealTimeGraphExShapeScroll() : base() { graphColumns = new RealTimeGraphColumnsCollection(); _graphController = new GraphController(); } #endregion #region Override Methods protected override void OnSetCrossThreadFields() { base.OnSetCrossThreadFields(); this.Dispatcher.Invoke(() => { _shapeType = ShapeType; _shapeWidth = ShapeWidth; _shapeGap = ShapeGap; _opacityAnimationType = OpacityAnimationType; }, System.Windows.Threading.DispatcherPriority.Send); } protected override void OnClearGraph() { graphColumns.ClearColumns(); currentColumnIndex = 0; updateCounter = 0; base.OnClearGraph(); } protected internal override void OnRenderGraph() { if (_graphController != null && _graphController.dataSeries.Points != null && _graphController.dataSeries.Points.Count > 0 && _width > 1 && _height > 1) { for (int i = 0; i < _graphController.dataSeries.Points.Count; i++) { double value = _graphController.dataSeries.Points[i]; NormalizeValue(ref value); double valuePrecentage = ConvertYToImageYFliped(value); graphColumns.Add((int)xValueCounter, (int)valuePrecentage, (int)xValueCounter + _shapeWidth, (int)(_maximum - valuePrecentage), (int)value); xValueCounter += (_shapeWidth + _shapeGap + 1); if (xValueCounter > _width) { xValueCounter -= (_shapeWidth + _shapeGap + 1); graphColumns.RemoveFromStart(1); } } updateCounter++; if (updateCounter >= 1 && !_isPaused) { updateCounter = 0; if (!_disableRendering) { WriteableBitmap bmp = BitmapFactory.New((int)_width, (int)_height); bmp.Clear(Colors.Transparent); Color lineColor = _graphController.dataSeries.GetStrokeColor() != null ? _graphController.dataSeries.GetStrokeColor().Value : _stroke; Color fillColor = _graphController.dataSeries.GetFillColor() != null ? _graphController.dataSeries.GetFillColor().Value : _fill; int right = graphColumns.TotalColumns - currentColumnIndex; double r_opacity = right > 0 ? 255 / right : 255; double l_opacity = currentColumnIndex > 0 ? 255 / currentColumnIndex : 255; for (int i = 0; i < graphColumns.TotalColumns; i++) { var rec = graphColumns.Columns[i]; Color processedLineColor = lineColor; Color processedFillColor = fillColor; int calculatedOpacity = 255; switch (_shapeType) { case ShapeTypeEnum.Column: #region Column if (_opacityAnimationType == OpacityTypeEnum.FadeOut) { byte opacity = (byte)((((rec.X) * 100 / _width) * 255) / 100); processedLineColor.A = opacity; processedFillColor.A = opacity; } else if (_opacityAnimationType == OpacityTypeEnum.CrossFade) { if (i < currentColumnIndex && currentColumnIndex > 0) { calculatedOpacity = (int)((i + 1) * l_opacity); } else { calculatedOpacity = (int)(((right) - Math.Abs(currentColumnIndex - (i))) * r_opacity); } byte opacity = (byte)(calculatedOpacity); processedLineColor.A = opacity; processedFillColor.A = opacity; } if (_fillGraph) { bmp.FillRectangle(rec.X, rec.Y, rec.Right, rec.Bottom, processedFillColor); bmp.DrawRectangle(rec.X, rec.Y, rec.Right, rec.Bottom, processedLineColor); } else { bmp.DrawRectangle(rec.X, rec.Y, rec.Right, rec.Bottom, processedLineColor); } #endregion break; case ShapeTypeEnum.Circle: #region Circle if (_opacityAnimationType == OpacityTypeEnum.FadeOut) { byte opacity = (byte)((((rec.X) * 100 / _width) * 255) / 100); processedLineColor.A = opacity; processedFillColor.A = opacity; } else if (_opacityAnimationType == OpacityTypeEnum.CrossFade) { if (i < currentColumnIndex && currentColumnIndex > 0) { calculatedOpacity = (int)((i + 1) * l_opacity); } else { calculatedOpacity = (int)(((right) - Math.Abs(currentColumnIndex - (i))) * r_opacity); } byte opacity = (byte)(calculatedOpacity); processedLineColor.A = opacity; processedFillColor.A = opacity; } if (_fillGraph) { bmp.FillEllipseCentered(rec.X, rec.Y, _shapeWidth, _shapeWidth, processedFillColor); bmp.DrawEllipseCentered(rec.X, rec.Y, _shapeWidth, _shapeWidth, processedLineColor); } else { bmp.DrawEllipseCentered(rec.X, rec.Y, _shapeWidth, _shapeWidth, processedLineColor); } #endregion break; case ShapeTypeEnum.Rectangle: #region Rectangle if (_opacityAnimationType == OpacityTypeEnum.FadeOut) { byte opacity = (byte)((((rec.X) * 100 / _width) * 255) / 100); processedLineColor.A = opacity; processedFillColor.A = opacity; } else if (_opacityAnimationType == OpacityTypeEnum.CrossFade) { if (i < currentColumnIndex && currentColumnIndex > 0) { calculatedOpacity = (int)((i + 1) * l_opacity); } else { calculatedOpacity = (int)(((right) - Math.Abs(currentColumnIndex - (i))) * r_opacity); } byte opacity = (byte)(calculatedOpacity); processedLineColor.A = opacity; processedFillColor.A = opacity; } if (_fillGraph) { bmp.FillRectangle(rec.X, rec.Y, rec.X + _shapeWidth, rec.Y + _shapeWidth, processedFillColor); bmp.DrawRectangle(rec.X, rec.Y, rec.X + _shapeWidth, rec.Y + _shapeWidth, processedLineColor); } else { bmp.DrawRectangle(rec.X, rec.Y, rec.X + _shapeWidth, rec.Y + _shapeWidth, processedLineColor); } #endregion break; } } bmp.Freeze(); img.Dispatcher.BeginInvoke(new Action(() => { img.Source = bmp; }), System.Windows.Threading.DispatcherPriority.Send); } } } } #endregion } }