## Chapter 8. Animation and Special Effects

Animation can add a splash of character to an otherwise bland application. This chapter systematically works through the animation utilities that are built right into Base as well as the dojo.fx (pronounced "effects") module that Core provides. This chapter includes a lot of source code and the bulk of the content builds upon only a few other concepts covered in earlier chapters. As such, this chapter may prove useful as a near-standalone reference.

## Animation

The toolkit provides animation facilities in Base and supplements them with additional functionality offered through dojo.fx. The stock functionality offered by Base includes _Animation, a class that acts as a delegate in that it fires callbacks according to its configuration; these callback functions are what manipulate properties of a node so that it animates. Once instantiated, all that has to be done to execute an _Animation is to invoke its play method.

The leading underscore on the _Animation class currently designates at least two things:

• The API isn't definitively final yet, although it is really stable and probably will not change much (if any) between version 1.1 of the toolkit and when it does become final.

• You generally won't be creating an _Animation directly. Instead, you'll rely on auxiliary functions from Base and dojo.fx to create, wrap, and manipulate them on your behalf. You will, however, usually need to run their play methods to start them.

Before delving into some of the advanced aspects of animations, let's kick things off with one of the simplest examples possible: a simple square on the screen that fades out when you click on it, shown in Figure 8-1. This example uses one of the two fade functions included with Base. The fadeOut function and its sibling fadeIn function accept three keyword arguments, listed in Table 8-1. Figure 8-1 shows an illustration of the default easing function.

Table 8-1. Parameters for Base's fade functions
 Parameter Type Comment node DOM Node The node that will be faded. duration Integer How many milliseconds the fade should last. Default value is 350. easing Function A function that adjusts the acceleration and/or deceleration of the progress across a curve. Default value is: (0.5 + ((Math.sin((n + 1.5) * Math.PI))/2). Note that the easing function is only defined from a domain of 0 to 1 for fadeIn and fadeOut.

The node and duration parameters should be familiar enough, but the notion of an easing function might seem a bit foreign. In short, an easing function is simply a function that controls the rate of change for something—in this case an _Animation. An easing function as simple as function(x) { return x; } is linear: for each input value, the same output value is returned. Thus, if you consider the domain for possible x values to be decimal numbers between 0 and 1, you notice that the function always returns the same value. When you plot the function, it is simply a straight line of constant slope, as shown in Figure 8-2. The constant slope guarantees that the animation is smooth and occurs at a constant rate of change.

Example 8-1 demonstrates how to fade out a portion of the screen using the default parameters.

Example 8-1. Fading out a node
<html>
<title>Fun with Animation!</title>
<style type="text/css">
@import "http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css";
.box {
width : 200px;
height : 200px;
margin : 5px;
background : blue;
text-align : center;
}
</style>
<script
type="text/javascript"
src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js">
</script>
<script type="text/javascript">
var box = dojo.byId("box");
dojo.connect(box, "onclick", function(evt) {
var anim = dojo.fadeOut({node:box});
anim.play(  );
});
});
</script>
<body>
<div id="box" class="box">Fade Me Out</div>
</body>
</html>

To contrast the default behavior with a different easing function, shown in Figure 8-3, consider the following revision to the previous addOnLoad block. Note how the default easing function is a relative smooth increase from 0 to 1, while the custom easing function delays almost all of the easing until the very end. This example also uses the dot-operator to run the play method on the _Animation instead of storing an explicit reference, which is cleaner and more customary.

dojo.addOnLoad(function(  ) {
var box = dojo.byId("box");
dojo.connect(box, "onclick", function(evt) {
var easingFunc = function(x) {
return Math.pow(x,10);
}
node:box,
easing : easingFunc,
duration : 3000
}).play(  );
});});

The dojox.fx.easing module contains a number of excellent easing functions. Check them out if you find yourself in need of some creative possibilities.

Given that simple fades are incredibly common, having them at a distance of one function call away through Base is wonderful. However, it won't be long before you'll start to wonder about what kinds of other slick animations you can create with _Animation.

### Animating Arbitrary CSS Properties

Let's build on our current foundation by introducing the rest of the animateProperty function, which accepts one or more of the configuration parameters shown in Table 8-2 in the same manner that fadeIn and fadeOut work.

Table 8-2. The animateProperty function
 Parameter Type Comment node DOM Node | String The node or a node id that will be animated. duration Integer How many milliseconds the animation should last. Default value is 350. easing Function A function that adjusts the acceleration and/or deceleration of the progress across a curve. Default value is (0.5 + ((Math.sin((n + 1.5) * Math.PI))/2). repeat Integer How many times to repeat the _Animation. By default, this value is 0. rate Integer The duration in milliseconds to wait before advancing to the next "frame". This parameter controls how frequently the _Animation is refreshed on a discrete basis. For example, a rate value of 1000 would imply a relative rate of 1 frame per second. Assuming a duration of 10000, this would result in 10 discrete updates being performed in the _Animation. By default, this value is 10. delay Integer How long to wait before performing the animation after its play method is executed. properties Object Specifies the CSS properties to animate, providing start values, end values, and units. The start and end values may be literal values or functions that can be used to derive computed values: start (String) The starting value for the property end (String) The starting value for the property unit (String) The type of units: px (the default), em, etc.

Replace the existing addOnLoad function with this updated one to test out animateProperty. In this particular case, the width of the node is being animated from 200px to 400px:

dojo.addOnLoad(function(  ) {
var box = dojo.byId("box");
dojo.connect(box, "onclick", function(evt) {
dojo.animateProperty({
node : box,
duration : 3000,
properties : {
width : {start : '200', end : '400'}
}
}).play(  );
});
});

It is worthwhile to spend a few moments experimenting with the animateProperty function to get a good feel for the kinds of creative things that you can make happen; it is the foundation of most dojo.fx animations and chances are that you'll use it often to take care of routine matters. It accepts virtually any CSS properties all through the same unified interface. Example 8-2 illustrates that animations adjust other inline screen content accordingly. Clicking on the blue box causes it to expand in the x and y dimensions, causing the red and green boxes to adjust their position as needed.

Example 8-2. Expanding the dimensions of a node
<html>
<title>More Fun With Animation!</title>
<style type="text/css">
@import "http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css";
.box {
width : 200px;
height : 200px;
margin : 5px;
text-align : center;
}
.blueBox {
background : blue;
float : left;
}
.redBox {
background : red;
float : left;
}
.greenBox {
background : green;
clear : left;
}
</style>
<script
type="text/javascript"
src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js">
</script>
<script type="text/javascript">

var box = dojo.byId("box1");
dojo.connect(box, "onclick", function(evt) {
dojo.animateProperty({
node : box,
duration : 3000,
properties : {
height : {start : '200', end : '400'},
width : {start : '200', end : '400'}
}
}).play(  );
});
});

</script>
<body>
<div id="box2" class="box redBox"></div>
<div id="box2" class="box greenBox"></div>
</body>
</html>

If some of the animateProperty parameters still seem foggy to you, the previous code example is a great place to spend some time getting more familiar with the effect of various parameters. For example, make the following change to the animateProperty function to produce 10 discrete frames of progress instead of a more continuous-looking animation (recall that the duration divided by the rate provides a number of frames):

dojo.addOnLoad(function(  ) {
var box = dojo.byId("box1");
dojo.connect(box, "onclick", function(evt) {
dojo.animateProperty({
node : box,
duration : 10000,
rate : 1000,
properties : {
height : {start : '200', end : '400'},
width : {start : '200', end : '400'}
}
}).play(  );
});
});

Given that the default easing function being used is fairly smooth, take a moment to experiment with the effect that various more abrupt functions have on the animation. For example, the following adjustment uses a parabolic easing function, shown in Figure 8-4, in which the values increase in value at much larger intervals as you approach higher domain values, and the discrete effect over the 10 distinct frames should be apparent:

dojo.addOnLoad(function(  ) {
var box = dojo.byId("box1");
dojo.connect(box, "onclick", function(evt) {
dojo.animateProperty({
node : box,
duration : 10000,
rate : 1000,
easing : function(x) { return x*x; },
properties : {
height : {start : '200', end : '400'},
width : {start : '200', end : '400'}
}
}).play(  );
});
});

Although the examples so far have implied that easing functions are monotonic,[17] this need not be the case. For example, try adjusting the working example with an easing function that is not monotonic, shown in Figure 8-5, to see the effect:

dojo.addOnLoad(function(  ) {
var box = dojo.byId("box1");
dojo.connect(box, "onclick", function(evt) {
dojo.animateProperty({
node : box,
duration : 10000,
easing : function(x) {return Math.pow(Math.sin(4*x),2);},
properties : {
height : {start : '200', end : '400'},
width : {start : '200', end : '400'}
}
}).play(  );
});
});

### Programatically Controlling Animations

Although you generally do not create raw _Animation objects, you still have the ability to control them for most of the common use cases. For example, while an animation is ongoing, you have the ability to pause, restart, and stop it prematurely, inquire about its status, or cue it to a specific point. _Animation provides methods for all of these common tasks, listed in Table 8-3.

Table 8-3. _Animation control functions
 Method Parameters Comment stop /* Boolean */ goToEnd Stops an animation. If goToEnd is true, then the _Animation advances to the end so that when play is invoked again, it will start from the beginning. goToEnd is false by default. pause N/A Pauses an animation. play /* Integer */ delay /* Boolean */ goToStart Plays an animation, optionally allowing for a delay (in milliseconds) before the play operation. For paused animations, specifying true for goToStart restarts the animation versus continuing where it left off. status N/A Returns the status of an animation. Possible values for status are "paused", "playing", and "stopped". gotoPercent /* Decimal */ percent /* Boolean */ andPlay Stops the animation and then advances its percentage complete between 0.0 and 1.0. Setting andPlay is true (false by default) restarts the animation.

Notice that gotoPercent is not mixedCase, like goToPercent. This is one of the few functions in the toolkit that does not use mixedCase, which makes it very easy to mistype.

You may also define any of the methods shown in Table 8-4 as an input to animateProperty. The following table summarizes the functionality provided, and a block of code follows that illustrates a change to animateProperty that you can try to set out the method calls.

Table 8-4. Input methods for animateProperty
 Method Parameters Comment beforeBegin N/A Fired before the animation begins, providing access to the _Animation and the node for modification immediately before anything happens. onBegin /* Object */ value Fires after the animation has begun cycling, so in effect, this method is somewhat asynchronous. The value parameter is an object containing the current values for the style properties. onAnimate /* Object */ value Called for each discrete frame of the animation. The parameter is an object containing the current values for the style properties. onEnd N/A Called automatically when the animation ends. onPlay /* Object */ value Called each time play is called (including the first time). The value parameter is an object containing the current values for the style properties. onPause /* Object */ value Called each time pause is called. The value parameter is an object containing the current values for the style properties. onStop /* Object */ value Called each time stop is called. The value parameter is an object containing the current values for the style properties.

Here's a small code snippet you can use to tinker around with these methods firing:

dojo.animateProperty({
node : "box1",
duration:10000,
rate : 1000,
beforeBegin:function(  ){ console.log("beforeBegin: ", arguments); },
onBegin:function(  ){ console.log("onBegin: ", arguments); },
onAnimate:function(  ){ console.log("onAnimate: ", arguments); },
onEnd:function(  ){ console.log("onEnd: ", arguments); },
onPlay:function(  ){ console.log("onPlay: ", arguments); },
properties : {height : {start : "200", end : "400"} }
}).play(  );

The following adjustments to the working example illustrate some basic methods for controlling an _Animation:

<!-- snip -->
<script type="text/javascript">
var box = dojo.byId("box1");
var anim;
dojo.connect(box, "onclick", function(evt) {
anim = dojo.animateProperty({
node : box,
duration : 10000,
rate : 1000,
easing : function(x) { console.log(x); return x*x; },
properties : {
height : {start : '200', end : '400'},
width : {start : '200', end : '400'}
}
});
anim.play(  );
dojo.connect(dojo.byId("stop"), "onclick", function(evt) {
anim.stop(true);
console.log("status is ", anim.status(  ));
});
dojo.connect(dojo.byId("pause"), "onclick", function(evt) {
anim.pause(  );
console.log("status is ", anim.status(  ));
});
dojo.connect(dojo.byId("play"), "onclick", function(evt) {
anim.play(  );
console.log("status is ", anim.status(  ));
});
dojo.connect(dojo.byId("goTo50"), "onclick", function(evt) {
anim.gotoPercent(0.5, true);
});
});
});

</script>
<body>
<div>
<button id="stop"  style="margin : 5px">stop</button>
<button id="pause" style="margin : 5px">pause</button>
<button id="play"  style="margin : 5px">play</button>
<button id="goTo50"  style="margin : 5px">50 percent</button>
</div>
<div id="box2" class="box redBox"></div>
<div id="box2" class="box greenBox"></div>
</body>
</html>

## Core fx

The content of this chapter up to this point has concentrated entirely on the animation facilities that are provided by Base. The existing functionality in Base consisting of fadeIn, fadeOut, and animateProperty covers a tremendous amount of use cases; however, there are a few additional functions provided in Core's fx module that you can get for the cost of one additional dojo.require statement. These facilities for effects include functions for sliding nodes and wiping nodes in and out, as well as chaining, combining, and toggling animations.

### Sliding

Sliding nodes is just as easy as fading them. You pass a hash containing configuration parameters to the dojo.fx.slideTo function just like you would with animateProperty. Table 8-5 summarizes.

Table 8-5. Parameters for Core's slide functions
 Parameter Type Comment node DOM Node The node that will be sliding. duration Integer How many milliseconds the fade should last. Default value is 350. easing Function A function that adjusts the acceleration and/or deceleration of the progress across a curve. Default value is (0.5 + ((Math.sin((n + 1.5) * Math.PI))/2). Note that the easing function is only defined from a domain of 0 to 1 for the fadeIn and fadeOut. left Integer Where the node's left corner should be at the end of the slide. top Integer Where the node's top corner should be at the end of the slide.

Example 8-3 illustrates the sliding functions. The only portions of the page that are any different from the previous fade examples are emphasized.

Example 8-3. Sliding a node
<html>
<title>Animation Station</title>
<style type="text/css">
@import "http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css";
.box {
width : 200px;
height : 200px;
margin : 5px;
background : blue;
text-align : center;
}
</style>
<script
type="text/javascript"
src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js">
</script>
<script type="text/javascript">

dojo.require("dojo.fx");

var box = dojo.byId("box");
dojo.connect(box, "onclick", function(evt) {
dojo.fx.slideTo({

node:box,

top : "200",

left : "200"

}).play(  );
});
});
</script>
<body>
<div id="box" class="box">Slide Me</div>
</body>
</html>

### Wiping

Slides and fades are a lot of fun, but wipes are frequently used and have wonderful utility as well. The basic approach to using them should be no surprise by now. Most of the same arguments apply. Table 8-6 provides a synopsis.

Table 8-6. Parameters for Core's wipe functions
 Parameter Type Comment node DOM Node The node that will be wiped. duration Integer How many milliseconds the fade should last. Default value is 350. easing Function A function that adjusts the acceleration and/or deceleration of the progress across a curve. Default value is (0.5 + ((Math.sin((n + 1.5) * Math.PI))/2). Note that the easing function is only defined from a domain of 0 to 1 for the fadeIn and fadeOut.

Be advised that in some layouts, border, margin, and padding values associated with nodes have been known to affect the layout once wipe animations have completed.

Following suit with the other examples in this chapter, Example 8-4 can get you started.

Example 8-4. Wiping a node
<html>
<title>Animation Station</title>
<style type="text/css">
@import "http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css";
.box {
width : 200px;
height : 200px;
text-align : center;
float : left;
position : absolute;
margin : 5px;
}
</style>
<script
type="text/javascript"
src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js">
</script>
<script type="text/javascript">
dojo.require("dojo.fx");

var box = dojo.byId("box");
dojo.connect(box, "onclick", function(evt) {
dojo.fx.wipeOut({
node:box
}).play(  );
});
});
</script>
<body>
<div class="box">Now you don't</div>
<div id="box" style="background : blue" class="box">Now you see me...</div>
</body>
</html>

You may also find it especially interesting to experiment with custom easing functions for wipes. Try our custom, nonmonotonic easing function from earlier and note the interesting bouncy effect with the following addOnLoad change:

dojo.addOnLoad(function(  ) {
var box = dojo.byId("box");
dojo.connect(box, "onclick", function(evt) {
dojo.fx.wipeOut({
node:box,
easing : function(x) { return Math.pow(Math.sin(4*x),2);   },
duration : 5000
}).play(  );
});
});

Because the easing function increases, decreases, then decreases again, the internal _Animation that wipeOut uses scales the height of the node accordingly.

### Chaining and Combining

There's something that's quite remarkable about watching an object slide, fade, and wipe around the screen, but that's not all you can do: you can use another function in Core fx, dojo.fx.chain, to chain together animations. This function is incredibly simple in that its only argument is an Array of _Animation objects and it returns another _Animation for you to play. Let's use it to make the box do something a little more fancy. Table 8-7 lists the functions for combining and chaining.

As of Dojo version 1.1, the animation functions chain and combine in this section have several known issues relating to how events such as beforeBegin and onEnd are processed when multiple animations are rolled up. The basic gist is that if you are trying to rely on these events for specific hooks in your application's logic, you might be better off using functions like dojo.connect and dojo.subscribe to rig up your own chains and combinations. Of course, for less advanced tasks, chain and combine work fine.

Table 8-7. Animation combination and chaining
 Function Comment dojo.fx.chain(/* Array */ animations) Chains together the animations enclosed in the array that is passed in as a parameter and returns a consolidated animation that you can play as usual. The resulting animation is the sequential result of playing each animation back to back. dojo.fx.combine(/* Array */ animations) Combines the animations enclosed in the array that is passed in as a parameter and returns a consolidated animation that you can play as usual. The resulting animation provides the effect of playing each of the original animations in parallel.

Example 8-5 demonstrates a box that makes a zigzag pattern across the screen. Note that you define custom easing function and other parameters just as normal.

Example 8-5. Chaining animations together
dojo.addOnLoad(function(  ) {
var box = dojo.byId("box");
dojo.connect(box, "onclick", function(evt) {
var easing = function(x) { return x; };
var a1 = dojo.fx.slideTo({
node:box,
easing : easing,
duration : 1000,
top : "150",
left : "300"
});
var a2 = dojo.fx.slideTo({
node:box,
easing : easing,
duration : 400,
top : "20",
left : "350"
});
var a3 = dojo.fx.slideTo({
node:box,
easing : easing,
duration : 800,
top : "350",
left : "400"
});
dojo.fx.chain([a1,a2,a3]).play(  );
});
});

But say you want to fade and slide at the same time. No problem. Following the same type API call as dojo.fx.chain, the dojo.fx.combine will do it in a jiffy. Any animations you pass into it through the Array parameter are run in parallel. First, let's look at a simple combination of our slide and fade examples. Example 8-6 shows the relevant change to addOnLoad.

Example 8-6. Combining animations
dojo.addOnLoad(function(  ) {
var box = dojo.byId("box");
dojo.connect(box, "onclick", function(evt) {
var a1 = dojo.fx.slideTo({
node:box,
top : "150",
left : "300"
});
var a2 = dojo.fadeOut({
node:box
});
dojo.fx.combine([a1,a2]).play(  );
});
});

It's easy to forget that slideTo is in dojo.fx while fadeIn and fadeOut are in Base, so take a moment to acknowledge that a call like dojo.fx.fadeIn would give you an error. If you do not issue a dojo.require("dojo.fx") before attempting to use anything in dojo.fx, you'll get an error.

Given that chain returns a single _Animation, let's try something more advanced (but still really simple) because it builds on the same fundamentals: in Example 8-7, we'll chain together several fade animations and combine them with several slide animations that we'll also chain together.

Example 8-7. Chaining and combining animations
dojo.addOnLoad(function(  ) {
var box = dojo.byId("box");
dojo.connect(box, "onclick", function(evt) {

//chain together some slides
var a1 = dojo.fx.slideTo({
node:box,
top : "150",
left : "300"
});
var a2 = dojo.fx.slideTo({
node:box,
top : "20",
left : "350"
});
var a3 = dojo.fx.slideTo({
node:box,
top : "350",
left : "400"
});
var slides = dojo.fx.chain([a1,a2,a3]);

//chain together some fades
var a1 = dojo.fadeIn({
node:box
});
var a2 = dojo.fadeOut({
node:box
});
var a3 = dojo.fadeIn({
node:box
});
var fades = dojo.fx.chain([a1,a2, a3]);

//now combine the two chains together

});
});

### Toggling

The dojo.fx.Toggler class is essentially a wrapper for configuring the animations for toggling (showing and hiding) a node. The class constructor accepts an associative array of parameters that include the show and hide functions as well as the durations for the show and hide functions. Toggler is nice in that there is very little thinking involved about what has to happen. You simply tell it what functions to use, provide the durations, and then manually call its show and hide function accordingly. Both the show and hide function optionally accept a parameter that delays the operation by a said amount of time (Table 8-8).

Table 8-8. Parameters for Core's Toggler function
 Parameter Type Comment node DOM Node The node to toggle. showFunc Function A function that returns an _Animation for showing the node. Default value is dojo.fadeIn. hideFunc Function A function that returns an _Animation for hiding the node. Default value is dojo.fadeOut. showDuration Integer The duration in milliseconds to run showFunc. Default value is 200 (milliseconds). hideDuration Integer The duration in milliseconds to run hideFunc. Default value is 200 (milliseconds).

Table 8-9 provides the method summary for the class.

Table 8-9. Toggler functions
 Method Comment show(/*Integer*/delay) Shows a node over a duration defined by showDuration using showFunc. The optional delay parameter causes the animation to wait by the specified amount before starting. hide(/*Integer*/delay) Hides a node over a duration defined by hideDuration using hideFunc. The optional delay parameter causes the animation to wait by the specified amount before starting.

Example 8-8 provides the compulsory source code and another modification to addOnLoad for our working example from Example 8-4.

Example 8-8. Toggling a node
dojo.addOnLoad(function(  ) {
var box = dojo.byId("box");
var t = new dojo.fx.Toggler({
node : box,
showDuration : 1000,
hideDuration : 1000
});
var visible = true;
dojo.connect(box, "onclick", function(evt) {
if (visible)
t.hide(  );
else
t.show(  );

visible = !visible;
});
});

If you try out the example, you should notice that clicking on the "Now you see me . . . " box causes it to fade out, while clicking on the "Now you don't" box causes the first box to fade back in.

## Animation + Drag-and-Drop = Fun!

Drag-and-drop combined with animations are an incredibly powerful combination. Take a moment to review and experiment with the following block of code, which combines very basic concepts from drag-and-drop in the previous chapter with what you've been learning about in this one; it's illustrated in Figure 8-6.

<html>
<title>Animation + Drag and Drop = Fun!</title>

<script
type="text/javascript"
src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js">
</script>
<script type="text/javascript">
dojo.require("dojo.fx");
dojo.require("dojo.dnd.move");
var move = new dojo.dnd.Moveable(dojo.byId("ball"));
var coords;
dojo.subscribe("/dnd/move/start",function(e){
// when drag starts, save the coords
coords = dojo.coords(e.node);
});

//now use the coords to control where the image slides back
dojo.subscribe("/dnd/move/stop",function(e){
dojo.fx.slideTo({
node: e.node,
top: coords.t,
left: coords.l,
duration:1200,
easing : function(x) { return Math.pow(x,5);}
}).play(  );
});
});
</script>
<body>
<!-- Insert any image into the page here in place of ball.png -->
<img style="position : absolute; left : 300px; top : 300px;"
id="ball"
src="ball.png"/>
</body>
</html>

To summarize, the code example detects the start of a global drag event and remembers the coordinates of where that drag began. Then, it waits until the drag event ends, and at that point, moves the image back to its original sport according to the specific easing function. The easing function dictates that the move back will be slow at first, but will rapidly accelerate toward the end in a trendy sort of way.

## Colors

Animations and effects in a page may often depend on computing specific color values. Base provides an elementary Color class for encapsulating much of the mundane logic in computing colors, converting them to and from hexadecimal values, and so on. Several auxiliary functions for common operations on colors are also included.

### Creating and Blending Colors

The Color class has a flexible constructor that can accept a named string value for a color, a hex string representing a color, or an array of RGB[18] values. Example 8-9 illustrates the creation of two Color objects and a function Base provides for blending colors.

Example 8-9. Blending Color objects
<html>
<title></title>
<script
type="text/javascript"
src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js">
</script>
<script type="text/javascript">
var blue = new dojo.Color("#0000ff"); //could also have used "blue"

var red = new dojo.Color([255, 0, 0]);

var purple = dojo.blendColors(blue, red, 0.5);
dojo.style("foo", "background", purple.toCss(  ));
});
</script>
<body>
<div id="foo" style="width:200px; height:200px; padding:5px;"></div>
</body>
</html>

The blendColors function accepted the red and blue Color objects and blended them according to a 50/50 mixture to produce the RGB value (128, 0, 128), a neutral shade of purple. The alternative to blending colors is to crunch the numbers yourself—not rocket science, but not very much fun either!

Table 8-10 summarizes the Color class provided by Base.

Table 8-10. Color functionality supported by Base
 Method Comment Color(/* Array | String */color) The constructor function, which accepts an array of RGB or RGBA values, or a String, which may be a named color like "blue" or a hex string like "#000ff". If no arguments are passed, the Color object is constructed with the RGBA tuple (255,255,255,1). setColor(/* Array | String | Object */ color) Works on an existing Color object to configure its value in a manner analogous to its constructor function; the preferred way of reusing an existing Color object. toRgb( ) Returns a String value expressing a Color as an RGB value such as (128, 0, 128). toRgba( ) Returns a String value expressing a Color as an RGBA value such as (128, 0, 128, 0.5). toHex( ) Returns a String value expressing a Color as a hex value such as "#80080". toCss(/* Boolean */ includeAlpha) Returns a CSS-compliant String value expressing a Color as an RGB value such as (128, 0, 128). By default, includeAlpha is false. This method is the preferred means of transforming a Color object for use in styling a node. toString Returns a standardized String value for a Color as an RGBA value.

Most browsers currently implement a deviation of the CSS2 specification, which does not support RGBA tuples for expressing colors, so Color 's toCss( ) function (with no parameter passed in) is probably your choice method of deriving a value acceptable for passing into a method like dojo.style. If you need to express transparency for nodes that have color, use the style value for opacity to do so.

Transparency and opacity are the inverses of one another. If the opacity of something is 1.0, it is fully opaque, and its transparency is therefore 0.0. If its opacity were 0.1, it would be 90% transparent, and you would barely be able to see it.

### Named Color Values Available Via Base

One other utility in Base is the configuration of preloaded named colors that is stored in dojo.Color.named, which maps named colors to RGB values. For example, to quickly access the RGB values for maroon, simply use the reference to dojo.Color.named.maroon to get back the RGB array [128,0,0]. Table 8-11 summarizes the named colors that are built into Base. Although you will probably want to use and manipulate Color objects directly, dojo.Color.named may still prove useful during development.

dojo.Color.named is not available from an actual Color object. It is a static collection of color values and no object creation is required to use it. Trying to access a color object instance's .named value will cause an error.

Table 8-11. Named color values available through Base
 Name Red Green Blue black 0 0 0 silver 192 192 192 gray 128 128 128 white 255 255 255 maroon 128 0 0 red 255 0 0 purple 128 0 128 fuchsia 255 0 255 green 0 128 0 lime 0 255 0 olive 128 128 0 yellow 255 255 0 navy 0 0 128 blue 0 0 255 teal 0 128 128 aqua 0 255 255

### Additional Color Values Available Via Core

Although not included directly in Base, you can expand dojo.Color.named with more than 100 additional colors including all of the CSS3 named colors complete with SVG 1.0 variant spellings by performing a dojo.require("dojo.colors") statement (see Table 8-12). Note that you can also use the animateProperty function you learned about earlier to to animate the backgroundColor property. For example, you could provide start and end values of "black" and "white", "white" and "#43fab4", etc.

In addition to expanding dojo.Color.named, dojo.colors provides the additional enhancement of augmenting the Color constructor to accept HSL and HSLA color module formats. The HSL color space attempts to describe perceptual color relationships more accurately then RGB by representing colors in terms of hue, saturation, and lightness. You can read more about the CSS Color module at http://www.w3.org/TR/css3-iccprof.

Table 8-12. Additional named color values available through Core
 Name Red Green Blue aliceblue 240 248 255 antiquewhite 250 235 215 aquamarine 127 255 212 azure 240 255 255 beige 245 245 220 bisque 255 228 196 blanchedalmond 255 235 205 blueviolet 138 43 226 brown 165 42 42 burlywood 222 184 135 cadetblue 95 158 160 chartreuse 127 255 0 chocolate 210 105 30 coral 255 127 80 cornflowerblue 100 149 237 cornsilk 255 248 220 crimson 220 20 60 cyan 0 255 255 darkblue 0 0 139 darkcyan 0 139 139 darkgoldenrod 184 134 11 darkgray 169 169 169 darkgreen 0 100 0 darkgrey 169 169 169 darkkhaki 189 183 107 darkmagenta 139 0 139 darkolivegreen 85 107 47 darkorange 255 140 0 darkorchid 153 50 204 darkred 139 0 0 darksalmon 233 150 122 darkseagreen 143 188 143 darkslateblue 72 61 139 darkslategray 47 79 79 darkslategrey 47 79 79 darkturquoise 0 206 209 darkviolet 148 0 211 deeppink 255 20 147 deepskyblue 0 191 255 dimgray 105 105 105 dimgrey 105 105 105 dodgerblue 30 144 255 firebrick 178 34 34 floralwhite 255 250 240 forestgreen 34 139 34 gainsboro 220 220 220 ghostwhite 248 248 255 gold 255 215 0 goldenrod 218 165 32 greenyellow 173 255 47 grey 128 128 128 honeydew 240 255 240 hotpink 255 105 180 indianred 205 92 92 indigo 75 0 130 ivory 255 255 240 khaki 240 230 140 lavender 230 230 250 lavenderblush 255 240 245 lawngreen 124 252 0 lemonchiffon 255 250 205 lightblue 173 216 230 lightcoral 240 128 128 lightcyan 224 255 255 lightgoldenrodyellow 250 250 210 lightgray 211 211 211 lightgreen 144 238 144 lightgrey 211 211 211 lightpink 255 182 193 lightsalmon 255 160 122 lightseagreen 32 178 170 lightskyblue 135 206 250 lightslategray 119 136 153 lightslategrey 119 136 153 lightsteelblue 176 196 222 lightyellow 255 255 224 limegreen 50 205 50 linen 250 240 230 magenta 255 0 255 mediumaquamarine 102 205 170 mediumblue 0 0 205 mediumorchid 186 85 211 mediumpurple 147 112 219 mediumseagreen 60 179 113 mediumslateblue 123 104 238 mediumspringgreen 0 250 154 mediumturquoise 72 209 204 mediumvioletred 199 21 133 midnightblue 25 25 112 mintcream 245 255 250 mistyrose 255 228 225 moccasin 255 228 181 navajowhite 255 222 173 oldlace 253 245 230 olivedrab 107 142 35 orange 255 165 0 orangered 255 69 0 orchid 218 112 214 palegoldenrod 238 232 170 palegreen 152 251 152 paleturquoise 175 238 238 palevioletred 219 112 147 papayawhip 255 239 213 peachpuff 255 218 185 peru 205 133 63 pink 255 192 203 plum 221 160 221 powderblue 176 224 230 rosybrown 188 143 143 royalblue 65 105 225 saddlebrown 139 69 19 salmon 250 128 114 sandybrown 244 164 96 seagreen 46 139 87 seashell 255 245 238 sienna 160 82 45 skyblue 135 206 235 slateblue 106 90 205 slategray 112 128 144 slategrey 112 128 144 snow 255 250 250 springgreen 0 255 127 steelblue 70 130 180 tan 210 180 140 thistle 216 191 216 tomato 255 99 71 transparent 0 0 0 turquoise 64 224 208 violet 238 130 238 wheat 245 222 179 whitesmoke 245 245 245 yellowgreen 154 205 50

## Summary

This chapter has systematically walked you through Base and Core's tools for animation. A splash of animation, when applied with discretion, can really add that extra bit of umph that distinguishes your application from the rest of the crowd. After reading this chapter, you should:

• Be able to use Base's utilities for fading nodes in and out

• Be able to use Base's animateProperty function to animate arbitrary CSS properties

• Understand the effect of easing functions, duration, and rate on an _Animation

• Be aware of Core's facilities that supplement the animation support provided by Base

• Be able to use Core's animation support for additional effects, including wipes and slides

• Be able to chain together animations to run sequentially with dojo.fx.chain as well as run multiple animations in parallel with dojo.fx.combine

• Be able to use dojo.fx.Toggler to hide and show a node via its simple, uniform interface

• Understand how to combine animations with drag-and-drop to create highly interactive page content

• Be able to create and effectively use Color objects to eliminate manual computation of color values in your code

There are amazing graphics and animation tools backed by SVG, VML, and Silverlight backends, provided through the dojox.gfx module.

We're going to cover data abstraction in the next chapter.

[17] Basically, a function is monotonic if it moves steadily in one direction or the other, i.e., if it always increases or if it always decreases.

[18] RGB is shorthand for "red green blue," one of the standard ways of representing colors in CSS. RGBA is shorthand for "red green blue alpha" and expresses a fourth color component, which represents the transparency of a color.