Creating Sophisticated Animations with the Microsoft AJAX Library

13 Comments April 4, 2007


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>
                <ScriptAction Script="removeBalloon('Balloon1');" />
            </Sequence>
        </OnClick>
    </Animations>
</ajaxToolkit:AnimationExtender>

<script type="text/javascript">
function removeBalloon(id)
{
    var image = $get(id);
    image.parentNode.removeChild(image);  // Remove the image
}
</script>


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" />

<script type="text/javascript">
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;
    }
}
</script>


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.


13 Comments

  • Gravatar Image
    Chaves (Portugal) April 4, 2007 4:04 PM

    GREAT!! Thanks Jeff

  • Gravatar Image
    Chaves April 4, 2007 4:07 PM

  • Gravatar Image
    Ricardo Calejo April 4, 2007 4:26 PM

    To a person who doesn't like much Javascript, u sure rule! :D Tks for the chat in TechDays, was a pleasure to meet u, and about this post? Nice... simply nice...

  • Gravatar Image
    Luis Abreu April 5, 2007 12:27 PM

    Jeff, have you taken a look at the client classes in the AJAX Toolkit? According to my sources, animation classes present on the toolkit are better than those you have on the preview bits and will get better support in the future (according to some, the preview classes will be fropped - including the drag-and-drop classes - and everything will be moved into the toolkit). The only problem I see with the toolkit client classes is that it's almost impossible to use only client code (ie, you need to drop the dll on the bin folder or you'll have to go through the client code and remove several references to elements which are inserted on the page by the dll on the server side)

  • Gravatar Image
    jprosise April 5, 2007 8:02 PM

    Yes, I have looked at the ones in the toolkit. They're very similar to the ones in the CTP (but slightly better). I used the ones in the CTP because those are the ones that non-ASP.NET developers are supposed to use, although there's nothing preventing them from extracting the script resources from the toolkit assembly and using those.

  • Gravatar Image
    Chris Spyker April 13, 2007 12:17 AM

    Very cool! But it doesn't seem to work in Firefox. Any chance of making the code cross-browser-compatible? Or am I missing something?

    Thanks for a great class on Tues/Wed!

  • Gravatar Image
    jprosise April 13, 2007 6:49 AM

    It should work in Firefox 2.0. I haven't tested it there, but if it doesn't work there, something's wrong because the Microsoft AJAX Library supports that platform. I'll check it out and see if something's missing.

  • Gravatar Image
    jprosise April 14, 2007 8:14 AM

    Gee, you're right: it doesn't work in Firefox. The fade animation works, but the scaling does not. I wonder if this is because the animation classes are part of the CTP and not part of the core.

    Interestingly enough, I have a version of the same page that uses the toookit animation classes, and it works better in FireFox than it does in IE! I'll compare the JavaScript used by the toolkit animation classes to the JavaScript in PreviewGlitz.js to see what's different.

  • Gravatar Image
    Chris Spyker April 16, 2007 12:18 AM

    I noticed that the toolkit animation page worked in Firefox as well. The first time I tried the javascript page I only had the 1.0 release of ASP.NET AJAX installed. I thought maybe it wasn't working because I didn't have the CTP installed, so I downloaded and installed that as well. However, it didn't make a difference. Very odd indeed.

  • Gravatar Image
    Robert Werner June 15, 2007 10:14 PM

    Jeff,

    I wonder if you've had any experience with the HoverExtender? I was really excited by this control but then found a serious bug. You can see it here: http://pocketpollster.com/beta/products.aspx

    Hover once and everything works fine. But slowly move the cursor in a 2nd time and you'll see that the hover is activated when you hit the extents or the LARGER image, not the original thumbnail.

    My intuition tells me that this is a bug that could be resolved by a fix in JavaScript but I don't know that language. :-(

    Anyhow, I was hoping you might know a solution.

    Robert Werner
    Vancouver, BC

  • Gravatar Image
    rishi August 30, 2010 1:35 AM

    Hi Jeff,
    It was good example.
    Is there any control that give us the facility of drag and drop feature from list box to any other control or from list box to list box in asp.net only.



  • Gravatar Image
    Ashish December 21, 2010 4:03 PM

    Hi Jeff,

    I saw your example of Drag and Drop and want to extend the same for user control, to be able to drag and drop user controls on the page. Could you help me on that.

  • Gravatar Image
    Chandan Dey February 28, 2011 2:33 PM

    I need help in drag drop in asp.net. I send you mail in wicked@microsoft.com, but it was bounced.

    Please tell me your mail id, i will send you the test application.

    Thanks,
    Chandan

    My mail id is : deychandan@hotmail.com

Have a Comment?

Archives

Tags

Blogs