DHTML Lab - dhtmlab.com - Smooth animation using DHTML | 4 | WebReference

DHTML Lab - dhtmlab.com - Smooth animation using DHTML | 4


Smooth animation using DHTML
part 1 - introduction


I would like to thank my employer InfoStream ASA for graciously donating both time and computer resources for this project and that they've allowed me to publish my results. I'd also like to thank my fellow employees there as well as my girlfriend for letting me borrow their computers for testing.

My thanks also go to Jim Ley, Steven Champeon and Scott Porter for reading throuh a draft of this article and giving thoughtful comments and recommendations. Jim Ley is also the author of the DirectAnimation test. I'd like to thank Steven Champeon again for being my favourite list mom, and allowing me to look at some of his wonderfully written code and for supplying very useful comments.

First article in a series

This article is the first in a series of articles looking into browser DHTML performance. The tests I've used here are very simple, allowing me to identify basic differences between the browsers and platforms.

Future articles will examine animation under more difficult conditions. There will be movement of multiple objects, movement in all three dimensions, and also tests using pages with regular content to see how that affects performance.

What is a layer?

For the purposes of this article, we will refer to CSS positioned elements as layers. The creation of layers for both browsers, both in-page and dynamically, has been discussed with countless examples here at DHTML Lab since Column 2. To refresh our memories, a layer, suitable for our tests, may be specified with the DIV tag, using this syntax:

<DIV ID="myDiv"
 STYLE="position: absolute; left: 100px; top: 100px;">
layer content goes here...

This code creates a layer with ID "myDiv" positioned 100 pixels in from the left and 100 pixels down from the top of the browser's document area. This layer can be referenced in MSIE as document.all['myDiv'] and in Navigator as document.layers['myDiv']. In Mozilla the DIV can be referenced by using the method "getElementById()".

Moving a layer

Once you've created a layer it's fairly easy to move it around. Netscape Navigator gives you the moveTo(x,y) method which moves the layer you refer to the x- & y-coordinates you give to it. In MSIE you can do it several ways, but one way is to use the properties style.left and style.top. You set the properties to the same x- and y-coordinate values as Navigator's moveTo() to move the layer to the same position.

When you target Navigator 4.x and MSIE 4/5 you can quite easily write one combined moveTo() function so you won't have to fiddle around with more than one way to move a layer. All you do is look for Navigator by checking for document.layers and MSIE by checking for document.all. Then you set values accordingly. The function I've ended up with, and that I use in all tests is:

function myMoveTo(layerID, xpos, ypos) {
/* moves layer 'layerID' to xpos, ypos */
    if(document.layers) {
        document.layers[layerID].moveTo(xpos, ypos);
    } else if(document.all) {
        document.all[layerID].style.left = xpos;
        document.all[layerID].style.top = ypos;

Animating a layer's movement

So far I've shown how to move a layer. This article isn't really about moving a layer from point A to point B though. It's about moving a layer from point A to point B and stopping at a whole bunch of places in between. In my case the whole bunch of points is in a straight line going from point A to point B.

"So how do you do that?" you might wonder. It's not very difficult. Instead of moving the layer directly from point A to point B you create a way of stepping through intermediate points between A and B, and then you use a loop to do it. In calls itself with a slight delay. The delay is usually created by calling the setTimeout() method. setTimeout() takes two parameters, a string representing a JavaScript statement to be evaluated and a numerical value which is the delay in milliseconds before the evaluation occurs. The resulting function could have this structure:

function animateLayer() {
  xpos = some_calculation();
  ypos = some_calculation();
  myMoveTo(layerID, xpos, ypos);
  if(!done) {
    setTimeout(animateLayer, delay);

The calculation to find where the layer should be moved to can be quite complicated, but in my case it's fairly simple. My functions look at what direction we're moving and then go 1 pixel in that direction. If you wanted to move in a circle, or an elliptical path the calculation would be slightly more complicated.

To achieve smooth animation you will need to do the movement at least 25 times per second. The delay is then too short for the eye to notice, so the layer will appear to move in a fluid motion. If you go below 25 times per second the eye will notice the steps. This is very important. You wouldn't want the layer movement to look like it's slowly stepping forward, simply because that wouldn't be appealing to the users. They'd probably be impressed by the animation the first time around, but the second time they'll notice the stepping.

To achieve 25 movements per second (or 25 frames per second, in cinematic terms) you need to have a delay between each movement of less than 40ms (1000ms/25 = 40ms). The delay would preferably be slightly less than 40ms, but there's no need to do it even shorter than that since you'd spend CPU resource for no cause (this is simplified, but you probably get the idea).

This article has been written because I've tried to set the delay to less than 40ms without seeing any visual improvement. My system refused to give me anything that looked like smooth animation, no matter how hard I tried. This article and its tests tries to figure out where the problem is, and what can be done to fix the problem. To find out where the problem was I needed to create a test. Let's look at how that was done.

Produced by Morten Wang and

All Rights Reserved. Legal Notices.
Created: Jan 03, 2000
Revised: Jan 03, 2000

URL: http://www.webreference.com/dhtml/column28/part-1.html