• 沒有找到結果。

Animation basics

在文檔中 Second Edition (頁 188-195)

An Animated Slideshow

What this chapter covers:

• The basics of animation

• Web page enhancement with animation

In this chapter, you’ll see one of the most dynamic applications of CSS-DOM: the ability to animate elements.

Animation basics

The previous chapter introduced the DOM’s ability to update the styles attached to a document. Using JavaScript to add presentational information can save you time and effort, but, for the most part, CSS remains the best tool for the job.

There’s one area, however, where CSS can’t really help much. If you want to change an element’s style information over time, you’ll probably need to use JavaScript. CSS3 introduces a number of different transition methods that allow you to animate elements. However, currently, browser support without vendor-specific prefixes is minimal. JavaScript, on the other hand, allows you to execute functions at set intervals. This means that you can alter an element’s style with the passage of time.

Animation is the perfect example of this kind of change. In a nutshell, animation involves changing an element’s position over time.

Position

An element’s position in the browser window is presentational information. As such, it is usually added using CSS. Here’s an example that sets an element’s position on the page:

element {

position: absolute;

top: 50px;

left: 100px;

}

That will position the element 100 pixels from the left of the browser window and 50 pixels from the top. Here’s the DOM equivalent of the same information:

element.style.position = "absolute";

element.style.left = "100px";

element.style.top = "50px";

Valid values for the position property are "static", "fixed", "relative", and "absolute". Elements have a position value of "static" by default, which simply means that they appear one after the other in the same sequence as they occur in the markup. The "relative" value is similar. The difference is that relatively positioned elements can be taken out of the regular flow of the document by applying the float property.

By applying a value of "absolute" to an element’s position, you can place the element wherever you want in relation to its container. The container is either the document itself or a parent element with a position of "fixed" or "absolute". It doesn’t matter where the element appears in the original markup, because its position will be determined by properties like top, left, right, and bottom. You can set any of those properties using pixels or percentages.

Setting an element’s top property will place the element a specified distance from the top of the document. An element’s bottom property will place it a specified distance from the bottom of the document. Similarly, left and right can be used to place the element a specified distance from the left and right edges of the document, respectively. It’s a good idea to use either top or bottom, but not both.

Likewise with left and right.

Positioning an element in the document is relatively straightforward. Say you had an element like this:

<p id="message">Whee!</p>

You could set the message element’s position in JavaScript with a function like this:

function positionMessage() {

if (!document.getElementById) return false;

if (!document.getElementById("message")) return false;

var elem = document.getElementById("message");

elem.style.position = "absolute";

elem.style.left = "50px";

elem.style.top = "100px";

}

Calling the positionMessage function when the page loads will position the paragraph 50 pixels from the left and 100 pixels from the top of the browser window:

window.onload = positionMessage;

Better yet, use the addLoadEvent function:

function addLoadEvent(func) { var oldonload = window.onload;

if (typeof window.onload != 'function') { window.onload = func;

Here, the element has been positioned absolutely.

Updating an element’s position is also quite easy. You just need to run a function that updates a style property like top or left:

function moveMessage() {

if (!document.getElementById) return false;

if (!document.getElementById("message")) return false;

var elem = document.getElementById("message");

elem.style.left = "200px";

}

But how do you activate that function? If you execute moveMessage when the page loads, the element’s position will be updated instantaneously. The original positioning, as specified by positionMessage, will be overridden instantly:

addLoadEvent(positionMessage);

addLoadEvent(moveMessage);

Now the element’s position has been changed.

The change in position is immediate. This isn’t true animation. Animation involves changing an element’s position over time.

The problem in this situation is that JavaScript is too efficient. Functions are executed one after another without any noticeable pause. To create animation, you need to create delays, which is what we will look at next.

Time

The JavaScript function setTimeout allows you to execute a function after a specified amount of time has elapsed. It takes two arguments. The first argument is a string containing the function you want to execute. The second argument is the number of milliseconds that will elapse before the first argument is executed.

setTimeout("function",interval)

It’s a good idea to always assign the result of this function to a variable:

variable = setTimeout("function",interval)

You’ll need to do this if you want to cancel the action that has been queued up. You can cancel a pending action using a function called clearTimeout. This function takes one argument, which is a variable that has been assigned to the result of a setTimeout function:

clearTimeout(variable)

Let’s update the positionMessage function so that it calls moveMessage after 5 seconds (5,000 milliseconds):

function positionMessage() {

if (!document.getElementById) return false;

if (!document.getElementById("message")) return false;

var elem = document.getElementById("message");

elem.style.position = "absolute";

elem.style.left = "50px";

elem.style.top = "100px";

movement = setTimeout("moveMessage()",5000);

}

The positionMessage function is called when the page loads:

addLoadEvent(positionMessage);

At first, the message appears at its specified coordinates. After five seconds, the message jumps 150 pixels to the right.

If you want to cancel that action any time before the five seconds elapse, you could do so with this statement:

clearTimeout(movement);

The movement variable refers to the setTimeout function defined in positionMessage. It’s a global variable; it wasn’t declared with the var keyword. This means the action can be canceled outside the positionMessage function.

Incremental movement

Moving an element by 150 pixels after an interval of five seconds is a sort of animation, albeit a very primitive one. Effective animation uses incremental movement. Moving from the starting position to the final location should happen in a series of steps rather than one quick jump.

Let’s update the moveMessage function so that movement occurs incrementally. Here’s the logic behind the new function:

1. Get the element’s current position.

2. If the element has reached its final destination, leave the function.

3. Otherwise, move the element closer to its destination.

4. Repeat from step 1 after a pause.

The first step is getting the element’s current position. We can do this by querying properties of the element’s style property. We want to find the left and top properties. We’ll assign them to the variables xpos and ypos, respectively:

var xpos = elem.style.left;

var ypos = elem.style.top;

When the moveMessage function is called after the positionMessage function, xpos will have a value of

"50px". The ypos variable will have a value of "100px". These values are strings, which presents a bit of a problem. The next step in the function involves arithmetical comparison operators. We need to work with numbers, not strings.

The JavaScript function parseInt can extract numeric information from a string. If you pass it a string that begins with a number, it will return the number:

parseInt(string) Here’s an example:

parseInt("39 steps");

That will return the number 39.

The parseInt function will return whole numbers (integers). If you need to extract numbers with decimal places (floating-point numbers), there is a corresponding parseFloat function:

parseFloat(string)

We’re dealing with integers in the moveMessage function, so we’ll use parseInt:

var xpos = parseInt(elem.style.left);

var ypos = parseInt(elem.style.top);

The parseInt function converts the string "50px" to the number 50. The string "100px" becomes the number 100. Now the xpos and ypos variables contain those numbers.

Note The use of the parseInt function shown here works only when the elements have been assigned a position using a DOM script or the style property.

The next few steps in the moveMessage function require the use of a lot of comparison operators.

The first comparison is a test for equality. We want to find out if xpos is equal to the final left position and if ypos is equal to the final top position. If they are, we’ll exit the function. We can do this test by using the comparison operator, which consists of two equal signs (remember that a single equal sign is used for assignment).

if (xpos == 200 && ypos == 100) { return true;

}

Everything after this line will be executed only if the message element has not reached its final position.

Next, we’ll update the xpos and ypos numbers based on their relationship to the final position. We want to bring them both closer to the final coordinates. If the value of xpos is less than the final left position, increase it by one:

if (xpos < 200) { xpos++;

}

If it’s greater than the final left position, decrease it:

if (xpos > 200) { xpos--;

}

The same applies for the relationship between the ypos variable and the final top position:

if (ypos < 100) {

You can see why we need xpos and ypos to be numbers rather than strings. We’re using the less-than and greater-than operators to compare numerical values and update the variables accordingly.

Now we want to apply the xpos and ypos variables to the style property of the element. We do this by adding the string "px" to their values and applying them to the left and top properties:

elem.style.left = xpos + "px";

elem.style.top = ypos + "px";

Finally, we want to repeat the whole function afresh after a slight pause. We’ll make the pause one hundredth of a second, which is ten milliseconds:

movement = setTimeout("moveMessage()",10);

The finished moveMessage function looks like this:

function moveMessage() {

if (!document.getElementById) return false;

if (!document.getElementById("message")) return false;

var elem = document.getElementById("message");

var xpos = parseInt(elem.style.left);

var ypos = parseInt(elem.style.top);

if (xpos == 200 && ypos == 100) {

}

movement = setTimeout("moveMessage()",10);

}

The message moves across the screen, one pixel at a time. Once the top property is "100px" and the left property is "200px", the function stops. That’s animation. It’s pretty pointless, but it’s animation nonetheless. We will be applying the same principles to something much more useful later in this chapter.

Abstraction

As it stands, the moveMessage function accomplishes a very specific task. It moves a specific element to a specific place, pausing for a specific amount of time between movements. All of that information is hard-coded into the function:

function moveMessage() {

if (!document.getElementById) return false;

if (!document.getElementById("message")) return false;

var elem = document.getElementById("message");

var xpos = parseInt(elem.style.left);

var ypos = parseInt(elem.style.top);

if (xpos == 200 && ypos == 100) {

movement = setTimeout("moveMessage()",10);

}

If all of those things were variables, the function would be a lot more flexible. By abstracting the moveMessage function, you can create something more portable and reusable.

在文檔中 Second Edition (頁 188-195)