Back to Devexpress

How to: Implement a Custom Marker Animation

windowsforms-116438-controls-and-libraries-chart-control-examples-end-user-interaction-how-to-implement-a-custom-marker-animation.md

latest7.6 KB
Original Source

How to: Implement a Custom Marker Animation

  • Nov 13, 2018
  • 4 minutes to read

To implement a custom bar animation, design a class inheriting the XYMarkerAnimationBase class and override the XYMarkerAnimationBase.ApplyState method which determines the transformations applied to an individual marker.

csharp
using DevExpress.XtraCharts;
using System;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace AnimationExample {
    class FanMarkerAnimation : XYMarkerAnimationBase {
        public override void ApplyState(
                SceneModifier modifier, 
                RectangleF diagramBounds, 
                MarkerSeriesPointLayoutParameters markerParameters, 
                float progress
        ) {
            RectangleF markerBounds = markerParameters.Bounds;
            float markerCenterX = markerBounds.Left + markerBounds.Width / 2;
            float markerCenterY = markerBounds.Top + markerBounds.Height / 2;

            float startAngle = 360 - progress * 180;
            float sweepAngle = 360 * progress;
            float endAngle = startAngle + sweepAngle;

            // To apply a fan animation we need to compute parameters of 
            // a marker's circumscribed circle sector.
            float circumscribedCircleRadius = (float)Math.Sqrt(
                    (markerBounds.Left - markerCenterX) * (markerBounds.Left - markerCenterX)
                    + (markerBounds.Top - markerCenterY) * (markerBounds.Top - markerCenterY)
            );

            float circumscribedCircleSectorLeftBoundEndX = 
                markerCenterX + (float)Math.Cos(startAngle / 180 * Math.PI) * circumscribedCircleRadius;
            float circumscribedCircleSectorLeftBoundEndY = 
                markerCenterY + (float)Math.Sin(startAngle / 180 * Math.PI) * circumscribedCircleRadius;

            float circumscribedCircleSectorRightBoundEndX = 
                markerCenterX + (float)Math.Cos(endAngle / 180 * Math.PI) * circumscribedCircleRadius;
            float circumscribedCircleSectorRightBoundEndY = 
                markerCenterY + (float)Math.Sin(endAngle / 180 * Math.PI) * circumscribedCircleRadius;

            RectangleF circumscribedCircleBounds = new RectangleF(
                    markerCenterX - circumscribedCircleRadius,
                    markerCenterY - circumscribedCircleRadius,
                    2 * circumscribedCircleRadius,
                    2 *circumscribedCircleRadius
            );

            // Path representing a marker's circumscribed circle sector.
            GraphicsPath path = new GraphicsPath();
            path.AddLine(
                    markerCenterX, 
                    markerCenterY, 
                    circumscribedCircleSectorLeftBoundEndX, 
                    circumscribedCircleSectorLeftBoundEndY
            );
            path.AddArc(
                circumscribedCircleBounds, 
                startAngle, 
                sweepAngle
            );
            path.AddLine(
                    circumscribedCircleSectorRightBoundEndX,
                    circumscribedCircleSectorRightBoundEndY,
                    markerCenterX,
                    markerCenterY
            );

            modifier.Clip(path);
        }
        protected override ChartElement CreateObjectForClone() {
            return new FanMarkerAnimation();
        }
    }
}
csharp
protected override void OnLoad(EventArgs e) {
    base.OnLoad(e);

    chartControl.AnimationStartMode = ChartAnimationMode.OnLoad;
    view.SeriesPointAnimation = new FanMarkerAnimation() {
        BeginTime = new TimeSpan(0, 0, 0),
        Duration = new TimeSpan(0, 0, 0, 1, 500),
        PointDelay = new TimeSpan(0, 0, 0, 0, 250),
        PointOrder = PointAnimationOrder.Random,
        EasingFunction = new QuinticEasingFunction {
            EasingMode = EasingMode.Out
        }
    };
}

private void OnAnimateClick(object sender, EventArgs e) {
    chartControl.Animate();
}
vb
Protected Overrides Sub OnLoad(ByVal e As EventArgs)
    MyBase.OnLoad(e)

    chartControl.AnimationStartMode = ChartAnimationMode.OnLoad
    view.SeriesPointAnimation = New FanMarkerAnimation() With { _
        .BeginTime = New TimeSpan(0, 0, 0), .Duration = New TimeSpan(0, 0, 0, 1, 500), .PointDelay = New TimeSpan(0, 0, 0, 0, 250), .PointOrder = PointAnimationOrder.Random, .EasingFunction = New QuinticEasingFunction With {.EasingMode = EasingMode.Out} _
    }
End Sub

Private Sub OnAnimateClick(ByVal sender As Object, ByVal e As EventArgs) Handles button1.Click, btnAnimate.Click
    chartControl.Animate()
End Sub
vb
Imports DevExpress.XtraCharts
Imports System
Imports System.Drawing
Imports System.Drawing.Drawing2D

Namespace AnimationExample
    Friend Class FanMarkerAnimation
        Inherits XYMarkerAnimationBase

        Public Overrides Sub ApplyState(ByVal modifier As SceneModifier, ByVal diagramBounds As RectangleF, ByVal markerParameters As MarkerSeriesPointLayoutParameters, ByVal progress As Single)
            Dim markerBounds As RectangleF = markerParameters.Bounds
            Dim markerCenterX As Single = markerBounds.Left + markerBounds.Width / 2
            Dim markerCenterY As Single = markerBounds.Top + markerBounds.Height / 2

            Dim startAngle As Single = 360 - progress * 180
            Dim sweepAngle As Single = 360 * progress
            Dim endAngle As Single = startAngle + sweepAngle

            ' To apply a fan animation we need to compute parameters of 
            ' a marker's circumscribed circle sector.
            Dim circumscribedCircleRadius As Single = CSng(Math.Sqrt((markerBounds.Left - markerCenterX) * (markerBounds.Left - markerCenterX) + (markerBounds.Top - markerCenterY) * (markerBounds.Top - markerCenterY)))

            Dim circumscribedCircleSectorLeftBoundEndX As Single = markerCenterX + CSng(Math.Cos(startAngle / 180 * Math.PI)) * circumscribedCircleRadius
            Dim circumscribedCircleSectorLeftBoundEndY As Single = markerCenterY + CSng(Math.Sin(startAngle / 180 * Math.PI)) * circumscribedCircleRadius

            Dim circumscribedCircleSectorRightBoundEndX As Single = markerCenterX + CSng(Math.Cos(endAngle / 180 * Math.PI)) * circumscribedCircleRadius
            Dim circumscribedCircleSectorRightBoundEndY As Single = markerCenterY + CSng(Math.Sin(endAngle / 180 * Math.PI)) * circumscribedCircleRadius

            Dim circumscribedCircleBounds As New RectangleF(markerCenterX - circumscribedCircleRadius, markerCenterY - circumscribedCircleRadius, 2 * circumscribedCircleRadius, 2 *circumscribedCircleRadius)

            ' Path representing a marker's circumscribed circle sector.
            Dim path As New GraphicsPath()
            path.AddLine(markerCenterX, markerCenterY, circumscribedCircleSectorLeftBoundEndX, circumscribedCircleSectorLeftBoundEndY)
            path.AddArc(circumscribedCircleBounds, startAngle, sweepAngle)
            path.AddLine(circumscribedCircleSectorRightBoundEndX, circumscribedCircleSectorRightBoundEndY, markerCenterX, markerCenterY)

            modifier.Clip(path)
        End Sub
        Protected Overrides Function CreateObjectForClone() As ChartElement
            Return New FanMarkerAnimation()
        End Function
    End Class
End Namespace