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.
Warning
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
_Animationdirectly. Instead, you'll rely on auxiliary functions from Base anddojo.fxto create, wrap, and manipulate them on your behalf. You will, however, usually need to run theirplaymethods to start them.
Simple Fades
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, “A visualization of the default easing function; an easing
function is only defined from a scale of 0 to 1 for fadeIn and
fadeOut”. 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, “Parameters for Base's fade functions”. Figure 8.1, “A visualization of the default easing function; an easing
function is only defined from a scale of 0 to 1 for fadeIn and
fadeOut” shows an illustration of
the default easing function.
Table 8.1. Parameters for Base's fade functions
|
Parameter |
Type |
Comment |
|---|---|---|
|
|
DOM Node |
The node that will be faded. |
|
|
Integer |
How many milliseconds the fade should last. Default value is 350. |
|
|
Function | A function that adjusts the acceleration and/or deceleration of the progress across a curve. Default value is:
Note that the easing
function is only defined from a domain of 0 to 1 for
|
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, “An simple easing function that is linear for values between
0 and 1”. The constant slope
guarantees that the animation is smooth and occurs at a constant
rate of change.
Figure 8.1. A visualization of the default easing function; an easing function is only defined from a scale of 0 to 1 for fadeIn and fadeOut
Example 8.1, “Fading out a node” demonstrates how to fade out a portion of the screen using the default parameters.
Example 8.1. Fading out a node
<html>
<head>
<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">
dojo.addOnLoad(function( ) {
var box = dojo.byId("box");
dojo.connect(box, "onclick", function(evt) {
var anim = dojo.fadeOut({node:box});
anim.play( );
});
});
</script>
</head>
<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, “An example of a custom easing function juxtaposed with the
default easing function”,
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);
}
dojo.fadeOut({
node:box,
easing : easingFunc,
duration : 3000
}).play( );
});});Tip
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, “The animateProperty function” in the same manner
that fadeIn and fadeOut work.
Table 8.2. The animateProperty function
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, “Expanding the dimensions of a node” 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>
<head>
<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">
dojo.addOnLoad(function( ) {
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>
</head>
<body>
<div id="box1" class="box blueBox">Click Here</div>
<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, “An example of a parabolic easing function”, 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, “An easing function that increases and then decreases in value”, 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, “_Animation control functions”.
Table 8.3. _Animation control functions
|
Method |
Parameters |
Comment |
|---|---|---|
|
|
|
Stops an animation.
If |
|
|
N/A |
Pauses an animation. |
|
|
|
Plays an animation,
optionally allowing for a delay (in milliseconds) before the
play operation. For paused animations, specifying |
|
|
N/A |
Returns the status of
an animation. Possible values for status are |
|
|
|
Stops the animation
and then advances its percentage complete between 0.0 and
1.0. Setting |
Warning
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, “Input methods for animateProperty” 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 |
|---|---|---|
|
|
N/A |
Fired before the
animation begins, providing access to the |
|
|
|
Fires after the
animation has begun cycling, so in effect, this method is
somewhat asynchronous. The |
|
|
|
Called for each discrete frame of the animation. The parameter is an object containing the current values for the style properties. |
|
|
N/A |
Called automatically when the animation ends. |
|
|
|
Called each time
|
|
|
|
Called each time
|
|
|
|
Called each time
|
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">
dojo.addOnLoad(function( ) {
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);
console.log("advanced to 50%");
});
});
});
</script>
</head>
<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="box1" class="box blueBox">Click Here</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, “Parameters for Core's slide functions”
summarizes.
Table 8.5. Parameters for Core's slide functions
|
Parameter |
Type |
Comment |
|---|---|---|
|
|
DOM Node |
The node that will be sliding. |
|
|
Integer |
How many milliseconds the fade should last. Default value is 350. |
|
|
Function | A function that
adjusts the acceleration and/or deceleration of the progress
across a curve. Default value is Note that the easing
function is only defined from a domain of 0 to 1 for the
|
|
|
Integer |
Where the node's left corner should be at the end of the slide. |
|
|
Integer |
Where the node's top corner should be at the end of the slide. |
Example 8.3, “Sliding a node” 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>
<head>
<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");
dojo.addOnLoad(function( ) {
var box = dojo.byId("box");
dojo.connect(box, "onclick", function(evt) {
dojo.fx.slideTo({
node:box,
top : "200",
left : "200"
}).play( );
});
});
</script>
</head>
<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, “Parameters for Core's wipe functions” provides a synopsis.
Table 8.6. Parameters for Core's wipe functions
|
Parameter |
Type |
Comment |
|---|---|---|
|
|
DOM Node |
The node that will be wiped. |
|
|
Integer |
How many milliseconds the fade should last. Default value is 350. |
|
|
Function | A function that
adjusts the acceleration and/or deceleration of the progress
across a curve. Default value is Note that the easing
function is only defined from a domain of 0 to 1 for the
|
Warning
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, “Wiping a node” can get you started.
Example 8.4. Wiping a node
<html>
<head>
<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");
dojo.addOnLoad(function( ) {
var box = dojo.byId("box");
dojo.connect(box, "onclick", function(evt) {
dojo.fx.wipeOut({
node:box
}).play( );
});
});
</script>
</head>
<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, “Animation combination and chaining” lists the functions
for combining and chaining.
Warning
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 |
|---|---|
|
|
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. |
|
|
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, “Chaining animations together” 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, “Combining animations” 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( );
});
});Warning
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, “Chaining and combining animations”, 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
dojo.fx.combine([slides, fades]).play( );
});
});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, “Parameters for Core's Toggler function”).
Table 8.8. Parameters for Core's Toggler function
|
Parameter |
Type |
Comment |
|---|---|---|
|
|
DOM Node |
The node to toggle. |
|
|
Function |
A function that
returns an |
|
|
Function |
A function that
returns an |
|
|
Integer |
The duration in
milliseconds to run |
|
|
Integer |
The duration in
milliseconds to run |
Table 8.9, “Toggler functions” provides the method summary for the class.
Table 8.9. Toggler functions
|
Method |
Comment |
|---|---|
|
|
Shows a node over a
duration defined by |
|
|
Hides a node over a
duration defined by |
Example 8.8, “Toggling a node” provides the compulsory
source code and another modification to addOnLoad for our working example from
Example 8.4, “Wiping a node”.
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, “A visualization of the x^5 easing function”.
<html>
<head>
<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");
dojo.addOnLoad(function( ){
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>
</head>
<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, “Blending Color objects”
illustrates the creation of two Color objects and a function Base provides
for blending colors.
Example 8.9. Blending Color objects
<html>
<head>
<title></title>
<script
type="text/javascript"
src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js">
</script>
<script type="text/javascript">
dojo.addOnLoad(function( ) {
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>
</head>
<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, “Color functionality supported by Base”
summarizes the Color class
provided by Base.
Table 8.10. Color functionality supported by Base
|
Method |
Comment |
|---|---|
|
|
The constructor
function, which accepts an array of RGB or RGBA values, or a
|
|
|
Works on an existing
|
|
|
Returns a |
|
|
Returns a |
|
|
Returns a |
|
|
Returns a
CSS-compliant |
|
|
Returns a
standardized |
Warning
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.
Figure 8.7. An example of how transparency works through the rgba( ) description for a color using Firefox 3
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, “Named color values available through Base” 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.
Warning
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
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, “Additional named color values available through
Core”). 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.
Tip
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
|
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
animatePropertyfunction to animate arbitrary CSS propertiesUnderstand the effect of easing functions, duration, and rate on an
_AnimationBe 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.chainas well as run multiple animations in parallel withdojo.fx.combineBe able to use
dojo.fx.Togglerto hide and show a node via its simple, uniform interfaceUnderstand how to combine animations with drag-and-drop to create highly interactive page content
Be able to create and effectively use
Colorobjects to eliminate manual computation of color values in your codeTip
There are amazing graphics and animation tools backed by SVG, VML, and Silverlight backends, provided through the
dojox.gfxmodule.
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.












Add a comment



Add a comment