The AnimationExtender control in the ASP.NET AJAX Control Toolkit makes it easy to add animated effects to Web pages. I especially like the fact that you can compose complex animations from simple animations and use <Parallel> and <Sequence> elements to control animation order.

Much of AnimationExtender’s magic is found in a file named Animations.js, which is derived from PreviewGlitz.js in the ASP.NET AJAX Futures January CTP. I was curious to find out how difficult it would be to implement complex animations using the low-level animation classes in PreviewGlitz.js, and found that there are virtually no samples out there demonstrating how to perform anything but the most trivial animations. So I cracked open the file and went spelunking. The result is my “Balloon Pop” demo (pictured below), which you can download here. When you click a balloon, the balloon pops. The pop is really a series of animations run in parallel to simultaneously fade the balloon out and scale its width and height from 1 to 8. Once the animations are complete, a bit of JavaScript code deletes the balloon by removing the balloon image from the browser DOM.

Balloon Pop Demo 

For comparison, here’s how the animation would be implemented using the ASP.NET AJAX Control Toolkit’s AnimationExtender:

<asp:Image id=”Balloon1″ ImageUrl=”~/Images/balloon.gif” runat=”server”
    style=”position: absolute; left: 320px; top: 260px; width: 74px; height: 110px” />
<ajaxToolkit:AnimationExtender ID=”AnimationExtender1″ TargetControlID=”Balloon1″ Runat=”server”>
    <Animations>
        <OnClick>
            <Sequence>
                <Parallel Duration=”0.2″ Fps=”40″>
                    <Scale ScaleFactor=”8″ Center=”true” />
                    <FadeOut />
                </Parallel>
               
           
       
   

function removeBalloon(id)
{
    var image = $get(id);
    image.parentNode.removeChild(image);  // Remove the image
}

It’s more difficult using the animation classes in PreviewGlitz.js. There is no equivalent of AnimationExtender’s <Parallel> element, so you create a Sys.Preview.UI.Effects.CompositeAnimation object and encapsulate all the subanimations inside it. I used NumberAnimations to simultaneously animate the width, height, x-position, and y-position of the balloon, plus a FadeAnimation to fade it out. (Makes you appreciate AnimationExtender’s ScaleAnimation, doesn’t it?) Once the CompositeAnimation has run its course, a bit of JavaScript needs to be executed to remove the balloon image from the DOM. At first glance, it appears that you can register a handler for the end event that fires when the animation is complete. However, in what is probably an oversight in the January CTP, PreviewGlitz.js’s animation classes don’t fire end events. So I set up a timer to check the animation progress and remove the image from the DOM after the animation ends. Not pretty, but it works.

Here is the key source code:

<img id=”Balloon1″ src=”Images/balloon.gif” onclick=”popBalloon(‘Balloon1’);”
    style=”position: absolute; left: 320px; top: 260px; width: 74px; height: 110px” />

var _scaleFactor = 8; // Modify this number to change the scale factor
var _image, _animation;
    
function popBalloon(id)
{
    if (_animation != null)
        return; // Prevent overlapping animations
    _image = $get(id);
    var width = parseFloat(_image.style.width);
    var height = parseFloat(_image.style.height);
    var x = parseFloat(_image.style.left);        
    var y = parseFloat(_image.style.top);       
    //
    // Use a CompositeAnimation object to “explode” the image by
    // simultaneously scaling, moving, and fading it.
    //
    var a1 = new Sys.Preview.UI.Effects.NumberAnimation();
    a1.set_target(_image);
    a1.set_property(‘style’);
    a1.set_propertyKey(‘width’);
    a1.set_startValue(width);
    a1.set_endValue(width * _scaleFactor);
    var a2 = new Sys.Preview.UI.Effects.NumberAnimation();
    a2.set_target(_image);
    a2.set_property(‘style’);
    a2.set_propertyKey(‘height’);
    a2.set_startValue(height);
    a2.set_endValue(height * _scaleFactor);
    var a3 = new Sys.Preview.UI.Effects.NumberAnimation();
    a3.set_target(_image);
    a3.set_property(‘style’);
    a3.set_propertyKey(‘left’);
    a3.set_startValue(x);
    a3.set_endValue(x – (width * (_scaleFactor – 1)) / 2);
    var a4 = new Sys.Preview.UI.Effects.NumberAnimation();
    a4.set_target(_image);
    a4.set_property(‘style’);
    a4.set_propertyKey(‘top’);
    a4.set_startValue(y);
    a4.set_endValue(y – (height * (_scaleFactor – 1)) / 2);
    var a5 = new Sys.Preview.UI.Effects.FadeAnimation();
    a5.set_target(new Sys.Preview.UI.Image(_image));
    a5.set_effect (Sys.Preview.UI.Effects.FadeEffect.FadeOut);
    _animation = new Sys.Preview.UI.Effects.CompositeAnimation();
    _animation.get_animations().add(a1);
    _animation.get_animations().add(a2);
    _animation.get_animations().add(a3);
    _animation.get_animations().add(a4);
    _animation.get_animations().add(a5);
    _animation.set_duration(0.2);
    _animation.set_fps(40);
    _animation.play();
    //
    // Because the animation classes in PreviewScript.js do NOT fire end
    // events (even though you can register end handlers), manually set a
    // timer to fire after 0.4 seconds so we can remove the image from the
    // DOM once the animation is complete.
    //
    var timer = new Sys.Preview.Timer();
    timer.initialize();
    timer.set_enabled(true);
    timer.set_interval(400);
    timer.add_tick(removeBalloon);
}
function removeBalloon(sender)
{
    if (!_animation.get_isPlaying())
    {
        sender.set_enabled(false);              // Disable the timer
        _image.parentNode.removeChild(_image);  // Remove the image
        _animation = null;
    }
}

Understanding how to do animations with PreviewGlitz.js is more than academic. If you want to use ASP.NET AJAX to do animations on non-ASP.NET platforms such as PHP and ColdFusion, you can’t use the ASP.NET AJAX Control Toolkit because it’s ASP.NET-specific. But you can use PreviewGlitz.js. And now there’s an example to go by.