This example derived from a recent conversation involving the Spark animation classes and interpolation. The question involved whether or not it was possible to use the Spark animation classes to perform a path interpolation based on a cartesian spline. Interpolators aside, Spark animations are based on properties that vary over time. A cartesian spline (such as the natural cubic spline) interpolates a path with y described strictly as a function of x. A natural extension of the original question is whether or not the implementation could be performed with a minimal change to existing MXML. So, consider something along the lines of
<fx:Declarations> <s:Animate id="pathAnimation" target="{marker}" duration="2000"> <!-- Note - time values should be consistent on both x and y keyframes; since this is a cartesian interpolation, x-values must be strictly increasing with time --> <s:MotionPath id="xKeyframes" property="x"> <s:Keyframe time="0" value="0"/> <s:Keyframe time="250" value="100"/> <s:Keyframe time="500" value="250"/> <s:Keyframe time="750" value="300"/> <s:Keyframe time="1000" value="400"/> <s:Keyframe time="1250" value="450"/> <s:Keyframe time="1500" value="500" /> <s:Keyframe time="1750" value="550" /> <s:Keyframe time="2000" value="600" /> </s:MotionPath> <s:MotionPath id="yKeyframes" property="y"> <s:Keyframe time="0" value="0"/> <s:Keyframe time="250" value="50"/> <s:Keyframe time="500" value="150"/> <s:Keyframe time="750" value="100"/> <s:Keyframe time="1000" value="200"/> <s:Keyframe time="1250" value="350"/> <s:Keyframe time="1500" value="300" /> <s:Keyframe time="1750" value="450" /> <s:Keyframe time="2000" value="600" /> </s:MotionPath> </s:Animate> </fx:Declarations>
The keyframes describe a path over time. We could execute the animation with linear interpolation between keyframes, but that moves a sprite along the straight line between spatial points. So, can we use the existing Spark animation structure to replace this with an animation along a path between keyframes based on a cubic spline interpolation (an example of a cartesian spline)?
My first thought was trying to ‘back-door’ an interpolator for the y-coordinate keyframes with the understanding that the animation proceeds strictly from beginning to end (i.e. forward in time). We can temporarily treat x as a function of time with linear interpolation. The trick is relating the fraction passed into the subclass of spark.effects.Interpolator to some global value in [0,1]. For each keyframe interval in the y-coordinate set, Flex passes a local fraction in [0,1] along with the y ranges. Given min/max ranges for the independent variable in the cubic spline, this information can be converted to a global t-value in [0,1], which can be used to approximate the global x-coordinate used to interpolate y.
The problem I encountered is inconsistent fraction values between the x- and y-interpolators (which I found by replacing the default interpolator for the x keyframes with my own linear interpolator and tracing the fraction values). This caused the x-values positioned by Flex to be out of snych with the y-coordinates computed by the spline. Ugh.
This, however, lead to what I consider to be a more elegant (but less than optimal) solution, namely push Flex as far out of the picture as possible by writing my own custom Animate class. This process is described in the help files as well as this tutorial. It’s so easy, even a mathematician can do it 🙂
I wrote a factory, SplinePathAnimation, and a custom instance, SplinePathAnimationInstance which contains a natural cubic spline via composition. The keyframe data is accessed in the overridden play() method and used to initialize the natural cubic spline. The overridden animationUpdate() method linearly interpolates x and uses the natural cubic spline to interpolate y.
The demo draws a cubic spline path, then animates a sprite over that path. The sprite is just an FXG graphic that I ripped off from an Adobe example. The demo still has some rough edges, but then it’s just a demo 🙂 The important consideration is that all I had to change in the MXML was replace s:Animate with util:SplinePathAnimation (with the namespace declaration xmlns:util=”utils.*”) and the closing tag. This makes it pretty easy to switch out animations and keep the keyframe data intact in MXML.
I’d personally prefer controlling time myself and writing this as a custom animation outside the Spark framework, but the direct answer to the question is that I suppose it’s possible (at least in an approximate sense). At least you have another example on how to create custom Spark animations, although this example illustrates the absolute minimal implementation to execute the demo. It is not robust and the demo itself is still pretty rough.
If you’re interested in how the natural cubic spline is constructed, read all about it here.