Figure 10-2.The div’s style has been dynamically altered.But let’s try moving the element gradually—by increasing the topand leftvalues little by little until we arrive at the desired 50
Trang 1The Basics of Effects
Consider an element that’s 50 pixels square and absolutely positioned at the top-left
cor-ner of the page, as in Figure 10-1
/* CSS: */
#box {
position: absolute;
width: 50px;
height: 50px;
top: 0;
left: 0;
background-color: #999;
border: 2px solid #000;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
text-transform: uppercase;
text-align: center;
line-height: 50px;
font-size: 10px;
}
<! HTML: >
<div id="box">Box</div>
Figure 10-1.An absolutely positioned div
If we want to move it down and to the right, we can do so instantaneously:
var box = $('box');
box.setStyle({ left: '50px', top: '50px' });
Here, we’re changing the element’s leftand topproperties from 0pxto 50px When we
set the new style, it happens instantaneously—the box jumps down to its new place, as in
Figure 10-2
Trang 2Figure 10-2.The div’s style has been dynamically altered.
But let’s try moving the element gradually—by increasing the topand leftvalues little by little until we arrive at the desired 50px Our first attempt might look something like this:
var box = $('box');
for (var i = 1; i <= 50; i++)
box.setStyle({ left: i + 'px', top: i + 'px' });
Unfortunately, when we run this code, we find that it behaves exactly the same way
as the first example—the box seems to jump to its new coordinates without any steps in the middle Why?
Take a moment to think like a computer It doesn’t take that much time to change
a CSS property—let’s say around 1ms Multiply that by 50 and you’ve got 50ms, still less than one-tenth of a second The animation is happening, but far too fast for a human to notice It might even be happening faster than the rendering engine can update
But speed problems are easy to work around We need to slow things down by paus-ing after each frame of the animation so that our human eyes (and the browser’s
rendering engine) can catch up Remember that JavaScript has no sleepstatement; we can’t tell the interpreter to halt, but we can tell it to do other things for a while, and that’s good enough:
function incrementBox(value) {
$('box').setStyle({ left: value + 'px', top: value + 'px' });
if (value < 50) incrementBox.delay(0.01, ++value);
}
incrementBox(1);
Trang 3Remember Function#delay? It’s an excellent way to schedule a function to run later—
one hundredth of a second later, in this case Here, incrementBoxschedules itself to run
later, over and over, until we reach the desired value We need to call it only once to set
the effect in motion Figure 10-3 shows the “before” and “after” states of the box
Figure 10-3.The element animates into its new position.
Trang 4So let’s look at the ingredients of this effect:
• The element (<div id="box">) is the target of the effect
• The starting and ending points are pixel coordinates (0, 0to 50, 50)
• The incrementing is done by Element#setStyle
This method works, but not as well as it could It’s far too dependent on the speed of the computer it runs on, and it’s not guaranteed to move at a constant pace Our call to
JavaScript engine is busy with something else, we could be waiting for quite a bit longer We’re guaranteed to get 50 frames of animation, but the element might not move at a constant speed
script.aculo.us Effects
Fortunately, script.aculo.us manages all these annoying details for you It creates a base class for running effects, and then defines scads and scads of specific effects that inherit from that base class The effects themselves vary wildly, but they all have several things in common:
• They all act on an element
• They all involve transforming that element’s style from a starting point to an end-ing point over a specified amount of time No matter how slow the computer or how overwhelmed the JS engine, script.aculo.us effects will always execute in the amount of time specified
• They all accept callbacks that let us run our own functions at certain milestones in
the animation These callbacks are very similar to the Ajax callbacks covered in Chapter 4
The previous exercise was meant to give you an idea of how effects work under the hood script.aculo.us defines a base class that solves all the problems we encountered—
a boilerplate for any sort of browser-based effect It then defines subclasses that do spe-cific things: one animates opacity, another animates position, and so on These are called
core effects Finally, it defines some functions that build on these core effects by running two or more in parallel These are called combination effects.
Trang 5Using Effect.Morph
Simple cases first, though—let’s look at Effect.Morph, the most generic (and most
versa-tile) of all effects It works like a time-lapse version of Element#setStyle: it takes an
element and some CSS rules to apply to the element, and slowly “morphs” the element
according to the new rules (see Figure 10-4)
new Effect.Morph('box', {
style: "left: 50px; top: 50px;",
duration: 1.0
});
Figure 10-4.The Effect.Morph call animates the box into the desired position.
Trang 6In other words, from the starting and ending values of each element’s properties,
them over the specified period of time
param-eter, style, can be either a string or an object in the form expected by Element#setStyle
An optional durationargument indicates how long the effect should last; if absent, it defaults to 0.5 seconds
script.aculo.us also adds Element#morphfor maximum convenience This code exam-ple is equivalent to the preceding one:
$('box').morph("left: 50px; top: 50px;", { duration: 1.0 });
tweening—figuring what goes in between a starting point and an ending point Anything
with a quantitative value—pixels, ems, hex color values, and so on—can be morphed
$('box').morph("width: 500px");
$('box').morph("font-size: 1.6em");
$('box').morph("background-color: #cc5500");
How Does It Do That?
As we’ve established, all effects need to know several things: the element to change, the aspect of that element to change, and starting and ending values.Effect.Morphlets us specify, in very precise form, all of those things except for one—we don’t need to specify
a starting value because it’s assumed we want to start at whatever state the element is already in This shortcut limits the overall expressive power of Effect.Morph, but broadens its applicability
To illustrate this, let’s place our element at a different starting point:
#box {
position: absolute;
width: 50px;
height: 50px;
top: 200px;
left: 100px;
background-color: #999;
border: 2px solid #000;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
text-transform: uppercase;
text-align: center;
line-height: 50px;
font-size: 10px;
}