Wpf Easing fonctions, otherwise known as the acceleration functions, are functions that slow down or accelerate the motion of an animation according to a mathematical formula. In this post we will see how to make a small WPF application that lists and draws the Easing functions available in the WPF framework.
Let’s start with the design of the main window which will contain:
- a canvas to draw the functions
- a drop-down list to choose the easing function to represent
- a check box to activate / deactivate the animations, because one wishes to move plots on the curves of the graphs, in order to highlight the effects of acceleration and slowing down introduced by the formulas
it will look something like this:
the XAML code of the main window (MainWindow.xaml) is :
<Window x:Class="FranckGaspoz.Wordpress.WPF.CSharp.EasingFunctionDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:EasingFunctionDemo" mc:Ignorable="d" Title="EasingFunctionDemo" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" Height="402" Width="519" SizeToContent="WidthAndHeight" > <Grid> <Grid.Resources> <!-- diagram background brush --> <DrawingBrush x:Key="BackBrush" Viewport="0,0,10,10" ViewportUnits="Absolute" TileMode="Tile"> <DrawingBrush.Drawing> <DrawingGroup> <GeometryDrawing Geometry="M0,0 L1,0 1,0.1, 0,0.1Z" Brush="#EEEEEE" /> <GeometryDrawing Geometry="M0,0 L0,1 0.1,1, 0.1,0Z" Brush="#EEEEEE" /> </DrawingGroup> </DrawingBrush.Drawing> </DrawingBrush> </Grid.Resources> <!-- main layout --> <Grid Name="GR_Layout" Background="WhiteSmoke"> <Grid.RowDefinitions> <RowDefinition Height="40"/> <RowDefinition Height="320"/> <RowDefinition Height="20"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="20"/> <ColumnDefinition Width="470"/> <ColumnDefinition Width="20"/> </Grid.ColumnDefinitions> <!-- control bar --> <StackPanel Grid.ColumnSpan="3" HorizontalAlignment="Left" Orientation="Horizontal" VerticalAlignment="Center" Margin="0" > <Label Content="easing function: "/> <!-- functions list --> <ComboBox Name="CB_EaseFunctions" Width="Auto" SelectionChanged="CB_EaseFunctions_SelectionChanged" /> <!-- enable / disable animations --> <CheckBox Margin="8,0,0,0" VerticalAlignment="Center" IsChecked="{Binding AnimationEnabled}" Name="CKB_AnimationsOn" Click="CKB_AnimationsOn_Click"> animation enabled </CheckBox> </StackPanel> <Border BorderThickness="1" BorderBrush="Gray" Grid.Row="1" Grid.Column="1"> <!-- and finally the drawing area --> <Canvas Background="{StaticResource BackBrush}" Name="Canvas" /> </Border> </Grid> </Grid> </Window>
The code behind is relatively simple and revolves around the 4 properties of the class:
// drawer of the graph EasingFunctionDrawer drawer = new EasingFunctionDrawer(); // list of functions BindingList<string> EasingFunctions = new BindingList<string>(); // easing function being displayed EasingFunctionBase EasingFunction = null; // indicates whether the animation is enabled or disabled public bool AnimationEnabled { get { return (bool)GetValue(AnimationEnabledProperty); } set { SetValue(AnimationEnabledProperty, value); } } // dependency property to bind the CheckBox public static readonly DependencyProperty AnimationEnabledProperty = DependencyProperty.Register("AnimationEnabled", typeof(bool), typeof(MainWindow), new PropertyMetadata(true));
The list of functions is built by introspecting the classes of the System.Windows.Media.Animation namespace in which the classes that interest us respect the naming convention {fonctionName}Easing
The InitGraph method is called when the graph needs to be redrawn (window constructor, selection in the list or click on checkbox)
All drawing tasks are assigned to the EasingFunctionDrawer class , whose method is to represent a easing function:
/// <summary> /// draws an easing function on a canvas /// </summary> /// <param name="canvas">target canvas</param> /// <param name="origin">coordinates of the graph origin</param> /// <param name="Length">chart size (enclosing square)</param> /// <param name="easeColor">line color of the function</param> /// <param name="easingFunc">easing function</param> /// <param name="scaley">scale on the Y axis (reduction factor)</param> internal void Draw( Canvas canvas, Point origin, double Length, Brush easeColor, EasingFunctionBase easingFunc, double scaley ) { double stp = 0.025/10d,d,x,y; // the X axis is linearly traversed for (double a = 0;a<=1;a+=stp) { x = origin.X + a * Length; y = origin.Y; /** * the easing function is called to determine the value * for the X position, which is here provided as a parameter of * normalized time t (for f(t) where f is the easing function) */ d = easingFunc.Ease(a); // the ordinate is determined according to the value of the easing function y = origin.Y - d * Length / scaley; // the point is drawn DrawPlot(canvas, x, y, easeColor); } }
The animation of a plot that follows the curve is done via the Animate(…) :
/// <summary> /// animates a point that runs through the representation of a easing function /// </summary> /// <param name="canvas">target canvas</param> /// <param name="origin">chart origin</param> /// <param name="Length">chart size (enclosing square)</param> /// <param name="easeColor">line color of the function</param> /// <param name="easingFunc">easing function</param> /// <param name="scaley">scale on the Y axis (reduction factor)</param> internal void Animate( Canvas canvas, Point origin, double Length, Brush easeColor, EasingFunctionBase easingFunc, double scaley ) { var duration = TimeSpan.FromSeconds(3); var r = DrawPlot( canvas, origin.X, origin.Y, easeColor, 6d); var ta = new TranslateTransform(0,0); r.RenderTransform = ta; // linear progression on the X axis (time axis) var x_move = new DoubleAnimation() { From = 0, To = Length, Duration = duration, AutoReverse = true, RepeatBehavior = RepeatBehavior.Forever }; // progression according to the function of ease on the Y axis var y_move = new DoubleAnimation() { From = 0, To = - Length/scaley, Duration = duration, EasingFunction = easingFunc, AutoReverse = true, RepeatBehavior = RepeatBehavior.Forever };<br /> // start the animation ta.BeginAnimation( TranslateTransform.XProperty, x_move );<br /> ta.BeginAnimation( TranslateTransform.YProperty, y_move ); }
Here is an example of the result:



