JQuery: Novice to Ninja- P10

JQuery: Novice to Ninja- P10

JQuery: Novice to Ninja- P10:No matter what kind of ninja you are—a cooking ninja, a corporate lawyer ninja, or an actual ninja ninja—virtuosity lies in first mastering the basic tools of the trade. Once conquered, it’s then up to the full-fledged ninja to apply that knowledge in creative and inventive ways.

Nội dung Text: JQuery: Novice to Ninja- P10

112 jQuery: Novice to Ninja
1. Stack the images on top of each other, so that the picture with the highest z-index
will be showing.
2. Fade out the top image so that the next image appears to fade in.
3. Once the fade has completed, reorder the z-index of the images so that the current
image is on top.
4. Repeat steps 2 and 3.
A disadvantage of this technique is that we’ll be stacking the images on top of each
other, so they must all be the same size. This usually is a small issue, as it’s fairly
common on the Web to be constrained to a certain area. It should also be noted that
Licensed to JamesCarlson@aol.com
it’s very easy to switch out the images for divs and be able to cross-fade any HTML
in their place.
z-index
z-index is a CSS property used to specify the visual stacking order of an element.
Elements with higher z-index values will appear in front of those with lower
values. This can be used in conjunction with absolute or relative positioning to
stack elements on top of each other.
Looking back at our outline, you should be able to tell that steps 1 and 2 are
straightforward. Let’s start by stacking up our images:
chapter_04/07_slideshow_cross_fade/index.html (excerpt)
⋮
We need to position the images absolutely and contain them within a bounding
box:

Images and Slideshows 113
chapter_04/07_slideshow_cross_fade/style.css (excerpt)
#photos img {
position: absolute;
}
#photos {
width: 180px;
height: 180px;
overflow: hidden;
}
Now that our images are stacked, let’s step back and do some planning. In order to
be able to execute step 4 (repeating the fade for the next image), we’ll need to put
Licensed to JamesCarlson@aol.com
our fading code in some sort of loop. As the loop needs to keep track of the current
photo, we’re going to move our code out into a named function, which we’ll call
from our $(document).ready block:
chapter_04/07_slideshow_cross_fade/script.js (excerpt)
$(document).ready(function() {
rotatePics(1);
}
Now we’ll create the rotatePics function, which will do all the hard work. This
method accepts a number, which should be the index of the current photo. We’ll
see how this is used shortly, but first, we store the total number of photos in a
variable. We do this because we’re going to be reusing it a few times in the code—and
storing it in a variable means jQuery is spared from wasting time doing the same
calculations over and over:
chapter_04/07_slideshow_cross_fade/script.js (excerpt)
function rotatePics(currentPhoto) {
var numberOfPhotos = $('#photos img').length;
currentPhoto = currentPhoto % numberOfPhotos;
⋮
}
The second line of code is a common JavaScript trick for ensuring that values are
confined to a given range. We never want the currentPhoto to be greater than the
total number of photos, so we perform a calculation to ensure that the index of the

114 jQuery: Novice to Ninja
photo we passed in is valid—by taking the modulus of the length. Modulus, repres­
ented in JavaScript by the % symbol, returns only the remainder of a division. So if
we have five photos in total, and we pass in an index of six, the operation gives 6
% 5 = 1. The number is effectively wrapped around back to the start, and we can
be sure we’re never trying to display a photo that’s nonexistent!
Now we can finally proceed with doing the actual cross-fade. As we described in
our outline, the effect works by fading out the current image. This will give the ap­
pearance of the next image fading in.
We use jQuery’s eq traversing command to grab the current photo. eq—short for
“equals”—selects the element from a group whose index is equal to the number we
Licensed to JamesCarlson@aol.com
pass in. We pass it our currentPhoto variable to select the current image. With the
image selected, we simply fade it out and run a callback function to take care of the
setup for the next fade:
chapter_04/07_slideshow_cross_fade/script.js (excerpt)
$('#photos img').eq(currentPhoto).fadeOut(function() {
// re-order the z-index
$('#photos img').each(function(i) {
$(this).css(
'zIndex', ((numberOfPhotos - i) + currentPhoto) %
➥numberOfPhotos
);
});
$(this).show();
setTimeout(function() {rotatePics(++currentPhoto);}, 4000);
});
There are a few things happening here. First, we do a bit of math to reorder the
images. We offset each photo’s index by the currently displayed photo index. Then
our new modulus trick is put to use again, and the end result is each image’s z-index
shuffled along by 1. To see this in action, open up Firebug and inspect the images
as the effect is running: you’ll see the z-index properties shuffling each time a new
image displays.
Once we’ve completed the reordering, the picture we just faded out will be on the
bottom of the pile. This means that it’s safe to show it again, ready for the next time
it rises to the top: an easy $(this).show().

Images and Slideshows 115
Then there’s a call to the timer function setTimeout to set up the function to be run
again after a delay of 4,000 milliseconds. We pass it the next photo’s index by
writing ++currentPhoto.
Increment and Decrement
In JavaScript, if you follow or precede a numeric variable with -- or ++, the
variable will be decremented or incremented by 1, respectively. This is a handy
shortcut for the -= and += operators we’ve already seen.
The difference between ++a and a++ is subtle, but important. If you are using it
in your code, the first form (with the ++ or -- preceding the variable name) will
increment the variable before returning it. The second form will return the unmod­
Licensed to JamesCarlson@aol.com
ified value, then increment it.
In our code above, we want to call our function with the new incremented value,
so we use ++currentPhoto.
Feel free to experiment with the type of effect; as well as fades, you can try using
the slideUp effect, or one of the jQuery UI effect plugins.
Advanced Fading with Plugins
As you’d imagine, there are countless jQuery plugins already built for transitioning
between images. If you have some advanced requirements (sometimes you just need
to have a starburst wipe), heading straight for the plugin repository could be a good
idea.
Before Using a Plugin
Many jQuery plugins you find on the Web were developed quite some time ago,
and have been more or less abandoned since then. Without continued development
and improvement, they’ll often be comparatively slow and buggy. It’s always a
good idea to try to understand what you’re adding to your site, instead of blindly
including a half-dozen plugin files. If the code is heavy (in terms of file size) and
has a lot of functionality unnecessary for your requirements, perhaps a more
lightweight, tailor-made solution is in order.
That said, many plugins provide excellent, well-documented code that will save
you enormous amounts of time and effort. Just be sure to adequately consider
your options!

116 jQuery: Novice to Ninja
Now we’ll look at two plugins you can use to achieve a slideshow effect; one is ex­
tremely lightweight, while the other has more features.
News Ticker with InnerFade
InnerFade4 is a tiny plugin that lets you transition between a series of elements,
much like the fading image gallery we just built. It does have a few benefits over
our code that makes it worth considering. For one, it’s a plugin—which means it’s
easy to drop in wherever we need it. Of course, we can easily turn our code into a
plugin too (just jump to the section called “Plugins” in Chapter 9 to see how easy
it is). It also has some extra options that give us more flexibility: the ability to show
the items in a random order, give a class name to the active element, and choose
different animation types.
Licensed to JamesCarlson@aol.com
You might be thinking that all these features would be fairly easy to add to our
custom code—after all, we’re well on our way to becoming jQuery ninjas! If you’re
feeling adventurous, open up the InnerFade plugin file to see how these features
have been developed in there, which should give some idea about how you would
implement them yourself.
As a departure from our image rotations, let’s have a look at rotating list items to
create a simple news ticker, where a list of text links will be displayed randomly.
To kick it off, we need to include the plugin in our page.
The ZIP file is linked at the very bottom of the plugin’s web page. It’s over
100KB—but don’t worry, most of that size consists of images used in the demos.
The actual script weighs in at 8KB, and that’s without being compressed!
chapter_04/08_innerfade/index.html (excerpt)
Next, we’ll set up our containing element and the items we’d like to scroll. The
plugin will treat all first-level children of the container we pass to it as fair game
to cycle through. We’ll use an unordered list as the container, and the list items as
the elements:
4
http://medienfreunde.com/lab/innerfade/

Images and Slideshows 117
chapter_04/08_innerfade/index.html (excerpt)
News
Barron Von Jovi spotted …
Mo'Fat signs up-and-coming rapper …
Glendatronix rumored to be …
Man claims to be Darth Fader's son …
When our document is ready, we use the plugin’s provided innerfade method on
the list. There are a number of options available to customize the way this method
Licensed to JamesCarlson@aol.com
works; we’re using a few here, and you should consult the plugin’s documentation
to discover all of them. We’ll specify a slide effect, rather than a fade effect, to round
out our news ticker style, and we’ll have the elements rotate at random:
chapter_04/08_innerfade/script.js (excerpt)
$('#news ul').innerfade({
animationtype: 'slide',
speed: 750,
timeout: 2000,
type: 'random'
});
And there we have it: a simple and cool effect for displaying news items. The Inner-
Fade plugin is also perfectly suitable for image galleries like the ones we’ve already
built, though you should be aware of one important difference. InnerFade handles
all of the item hiding, showing, and positioning in its code—so without JavaScript
all of the elements will be displayed (whereas in our custom code, we hid all but
one in CSS). You’ll need to take this into consideration, and decide what you want
the baseline experience of your site to be and how you’d like to enhance it with
jQuery.
The Cycle Plugin
The Cycle plugin5 is a very mature, full-featured plugin that—like all the fading we
have been doing—enables you to transition between elements in a container. Its
5
http://malsup.com/jquery/cycle/

118 jQuery: Novice to Ninja
completeness results in a comparatively hefty download (25KB for the complete
minified version), but offers some impressive transition effects, well suited for dis­
playing image galleries in a more interesting manner.
The setup should be very familiar to you now: download the plugin and add the
JavaScript file to the head of your page. There are actually three different versions
of the plugin contained in the download: a base version with only a slide transition
(jquery.cycle.min.js, 16KB), a full-featured version with a wide range of available
transitions (jquery.cycle.all.min.js, 25KB), and a stripped-down version with only the
most basic options (jquery.cycle.lite.min.js, 4KB). For our example, we’ll use the full-
fledged version for the sake of illustrating the available options.
Licensed to JamesCarlson@aol.com
We’ll start off with exactly the same markup we used for our previous slideshows.
You can easily cross-fade images with the Cycle plugin, but given that it’s provided
us with a number of fancier options, let’s try one and “shuffle” the images:
chapter_04/09_cycle_plugin/script.js (excerpt)
$('#photos').cycle({
fx: 'shuffle'
});
This effect is illustrated in Figure 4.5.
Figure 4.5. The shuffle effect included in the Cycle plugin

Images and Slideshows 119
The plugin gives us more than 20 ways to move around our gallery: shuffle, fade,
zoom, wipe, toss, curtainX, growY … for starters. Additionally, the plugin can be
customized to include your own transition effects, if you’re unable to find one that
suits your needs.
The number of options offered in Cycle is quite astounding, probably far more than
you’ll ever need. Let’s try out a more complicated example:
chapter_04/10_cycle_plugin_2/script.js (excerpt)
$('#photos').cycle({
fx: 'scrollDown',
speedIn: 2500,
Licensed to JamesCarlson@aol.com
speedOut: 500,
timeout: 0,
next: '#photos'
});
The timeout setting controls the time between transitions—but what would a value
of 0 mean? In this case it means “don’t animate.” Instead, we’ve used the next option
to select an element that, when clicked, will advance to the next slide. That selector
is the slideshow itself—so to move to the next picture, you just need to click on the
picture.
Additionally, we’ve used the speedIn and speedOut options to specify the duration
of the “in” and “out” animations: we’ve chosen to sloooowly bring the next picture
into view, while quickly dismissing the last. There are so many options available
that you’ll need some serious playing with it to exhaust the possibilities for usable
effects.
Scrolling Slideshows
As we saw when using the Cycle plugin, cross-fading is far from being the only way
to transition between a set of images. In the next few examples, we’ll explore another
technique for creating interactive slideshows. We’re going to throw all our images
in a giant container, and use a wrapper element to hide all but one or a few from
view. Then, when we want to display a different image, we’ll just scroll the element
to the desired position.

120 jQuery: Novice to Ninja
Thumbnail Scroller
Our first stab at a scrolling gallery will be a horizontal list of thumbnails. If you
click on the control, the list scrolls along to reveal more images.
To build this control we’ll need to have two nested elements. The child element
will be large and contain all of the images. The parent element is only as big as the
viewing area; that is, the area we want the user to see. As the child element moves
around, it appears to the user that the content is scrolling in. Here’s the markup:
chapter_04/11_thumbnail_scroller/index.html (excerpt)
Licensed to JamesCarlson@aol.com
⋮
The outer element needs to hide the excess content, and so needs to have overflow:
hidden. For our scroller, we define the inner element to have a width wide enough
to fit our 15 thumbnails:
chapter_04/11_thumbnail_scroller/style.css (excerpt)
#photos {
overflow: hidden;
width: 600px;
}
#photos_inner {
height: 100px;
width: 1500px;
overflow: hidden;
position: relative;
}
#photos_inner img {
float: left;

Images and Slideshows 121
width: 100px;
height: 100px;
}
With our container all set up, and an armful of images to show, let’s take a first stab
at scrolling the images:
chapter_04/11_thumbnail_scroller/script.js (excerpt)
$('#photos_inner').toggle(function() {
var scrollAmount = $(this).width() - $(this).parent().width();
$(this).animate({'left':'-=' + scrollAmount}, 'slow');
}, function() {
Licensed to JamesCarlson@aol.com
$(this).animate({'left':'0'}, 'slow');
});
First we need to calculate how much to scroll. We take the width of the overflowed
element that contains images and subtract that from the width of the parent container.
The parent action selects an element’s immediate parent (see the section called
“Bits of HTML—aka “The DOM”” in Chapter 1). We use this to tell us how far we
need to scroll to reach the very end of the images. When we click on the images,
our scroll effect toggles between the start and end of the images.
This is great if we have less than two screen width’s worth of images. But if we have
more, we’ll be unable to see all the images that lie in between the six on either end,
so we need a different approach. A better way is to scroll, say, a half-screen’s worth
of images at a time. When we reach the end of the list, we’ll scroll back to the start.
Let’s expand on our code to make it more bulletproof:

122 jQuery: Novice to Ninja
chapter_04/12_thumbnail_scroller_improved/script.js (excerpt)
$('#photos_inner').click(function() {
var scrollAmount = $(this).width() - $(this).parent().width();
var currentPos = Math.abs(parseInt($(this).css('left')));
var remainingScroll = scrollAmount - currentPos;
// Scroll half-a-screen by default
var nextScroll = Math.floor($(this).parent().width() / 2);
// But if there isn’t a FULL scroll left,
// only scroll the remaining amount.
if (remainingScroll < nextScroll) {
nextScroll = remainingScroll;
Licensed to JamesCarlson@aol.com
}
if (currentScrollPos < scrollAmount) {
// Scroll left
$(this).animate({'left':'-=' + nextScroll}, 'slow');
}
else{
// Scroll right
$(this).animate({'left':'0'}, 'fast');
}
});
Woah, that’s certainly more code—but if you walk through line by line, you’ll see
that it’s all fairly uncomplicated. We’re using quite a lot of variables, and because
we’ve given them clear names, it helps to make the code a little easier to understand:
As in the previous example, we first calculate the total amount of scrolling
space we have: our scrollAmount variable.
Because our new scroller needs to be able to handle more than two screens’
worth of images, we also need to figure out how far along we currently are. We
use the JavaScript function Math.abs() to convert the current scroll position
to a positive number, because scrolling to the left means we’re moving the
elements into negative territory. If your high school math is deep down in your
memory, here’s a refresher: the absolute value of a number will always be its
positive value, whether the number itself is positive or negative. So Math.abs(3)
is 3, and Math.abs(-3) is also 3.

Images and Slideshows 123
We know how much space there is in total, and we also know how far along
we are—so it’s simple to find out how far we have to go! Just subtract the latter
number from the former.
Now for the real business: we need to calculate how far to scroll. By default,
this will be half of the total width of our image container. (Math.floor() is a
way of rounding an image down, so we’re sure we end up with a round number.)
We store the distance we want to scroll in the nextScroll variable.
If there’s less space left than what we want to scroll, we’ll change our
nextScroll variable to only bring us to the end of the images.
Finally, we scroll. If we’ve yet to reach the end of the images (if our current
Licensed to JamesCarlson@aol.com
position is less than the total scrollable width), we scroll to the left by the
amount we calculated. Otherwise (if we’re at the end of the images), we scroll
all the way back to the beginning.
If you think that’s a lot of code for a fairly basic effect, you’re right! If only there
was a way of scrolling content without doing all that math …
A Scrolling Gallery with scrollTo
You might remember that back when we looked at scrolling in Chapter 3, we men­
tioned a particularly useful plugin for scrolling the page: scrollTo. As well as
scrolling the entire page, the scrollTo plugin excels in scrolling overflowed elements
(like those in a picture gallery) too! In our first stab at a scrolling thumbnail gallery,
we had to do quite a few of our own calculations to determine how big the scrollable
area was, and whether we were at the end or the start of the container.
The scrollTo plugin automatically figures a lot of this out for us, so we can concen­
trate on adding more complex features. In this demo we’re going to remove our list
of thumbnails, and replace them with larger images. The large images will be con­
tained in a grid—but we’re only going to display one at a time. When the user clicks
on the image, we’ll scroll around the grid, and stop on a new random picture.
To start off, we’ll need a list of pictures. For simplicity, we’ll just set it up as a swag
of image tags, inside a div container—itself contained inside another div. You might
like to set it up as an unordered list of images inside a div, to be semantically nicer,
but what we need to end up with is a block level element that’s as big and wide as

124 jQuery: Novice to Ninja
our grid. This needs to be inside an element with overflow: hidden (or auto).
Here’s what we mean:
chapter_04/13_scrolling_gallery/index.html (excerpt)
⋮
Licensed to JamesCarlson@aol.com
We’ll make the pic_container div the width of, say, three images and the height of
four images; the pictures, therefore, will be confined to a 3x4 grid. For this demo,
we’ll be using images that are 200x200px, so our container needs to be 800px wide
and 600px high. We’ll then make the visible region the size of a single image, and
hide all the rest:
chapter_04/13_scrolling_gallery/style.css (excerpt)
#pic_container {
overflow: hidden;
height: 200px;
width: 200px;
margin-bottom: 15px;
}
#pic_scroller {
height: 600px;
width: 800px;
overflow: hidden;
}
#pic_scroller img {
float: left;
}
Now that our grid is ready, we can add some random scrolling pixie dust. We first
grab all the images, then choose a random one and scroll to it using scrollTo:

Images and Slideshows 125
chapter_04/13_scrolling_gallery/script.js (excerpt)
$('#pic_scroller').click(function() {
var numberOfPics = $(this).find('div > img').length;
var next = Math.floor(Math.random() * numberOfPics);
$(this)
.scrollTo(
'#photos_inner>img:eq(' + next + ')',
{duration: 1000}
);
});
That’s certainly a lot simpler than our last example! The plugin takes care of almost
all the complicated parts. That said, there are two new bits of jQuery in there: the
Licensed to JamesCarlson@aol.com
find action, and the :eq filter. find functions in much the same way as the main
jQuery $ selector itself, except that it searches only within the currently selected
element, rather than the whole document.
The :eq filter works exactly like the eq action we saw earlier, except that it’s a filter,
so you use it inside a selector string. We pass it a random number between 0 and
the total number of images to select a random image.
Random Numbers
Math.random will give you a random number between 0 and 1. More often,
though, you’re looking for random whole numbers in a given range. The easiest
way to achieve this is by writing Math.floor(Math.random() * maximum).
You multiply the fraction by the maximum number you’d like, then round it down
to the nearest whole number.
Notice how easy it is to ask scrollTo to scroll to a specific element: we simply pass
it a selector that will match that element!
Smarter Scrolling with the data Action
There’s a fairly big problem with the component we’ve built, however, especially
if you have a small number of images: the next random image to display might be
the same one we’re currently on! In this case no scrolling takes place, making it feel
like a bug. To remedy this, we need to keep track of what the last image was:

126 jQuery: Novice to Ninja
chapter_04/14_scrolling_gallery_improved/script.js (excerpt)
$('#pic_scroller').click(function() {
var numberOfPics = $(this).find('div > img').length;
var last = $(this).data('last');
var next = Math.floor(Math.random() * numberOfPics);
if (next == last) {
next = (next + 1) % numberOfPics;
}
$(this)
.data('last', next)
.scrollTo(
'#photos_inner>img:eq(' + next + ')',
{duration: 1000});
Licensed to JamesCarlson@aol.com
});
We’re using a new and extremely powerful jQuery action: data. data is unlike any
action we’ve seen so far, because it allows us to store information in any jQuery
object. We call it with two parameters to store data. The first parameter becomes
the name of the data item, and the second is the value to store. Then, to retrieve
data, we pass in only one parameter: the name of the data item.
In our improved example, once we find the image we’re going to scroll to, we store
the number element with the command $(this).data('last', next). The next
time the scroller element is clicked, we read it back again with the command
$(this).data('last'). If our new element is the same as our last, we simply add
1 to it to scroll to the next image. (We use the modulus again to ensure we stay
within the total number of images).
You should carefully study the two lines of code where we retrieve and set data on
the element (highlighted above). We’ll be using this amazing jQuery feature a lot in
the coming chapters, so do yourself a favor—commit it to memory, and play with
it as much as you can!
iPhoto-like Slideshow widget
We’ll look at a more advanced slideshow by building an iPhoto-like widget (iPhoto
is the included image gallery application in Mac OS X). Mousing over the left or
right side of the current image will scroll to the next or previous image, so the user
can flip casually through the gallery. This is the most advanced jQuery we’ve seen
so far, and it might be difficult for you to make complete sense of it the first time