Jaa


Generating key splines from a Path drawn in Blend

In Blend you can author keyframes with ease out and ease in interpolation to give your animations acceleration and deceleration: in other words, life. You can also draw a motion path and animate an element along it. A value curve is a graph of the change in a property value over time, and the combination of different value curves for different properties allows fine control over advanced scenarios such as acceleration along a curved trajectory.

The previous post Keyframe easing and key splines explains the string of numbers in a XAML KeySpline attribute such as those generated by Blend’s ease out and ease in settings. In a nutshell, the numbers are one keyframe’s worth of control points on a value curve. You can draw a value curve in Blend using the Pen tool and if you associate that curve with an element, a double property, and scales for the axes, then it’s a simple task to generate a set of keyframes and key splines. There are some scenarios where doing this is more appropriate than using Blend’s timeline so here’s a sample application which will get you started. The sample is unsupported but it is offered in the hope that it will be useful, instructive, or interesting.

Download the ValueCurve2KeySplines source code (Blend Beta 1).

Once you’ve downloaded and unzipped the sample project files, open and test (F5) the application. After building, the message on the artboard will disappear and the scene will display correctly. In the running application you can see three different-colored value curves, each of which targets a different property of the red plus sign-shaped element. When you click the ‘Generate’ button, an animation is generated from each of the value curves and these animations are saved in XAML format into the build folder in a file named Storyboard.xaml. The animations are also inserted into the application and previewed. The animation generated from the value curves included in the sample resembles an object spring-mounted on a surface and set in motion with a twang. If you’d like to know how the value curves and parameters were assembled then you can recreate it with the following procedure.

First, you need to delete the value curves and parameters so you can recreate them. Expand LayoutRoot > Graph > ValueCurves and delete the Path elements named X, Y and Angle. Expand LayoutRoot > LegendBd > [StackPanel] > LegendLB and delete the ValueCurveParameters elements named XParms, YParms and AngleParms. On the artboard you’ll notice that the Legend list box is now empty. Running and clicking ‘Generate’ now will have no effect.

The ‘spring twang’ animation happens over a small area and time period so let’s scale everything up while we’re designing it and then we can set the correct scale later without having to change any curves. Find the TextBlock element LayoutRoot > Graph > Axes > TimeAxis > TimeMax and set the Text property to ‘10’ so that the animation has a duration of ten seconds.

To recreate the value curve which controls the element’s X coordinate, first double-click ValueCurves to activate it; the yellow border confirms the activated state. Click the Pen tool (or press P) and draw a curve like the one in the diagram:

Make the first point with a click-drag toward the top-right of the screen to set the control point in that direction. Click-drag to the right to draw each of the subsequent points which will set horizontal tangents at the same time. In the previous post I mentioned that it is not valid for a control point to fall outside the bounding box of the spline which owns it. But some of the tangents shown above (and likely some of the tangents you will draw) are not perfectly horizontal so the control point on one end of the tangent will be breaking the rule. The ValueCurve2KeySplines sample will silently tolerate such errors up to a configurable limit (by default, 5% of the corresponding side-length of the bounding box) and will correct the control point. Any error greater than this tolerance will still be corrected but will provoke a warning message when the ‘Generate’ button is clicked. If you don’t want any automatic correction to take place then set the Window1.controlPointWarningTolerance member to zero and correct your control points manually until no warning message is shown. You can manipulate the control points individually with ALT and the Direct Selection tool (A). In the object tree, name the Path ‘X’ and set its Stroke to DarkSeaGreen and its Fill to No brush.

Now the value curve needs parameters so you need to create a parameter object which refers by name to the Path element representing the value curve. Make sure the ListBox named LegendLB is visible in the object tree. Click the Asset Library tool (the bottom tool in the Toolbox), click User Controls, and drag ValueCurveParameters out of the library. Be aware that the Asset Library will close as soon as your drag begins, but keep the mouse button pressed and drop the object onto LegendLB in the object tree to create a new ValueCurveParameters item in the ListBox. Name the object ‘XParms’ and then, in the Property Inspector, expand the Miscellaneous category and set the following property values: MaxValue = 350, MinValue = 50, set PathBrush to a SolidColorBrush with the Color DarkSeaGreen, TargetName = ‘Plus’, TargetProperty = ’(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)’, and ValueCurveName = ‘X’. An easy way to determine the TargetProperty and to make sure any necessary property elements exist on the target element is to create a new timeline and animate that property. You can copy the correct property path from the Storyboard.TargetProperty attribute in the XAML. Then you can delete the timeline and the necessary property elements will remain on the element.

For the element’s Y coordinate, draw a similar curve to the first but out of phase with it. Name the curve ‘Y’ and color it Navy with no Fill. Add a second parameter object (named ‘YParms’) to the ListBox and set the following property values: MaxValue = 350, MinValue = 50, PathBrush = ‘Navy’, TargetName = ‘Plus’, TargetProperty = ’(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)’, and ValueCurveName = ‘Y’.

Finally, for the element’s angle, draw a third curve out of phase with the other two. Name the curve ‘Angle’ and color it Orange with no Fill. Add a third parameter object (named ‘AngleParms’) to the ListBox and set the following property values: MaxValue = 30, MinValue = -30, PathBrush = ‘Orange’, TargetName = ‘Plus’, TargetProperty = ’(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)’, and ValueCurveName = ‘Angle’.

The finished application should look similar to this:

Test the animation and make any adjustments to the value curves to get the behavior you want. Essentially the frequency should be increasing while the amplitude is decreasing. When you’re happy, scale the whole animation down. Set TimeMax to ‘1.5’, set the MinValue and MaxValue of the X and Y parameter objects to 220 and 230 respectively, and set the MinValue and MaxValue of the Angle parameter object to -20 and 20 respectively. Now test the animation again. If you want to use the animation in another application then make sure a target element with the correct name and property elements exist and paste the contents of Storyboard.xaml into Window.Resources. You’ll also have to change the xmlns attribute into an x:Key attribute.

For another example set of value curves and parameters, you’ll find a file called Example2.txt in the zip file along with the source code. Replace the ValueCurves and LegendLB element in Window1.xaml with the ones in Example2.txt and give the result a try. It’s an example of an element moving along a circular path with increasing speed.

Happy animating!

Comments

  • Anonymous
    March 19, 2007
    To view a sample or tutorial, click on one of thumbnails or links below. Some samples also have supporting

  • Anonymous
    May 21, 2008
    Previously on the blog I’ve explained how a KeySpline can be used to do animation easing . I also demonstrated