Hypermedia Production Banner

Lab: DHTML Animation

Step 1: Setup

[1.1] All the files you will need for this lab are stored in the directory called animationLab within productionShare on Crow. Download this directory to your local machine. Launch a browser and a text editor.

[1.2] Open the file start.htm in your browser and in your text editor. A finished.htm page is also available for reference. Save start.htm as working.htm so you can return to the original if necessary.

[1.3] Look at what you are seeing, as my favorite old VW repair book used to say. In the HEAD portion of the document you have a minimal stylesheet (not involved in today's maneuvers) and a <SCRIPT></SCRIPT> container with two blank function bodies. We'll come to these in due time.

The BODY portion of the document contains two DIVs. The first houses only a single IMG tag. The transparent GIF invoked in this tag has some pretty interesting dimensions: 2400 by 1800. It's a very large green rectangle with a vaguely keyhole-shaped cutout in the center. This DIV serves as a moveable mask that screens out all but a small portion of the text that sits beneath it.

That text lives in the second DIV. It represents your tax dollars at work... or play... or something. You don't need to worry about this DIV. (It's too late to worry about the contents.)

To see what we're building, open finished.htm and watch the show. Click the mouse to see what happens when you do that. You can also view a somewhat slicker version of this project by visiting the demo page.

Step 2: A Simple Animation

[2.1] First we need to set up a pair of variables to store the horizontal (X) and vertical (Y) position of our moveable or masking DIV. Find the <SCRIPT></SCRIPT> container in the head portion of working.htm Immediately within that container but not within either of the blank function bodies, insert these two lines of code:

    var spotX = -800;
    var spotY = -600;

These declarations set up variables that will track the X and Y coordinates of the DIV. They are set to the initial locations of the DIV, which has its left edge at negative 800 and its top edge at negative 600 on the coordinate system. You'll see these same numbers in the in-line style attribute for the DIV.

These numbers are so large (in absolute value) because the masking DIV itself is fairly sizeable--2400 pixels wide and 1800 pixels high, so that it will cover the entire visible window even at fairly high resolutions. The numbers are negative because the edges of the masking DIV start out far to the left of the left margin of the screen (whose X coordinate is 0) and also far above the top margin (whose Y coordinate is 0).

[2.2] Now let's write a simple, linear animation in order to introduce the basic logic of the procedure. Within the function body of wander(), enter the following:

  spotX +=4;
  spotY +=4;
  document.all.tags("div").item(0).style.left = spotX;
  document.all.tags("div").item(0).style.top = spotY;
  if(spotX < -700) setTimeout("wander()", 1);

Be sure to type those long lines as precisely as you can: you have to get the dot notation just right. In the final line, pay close attention to the parentheses.

The first two lines above increment (increase) the values for the left and top edges by 4 pixels each. The second two lines plug these incremented values back into the left and top properties of the masking DIV, moving it across the screen. The final line automatically repeats the function if the X value has not reached -700, which is to say, it recycles the animation routine 25 times, until 100 pixels have been added to the X value of the DIV, moving it from -800 (its original position) to -700.

Since the Y value changes each time the X value changes (see the fourth line in the script above), this script moves the DIV along a 100-pixel diagonal that slopes down and to the right. Save your work, reload working.htm in your browser, and see what you see. If you feel adventurous, change the increment operator in the first two lines to a decrement operator (-=). Change the if condition in the fifth line so that it test for spotX > -900. The DIV and its keyhole cutout should move up and to the left.

Step 3: Continuous Animation

[3.1] Now we'll make the masking DIV move around the screen as if it were contained within an invisible box. This means that at some point the DIV will need to reverse direction: when it runs up against the lefthand margin of its box, it will have to turn around and head to the right, and likewise with right, top, and bottom limits. To control the direction of movement, we need to create two new variables to store directional information.

Look into the <SCRIPT></SCRIPT> container outside the function bodies. Find the existing variable declarations. Add these two new lines:

  var XDir = "plus";
  var YDir = "plus";

These declarations arbitrarily fix the initial direction of movement as down and to the left. You can change either or both variables to "minus" if you prefer. (As you'll see, the values "minus" and "plus" are themselves arbitrary and refer to a piece of code we're about to create.)

[3.2] Move your cursor down into the body of the wander() function until you come to the first two lines, where the variables spotX and spotY have their values changed. Delete these two lines and in their place write:

  if(XDir == "plus") spotX +=4;
  if(XDir == "minus") spotX -=4;
  if(YDir == "plus") spotY +=4;
  if(YDir == "minus") spotY -=4;

These four statements cover the possible variations of movement within an X/Y coordinate system: right, left, down, and up.

For reference, your wander() function should now look something like this:

function wander()
  {
    if(XDir == "plus") spotX +=4;
    if(XDir == "minus") spotX -=4;
    if(YDir == "plus") spotY +=4;
    if(YDir == "minus") spotY -=4;
    document.all.tags("div").item(0).style.left = spotX;
    document.all.tags("div").item(0).style.top = spotY;
    if(spotX < -700) setTimeout("wander()", 1);

[3.3] You can leave the two statements that reset the left and top properties exactly as they are, but delete the last line of the function, the one containing the setTimeout() statement. In its place put this much simpler statement:

  setTimeout("wander()", 1);

If you execute this code (uh, not a good idea), you'll see your keyhole drift majestically off into cyberspace. This is not what we want. To keep the wraps in place, we need to define that invisible box. This we'll do by adding four lines to the current script. Put them in immediately after the line

  if(YDir == "minus") spotY -=4;

The lines you will enter are:

  if(spotX > -650) XDir = "minus";
  if(spotX < -1150) XDir = "plus";
  if(spotY > -450) YDir = "minus";
  if(spotY < -800) YDir = "plus";

Again, be sure to copy the lines above precisely. These statements define limits of movement for the masking DIV. They're all negative because we're moving the edges of a very large rectangle which always remain off-screen. They're not symmetrical because we're moving them over an oblong rectangle. If you're curious, you can work out the geometry on a piece of graph paper (I sure had to); but it's not vital that you understand this aspect of the project right away.

[3.4] Save your work, switch to the browser, and reload. The keyhole cutout should now zoom and bounce around the screen. (Your "zoom" may vary.)

Step 4: Interrupt and Reset the Animation

[4.1] In the demo version of this project, the user can (momentarily) reposition the cutout by clicking in a particular place. Now we'll add this tantalizing feature. Two system variables, clientX and clientY, are exposed for every mouseClick. Let's begin by using those variables to set the masking DIV to the point at which the mouse was clicked.

Find the jumpTo() function body. Within it enter the following two lines:

  document.all.tags("div").item(0).style.left = window.event.clientX;
  document.all.tags("div").item(0).style.top = window.event.clientY;

If you save, reload, and test at this point, you won't see any effect; that's because we haven't activated the jumpTo() function yet. To do that, add the following handler to the initial <BODY> tag for working.htm:

  onClick="jumpTo()"

If you save, load, and test now, you should see the mask DIV jump down to the click point--spoiling the visual effect pretty badly. This is because the code we've written so far resets the left and top edges of the masking DIV. To preserve the illusion of a traveling cutout, we need to reposition the edges of the DIV so that the space in the middle (the cutout) coincides with the click point.

[4.2] To complete the jumpTo() function, add these two lines ahead of the two lines that already exist:

  spotX = window.event.clientX-1200;
  spotY = window.event.clientY-900;

These are our old friends the X and Y tracking variables that we used in the animation function. We can use them here as well. The values we subtract from each correspond to half the width and height of the masking DIV, respectively. This offsets the DIV from the click point so that its middle, not its edge, coincides.

To finish the function, alter the two original lines so that they read thus:

  document.all.tags("div").item(0).style.left = spotX;
  document.all.tags("div").item(0).style.top = spotY;

Save, reload, and test. When you click, the keyhole cutout should fly to the click point, then continue its relentless course.

As always, thanks to John Coliton for helping to debug and improve this lab.




University of Baltimore Logo
Copyright © 2000 Stuart Moulthrop