Chapter 25. Timers and Animating Elements

Users have come to expect a certain level of polish in the applications they use — particularly their operating systems. Every new version adds more visual goodness that, while not entirely necessary, enhances the user's experience. Features like menus that fade in and out, and windows that scale while maximizing and minimizing, are perfect examples of how unobtrusive animations can add visual flair while still maintaining the original functionality of showing or hiding a menu or resizing a window.

In Lesson 24 you allowed a user to click an element and drag it to wherever he wishes; you essentially wrote an animation script. The animation was limited and dependent upon the user's action, but the element moved to a different set of coordinates in sync with the mouse pointer — a movement animation.

Animations such as the fading in and out in menus aren't so dependent on user interaction. Sure, the user has to initiate an event to cause the animation to run, but a menu fades in over a certain period — not in relation to where the user moves the mouse pointer.

This type of animation is akin to motion pictures or cartoons — a character's fluid movement is broken into a number of frames that are shown in rapid sequence. Each frame is shown for a certain time (usually one thirtieth of a second) to mimic movement on the screen.

On a web page, you modify an element (the character) bit-by-bit (or frame by frame) over a certain period using timers. In this lesson you'll learn about two methods that are used for timing. Then you'll use the timers to create an animation.

SETTING A DELAY — THE SETTIMEOUT() METHOD

The first method is the setTimeout() method. It is a member of the window object, so it is global. It's essentially a delay: Its purpose is to execute a function once after a certain amount of time has elapsed. It accepts two arguments: a function to execute and the amount of time in milliseconds to wait before executing the code. Its syntax looks like the following:

function doSomething() {
    alert("Hello, timeout!");
}

var timer = setTimeout(doSomething, 1000);

The setTimeout() method returns a numeric value, which is the timer's unique ID number. While it's not necessary to use this ID number, it does come in handy, as you'll see in a few moments.

In this code the setTimeout() method is called by passing the doSomething() function as the first argument, and a number value of 1000 as the second argument. Remember, the second parameter is the amount of time in milliseconds. The number 1000 actually represents one second.

After the setTimeout() method executes, the JavaScript engine waits one second and then executes doSomething(). The engine, however, does not delay any statements that may appear after the setTimeout() call — it delays only the execution of doSomething(). For example, look at the following code:

function doSomething() {
    alert("Hello, timeout!");
}

var timer = setTimeout(doSomething, 1000);
alert("After setTimeout() call");

This code adds a statement to the end of the previous example. When this code executes, the setTimeout() call queues the doSomething() function to be called in one second, and then an alert box displays the text "After setTimeout() call." Then, and only after a second has passed since the call to setTimeout(), doSomething() executes. So the engine does not delay all code; it delays only the code specified as the first argument to setTimeout().

Even though setTimeout() is a one-shot timer, you can use a form of recursion (a function's calling itself) to call setTimeout() every time doSomething() executes. Look at the following code, which removes the alert() call from the previous example and adds a new line (bolded) to doSomething():

function doSomething() {
    alert("Hello, timeout!");
    timer = setTimeout(doSomething, 1000);
}

var timer = setTimeout(doSomething, 1000);

It's a simple modification, but it drastically changes how the code behaves. It creates an infinite loop. The call to setTimeout() outside the function initiates the loop by setting a one-second timeout before executing doSomething(). Then, when the second expires, doSomething() executes, which sets another one-second timeout to call doSomething() again. Every time doSomething() executes, a new one-second timeout is set to call doSomething().

Notice how the timer variable is reused. Since doSomething() executes when a timeout expires, the timeout ID stored in timer becomes useless. So instead of a new variable being created, timer is reused to store the new timeout's ID. This is advantageous because, as you may have guessed, a loop such as the preceding one could potentially be troublesome. A never-ending loop, especially one that pops up an alert window every second, can be very annoying.

Thankfully, when setTimeout() was added to Netscape 2 a companion method called clearTimeout() was included as well. As its name implies it cancels a timeout set with setTimeout(), and it accepts a timeout ID as an argument. Look at the following code to see it in action:

function doSomething() {
    alert("Hello, timeout!");
    timer = setTimeout(doSomething, 1000);
}

var timer = setTimeout(doSomething, 1000);
clearTimeout(timer);

Calling clearTimeout() and passing it timer cancels the timeout set in the statement before it can expire. Remember that setTimeout() doesn't stall the execution of the rest of the code. As a result, the timeout is cleared and doSomething() never executes.

Note

Calling clearTimeout() on an expired timer ID has no effect and doesn't throw an error.

Many years ago setTimeout() was often used to execute a function a certain number of times at particular time intervals, as the following code demonstrates:

function doSomething() {
    if (counter < 5) {
        alert("Hello, timeout!");
        counter++;
        timer = setTimeout(doSomething, 1000);
    }
}

var counter = 0;
var timer = setTimeout(doSomething, 1000);

This code adds a counter variable, and as long as the value of counter is less than 5, setTimeout() delays the execution of doSomething() again. If counter is greater than 5, the timeout isn't issued again and the loop exits.

This method of repeating a function with a time delay is still used today, but setTimeout() is usually more appropriately used to defer execution of a function. If you want to repeat a function call at regular time intervals, look to the setInterval() method.

SETTING AN INTERVAL — THE SETINTERVAL() METHOD

The setInterval() method, as implied in the previous section, executes a function at regular intervals of time. The following code executes the doSomething() function at regular intervals of one second:

function doSomething() {
    alert("Hello, timeout!");
}

var timer = setInterval(doSomething, 1000);

doSomething() will execute every second until either it is canceled in code or a different page is loaded in the browser. Like setTimeout(), the setInterval() method returns a unique timer ID that can be passed to the clearInterval() companion method. The following code re-creates the timeout with a timer code from the previous section, using setInterval() and clearInterval():

function doSomething() {
    if (counter < 5) {
        alert("Hello, timeout!");
        counter++;
    } else {
        clearTimeout(timer);
    }
}

var counter = 0;
var timer = setInterval(doSomething, 1000);

There's no need to call setInterval() more than once; its job is to repeat the provided function for as long as it's allowed to. So the code determines if counter is less than 5 and, if it isn't, calls clearTimeout() to clear the timer.

Note

setInterval() waits until the specified amount of time has passed before executing the provided function for the first time.

The setInterval() and clearInterval() methods are widely used to perform animations, and you'll use them now to create an animation script that resizes a box.

TRY IT

In this lesson, you learn about timers and what they're used for. In this section you use one of them, setInterval(), to animate an element.

Lesson Requirements

For this lesson, you need a text editor; any plain text editor will do. For Microsoft Windows users, Notepad is available by default on your system or you can download Microsoft's free Visual Web Developer Express (www.microsoft.com/express/web/) or Web Matrix (www.asp.net/webmatrix/). Mac OS X users can use TextMate, which comes as part of OS X, or download a trial for Coda (www.panic.com/coda/). Linux users can use the built-in VIM.

You also need a modern web browser. Choose any of the following:

  • Internet Explorer 8+

  • Google Chrome

  • Firefox 3.5+

  • Apple Safari 4+

  • Opera 10+

Create a subfolder called Lesson25 in the JS24Hour folder you created in Lesson 1. Store the files you create in this lesson in the Lesson25 folder.

Step-by-Step

  1. Start by typing the following HTML:

    <html>
    <head>
        <title>Lesson 25: Example 01</title>
        <style type="text/css">
        .box {
            width: 100px;
            height: 100px;
            background-color: navy;
        }
        </style>
    </head>
    <body>
    
    <div id="divNavyBox" class="box"></div>
    
    <script type="text/javascript">
    
    </script>
    </body>
    </html>

    This is the basis of your web page. It has a style sheet containing a CSS class called box. This class sets the height and width of the element to 100px, and gives it a background color of navy. Inside the <body/> is a <div/> element with an ID of divNavyBox, and it uses the box class.

  2. Now add some JavaScript code. Create an object called animated, and give it the members in the following code:

    <html>
    <head>
        <title>Lesson 25: Example 01</title>
        <style type="text/css">
        .box {
            width: 100px;
            height: 100px;
            background-color: navy;
        }
        </style>
    </head>
    <body>
    
    <div id="divNavyBox" class="box"></div>
    
    <script type="text/javascript">
    var animated = {
        timer : null,
        el : document.getElementById("divNavyBox"),
        startGrowAnimation : function() {
    
        },
        startShrinkAnimation : function() {
    
        },
        stopAnimation : function() {
            clearInterval(this.timer);
        },
        doAnimation : function(amount) {
    
        }
    };
    </script>
    </body>
    </html>

    This code adds a few members to the animated object. The timer property contains the interval's unique ID; the el property contains the <div/> element object; and the four methods start, stop, and perform the animations. The stopAnimation() method is simple: It calls clearInterval() and passes the timer property.

  3. Let's start with the doAnimation() method. Its purpose is to perform the growing and shrinking animations. It accepts one argument, a numeric value, which can be either positive or negative. If positive, the box grows by the amount specified. If negative, the box shrinks by the amount specified. The method's body is in bold:

    <html>
    <head>
        <title>Lesson 25: Example 01</title>
    <style type="text/css">
        .box {
            width: 100px;
            height: 100px;
            background-color: navy;
        }
        </style>
    </head>
    <body>
    
    <div id="divNavyBox" class="box"></div>
    
    <script type="text/javascript">
    var animated = {
        timer : null,
        el : document.getElementById("divNavyBox"),
        startGrowAnimation : function() {
    
        },
        startShrinkAnimation : function() {
    
        },
        stopAnimation : function() {
            clearInterval(this.timer);
        },
        doAnimation : function(amount) {
            var size = this.el.offsetWidth;
    
            if ((amount > 0 && size < 200) || (amount < 0 && size > 0)) {
                this.el.style.width = size + amount + "px";
                this.el.style.height = size + amount + "px";
            } else {
                this.stopAnimation();
            }
        }
    };
    </script>
    </body>
    </html>

    Because the <div/> element is in the shape of a square, the doAnimation() method keeps things simple by retrieving only the element's width with the element's offsetWidth property.

    Next, an if statement determines whether to grow or shrink the element by determining whether amount is positive or negative. It also determines how big or small the element gets. If amount is positive, the element will grow to a maximum of 200 pixels high and wide. If negative, the element will shrink to a minimum of zero pixels. The element's dimensions are adjusted by the specified amount as long as its size is within the hard-coded limits and the stopAnimation() method executes when either limit is reached.

  4. Now add the bold lines in the following code:

    <html>
    <head>
        <title>Lesson 25: Example 01</title>
        <style type="text/css">
        .box {
            width: 100px;
            height: 100px;
            background-color: navy;
        }
        </style>
    </head>
    <body>
    
    <div id="divNavyBox" class="box"></div>
    
    <script type="text/javascript">
    var animated = {
        timer : null,
        el : document.getElementById("divNavyBox"),
        startGrowAnimation : function() {
            this.stopAnimation();
            this.timer = setInterval(function() {
                animated.doAnimation(5);
            }, 10);
        },
        startShrinkAnimation : function() {
    
        },
        stopAnimation : function() {
            clearInterval(this.timer);
        },
        doAnimation : function(amount) {
            var size = this.el.offsetWidth;
    
            if ((amount > 0 && size < 200) || (amount < 0 && size > 0)) {
                this.el.style.width = size + amount + "px";
                this.el.style.height = size + amount + "px";
            } else {
                this.stopAnimation();
            }
        }
    };
    </script>
    </body>
    </html>

    The first line of this code calls stopAnimation(). This is absolutely vital because if startGrowAnimation() is called while another animation is in progress, the timer property will be overwritten with a new timer ID, and the interval timer that was running will stop only when the page is reloaded. By calling stopAnimation() first, you can stop the current animation (if there is one) and safely begin the grow animation.

    The second statement calls setInterval() and passes an anonymous function to it. Inside the anonymous function is a call to animated.doAnimation(), with a value of 5 being passed. An anonymous function is used here because you need to pass a value to the doAnimation() method in order for it to work.

  5. Now add the code for startShrinkAnimation(). It's very similar to that for startGrowAnimation(). The new code is bold in the following:

    <html>
    <head>
        <title>Lesson 25: Example 01</title>
        <style type="text/css">
        .box {
            width: 100px;
            height: 100px;
            background-color: navy;
        }
        </style>
    </head>
    <body>
    
    <div id="divNavyBox" class="box"></div>
    
    <script type="text/javascript">
    var animated = {
        timer : null,
        el : document.getElementById("divNavyBox"),
        startGrowAnimation : function() {
            this.stopAnimation();
            this.timer = setInterval(function() {
                animated.doAnimation(5);
            }, 10);
        },
        startShrinkAnimation : function() {
            this.stopAnimation();
            this.timer = setInterval(function() {
                animated.doAnimation(−5);
            }, 10);
        },
        stopAnimation : function() {
            clearInterval(this.timer);
        },
        doAnimation : function(amount) {
            var size = this.el.offsetWidth;
    
            if ((amount > 0 && size < 200) || (amount < 0 && size > 0)) {
                this.el.style.width = size + amount + "px";
                this.el.style.height = size + amount + "px";
            } else {
                this.stopAnimation();
            }
        }
    };
    </script>
    </body>
    </html>

    The only difference here is the value passed to doAnimation(). It is −5, so the element will shrink in size by five pixels.

  6. Now add the following <a/> elements to call the start and stop methods:

    <html>
    <head>
        <title>Lesson 25: Example 01</title>
        <style type="text/css">
        .box {
            width: 100px;
            height: 100px;
            background-color: navy;
        }
        </style>
    </head>
    <body>
    <a href="#" onclick="animated.startGrowAnimation(); return false;">Grow Box</a>
    <a href="#" onclick="animated.startShrinkAnimation(); return false;">Shrink Box</a>
    <a href="#" onclick="animated.stopAnimation(); return false;">Stop Animation</a>
    <div id="divNavyBox" class="box"></div>
    
    <script type="text/javascript">
    var animated = {
        timer : null,
        el : document.getElementById("divNavyBox"),
        startGrowAnimation : function() {
            this.stopAnimation();
            this.timer = setInterval(function() {
                animated.doAnimation(5);
            }, 10);
        },
        startShrinkAnimation : function() {
            this.stopAnimation();
            this.timer = setInterval(function() {
                animated.doAnimation(−5);
            }, 10);
        },
        stopAnimation : function() {
            clearInterval(this.timer);
        },
        doAnimation : function(amount) {
            var size = this.el.offsetWidth;
    
            if ((amount > 0 && size < 200) || (amount < 0 && size > 0)) {
                this.el.style.width = size + amount + "px";
                this.el.style.height = size + amount + "px";
    } else {
                this.stopAnimation();
            }
        }
    };
    </script>
    </body>
    </html>
  7. Save this file as lesson25_example01.htm, and open it in any browser. Click the links to grow and shrink the element, and also click the stop link to stop a running animation.

To get the sample code files, you can download Lesson 25 from the book's website at www.wrox.com.

Note

Please select Lesson 25 on the DVD to view the video that accompanies this lesson.

Step-by-Step
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.76.204