JavaScript Sprite Animation Using jQuery

Tweet

Last week I reported on my tests using percentage to position background-images. Today’s post is a walk thru of where I put this research to work — published earlier in the week in the July 2007 Design View.

One of the nicest things about going to a real bricks ‘n’ mortar bookstore is the effortless pleasure of thumbing mindlessly through any book that takes your fancy — not that you actually read anything in particular, but it’s just a great way to get a general sense of its layout, style, and quality.

There's something about real books...While it’s difficult to convey information about the paper and binding quality via a screen (compared to fingertips), our marketing manager Shayne and I started wondering whether it might be possible to reproduce some of that effortless “page flicking” feel, using a touch of JavaScript.

The result of our first take on the idea is here — promoting Kevin and Cam’s new JavaScript primer, fittingly enough, although not actually part of the book’s content.

Although you’re more than welcome to pick through the live version on our site to see how it’s done, I’m going to step through you through a slightly simplified, standalone version here.

It’s a little long winded, but it’s hard to cut it much shorter without leaving out potentially important stuff.

12 page sprites

Part I: The Starting Point

There were a few decisions I made early on in the project:

  1. I wanted the final product to be as flexible as possible, so that I could add or subtract pages and alter the page sizes without having to make major changes to the code.
  2. I needed all of the individual book pages (between eight and 16 pages) to be contained in a single, large, flat rendered image (like this one). This meant that I could guarantee that all my page images were downloaded and “ready to rock” at the first sign of a click.It also meant that I could overlay the rendered 3D elements of a turning page on a separate, reusable PNG layer (like the one shown below). This one is obviously setup for our blue and orange page head and footer, so you might need to generate a plain white version for use on other books.Displaying just the central third of the page gives us only the shaded curves of the inner spine — great for adding some depth to the book sitting open. When our user attempts to “turn” a page forwards or backwards, we can then align this background image to either the right- or left-hand side of our book respectively. These three simple frames go a long way toward creating the illusion of a turning page.The repeating 3D part
  3. I wanted to base my solution on jQuery, because of its easy-to-learn syntax, small size (20k), and speed.

Part II: The Structure

The markup structure we’re going to use is a construction of four divs.

1. div#leftpage: the left-hand page
2. div#rightpage: the right-hand page
3. div#flip: the midway point between the pages
4. div#turner: a wrapper to hold the whole thing together

The structure of the page turning gadget

div#flip is set as ‘position:absolute‘, so we can float it centrally over our spine region.

The other three divs are all set to position:relative, and floated to the left so that they stack together neatly. I’ve set my page dimensions to be 189px x 146px, but there’s nothing special about these dimensions — they just happened to be about the right size for the page area I had available.

Once our page inserts our images into their div backgrounds, our static book is ready, waiting for jQuery to make it dance.

Demo Button

Part III: The JavaScript

1) The setup

Time to get our hands dirty. The first thing we need to do is attach jQuery to our document and add a new script tag to contain our custom script.

 

<script type="text/javascript" src="jquery.js"></script>

<script type="text/javascript>

/* our script goes here */

</script>

2) Setting up some useful variables

We have a handful of numbers that we’ll need to use several times, so it makes sense to store them in variables. That means we’ll only need to update our script in two places if we decide to change our page size later. The variable names do a fairly good job of describing what they are:


/* Page sizes*/

var $pageheight = 189; // our page height
var $pagewidth = 146; // our page width
var $pageYpos = 0;  // current Y position of our bg-image

3) Setting up our ‘ready’ event

One of the things I like about jQuery is its simple document ready event, which is a souped-up replacement for the old-fashioned onLoad event.

Any code placed inside this ‘ready event’ will be executed as soon as the bits it needs are available. It looks something like this:


$(document).ready(function(){
// Your code here
});

The nice part is that jQuery’s ready event will begin working as soon as the parts it needs are downloaded — the old-school onLoad event had to wait until your page had completely finished loading. If you begin experimenting with jQuery some more, you’ll find yourself using this function quite a lot.

4) Making the #leftpage div clickable

The markup for our book image doesn’t contain any links, so at the moment there are no clickable “hooks” upon which to base our page-turning animation.

That’s no biggie, though — with a few lines we can tell jQuery to watch #leftpage for clicks, and then to perform a number of tasks every time it registers a click there. The code looks like this:


 $("#leftpage").click(function(){
   /* do stuff when they click on #leftpage */

});

5) Making a click re-position our background image

Okay, now we’re getting somewhere! For when a user clicks on #leftpage, we’ll first calculate how far we need to move the background image, and then we’ll move it. We set our starting Y position ($pageYpos) at the top as zero, so we just nee to add exactly one “page height” unit in order to move the background image to the next page position. We express this as $pageYpos = $pageYpos + $pageheight. After one click, the value of $pageYpos will be 189, after two clicks it will 278, and so on.

We then use that value to reposition our background image. Here’s the code snippet to perform that repositioning:


$("#leftpage").click(function(){

$pageYpos = $pageYpos + $pageheight;

 $("#leftpage").css("background-position", "0px"+$pageYpos+"px");

});

In the code above, we’re selecting #leftpage and using jQuery’s built-in css function to reposition its background graphic.

If we were to try that code now, we’d see that things are finally starting to happen! Clicking the left side of #leftpage should instantly snap the background-image to display the next page. The neat thing about this sprite technique is that our background tiles automatically — when we arrive at the last frame, the first page rolls around and the loop continues. Nice!

Demo Button

6) Showing the page turn

Adjusting background position to animate the page turn

Next we need to display the page-turning part of the graphic by telling jQuery to set the background-position of our div to the top right. It’s simple enough to add this to our click event:


$("#flip").css("background-position", "top right");

7) Removing the page turn and changing the right-hand page

If we follow the same logic, it’s not hard to predict what our next snippet of code will look like. First we need to return #flip to its default, central position:


$("#flip").css("background-position", "top center");

Next we need to display the next page on our right-hand page. We already know the new Y-position ($pageYpos) because we used it to reposition the left-hand page background earlier.


$("#rightpage").css("background-position", "146px"+$pageYpos+"px");

8) Delaying the page-turn effect

Okay, so now we have the correct animation sequence — change left-hand page, show page-turn graphic, hide page-turn graphic & change right-hand page.

The problem is, these steps all happens so quickly that we never even see the page-turning animation. We need a way to delay the script momentarily, before it clears the page-turning graphic and continues. The most common way to control time in JavaScript is via the ‘setTimeout’ function.

‘setTimeout’ requires two arguments: the action you want to take, and how long (in milliseconds) you want it to wait before taking that action. For instance, if you want an alert to pop up after five seconds, you might use the following code:


setTimeout ("alert('Five seconds has passed!)'", 5000);

All we need to do is place our last two CSS changes inside their own ‘setTimeout’ functions. I’ve set the delay on both to 200 milliseconds, but you might like to adjust it to your taste. In fact, setting the right-hand page to animate a fraction later (300 milliseconds, for example) might be closer to what happens in the real world when we turn a page in a book.


/* return flip to default position */
setTimeout ('$("#flip").css("background-position", "top center");', 200); 

/* change right page  */
setTimeout ('$("#rightpage").css("background-position", "146px "+$pageYpos+"px");', 200); 

There you have it — dropping that code into our script gives us a simple but relatively convincing animation, without having written a lot of code.

Demo Button

9) Making the right-hand page turn

In the interests of keeping this edition of this already sprawling post to a semi-reasonable length, I won’t step through the entire process of animating the right page here. Suffice to say it’s a mirror image of our left-hand page function. Instead of adding to our background Y-position, we subtract from it and we use the alternate page graphic. Have a go at working it out for yourself, or check out the finished demo here.

Demo Button

Now, if you’re thinking ‘hang on a minute, that doesn’t look quite the same as the version on sitepoint.com‘, you’re quite right. The production version:

  1. has an extra corner page curl part to the animation
  2. has an extra sliding animation effect that eases each page into place as it settles (it’s subtle, but you’ll notice it)
  3. is unobtrusive — meaning we actually load a garden-variety IMG tag into the raw page, and then use jQuery to replace it on the fly with the DIV structure outlined above. Anyone visiting the page without JavaScript enabled will at least have access to the raw page images

Of course, feel free to experiment with adding those parts into or improving the demo here. This was the our first cut, and I already have a raw concept of an improved version. Obviously there are currently built-in scaling limitations to the technique — keeping all the pages on one graphic ensures cached graphics but every page added increases the initial download requirement.

Perhaps a future version might load blocks of pages at time to strike a balance?

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Gilles

    This is downright sweet!

  • Lupin

    Sir(s), I salute you.

    Well done!

  • anonymous hero

    Safari 2.0.4 doesn’t show it as you intend. But it’s pretty cool in FF.

  • mufaddal zirapurwala

    This code is awesome you guys are champions loads of thanks for the Script.
    hats off

  • someone

    if you click the right once, then the left… it’s not the same content that your expecting to see as you see in a REAL book

  • Jessy

    This is great… But, how would I set the book to “auto flip”?

  • http://www.sitepoint.com AlexW

    This is great… But, how would I set the book to “auto flip”?

    Jessy, it would take a little bit of rewriting, but I don’t think it would be terribly difficult.

    I explain the ‘timeOut’ function above. I think you would need to use that to replace the ‘.click(function())‘ code — set with a longish delay. It would eliminate the need to be able to flip in both directions so you can completely remove the backward page turn functions.

    Almost everything you need is there. It just needs to be rearranged and trimmed up a little to work.

    Give it a try and let me know how you go.

  • Marc Bourlon

    I think the easiest way to automate the page flip is this one: simply create a timeOut function, which clicks the page:
    something like this
    function autoPageFlip() {
    $(“#rightpage”).click(); // I love jQuery :)
    setTimeout(autoPageFlip, 4000);
    }
    and launch this by a first:
    setTimeout(autoPageFlip, 4000);

    Nothing else to do, no need to break this nice code, it should work fine ;-)
    Feel free to ask if any question.

    marc.bourlon _ at _ proxistep.com

  • xx3xxx

    if we use an image, rather than the stacked pages in the JPG

    but how about if the size of each 2 pages are different, how to adjust it in the program

    beside DEMO, any where , we could download full code??

  • chance

    This is a cool effect!

    However, IE6 does not support alpha transparency of PNG image!

    So that the effect is much better in Firefox then in IE6.

  • Chad

    I would like to do this with my online bible here.
    http://www.talkjesus.com/misc.php?do=page&template=bible_kjv

    however, the images provides are tiny and I’m not a graphic designer by trade nor do I know where to find “book” images like these.

    I need a dimension of about 700px width / 550px height. This is to make an actual book reading experience, online.

    Can someone help out on this please?

    chad@talkjesus.com / http://www.talkjesus.com

  • Phil

    simply great…

  • Dullat

    Awesome Script

  • Portabile84

    Hi…
    I’m sorry if I’ll disturb with this question… but I haven’t understood if this tutorial can be used freely. I like this, and I would like to use this effect in my web site, free-technology.org (an italian web site), particularly in the future section where we’ll put our free magazine.
    So… This tutorial is freeware or we have to purchase a license?
    Thanks to someones that can help me. ;)

    Portabile84

  • http://www.sitepoint.com AlexW

    Portabile84, you are more than welcome to use and adapt the script to your own needs. Of course, a credit URL to this page in the comments is always useful for others wondering how to do it.

  • Portabile84

    :D Thanks for your reply AlexW :D
    Ok… I’ll put a link into the footer and into the credits section of my web site :D

    Thanks

    PS: Happy 2008! ;)

  • Portabile84

    Hi…
    I have just create my Thumb Magazine Preview… Next week I will create the big resolution of the Magazine :D

    But I would like to tell to you that your script has a little bug :D

    If I click into the right page, to display next pages… ok It work with no problem.

    But If you try to click into the left page, the javascript script doesn’t dysplay the correct 2 previus pages…
    Also, a little advice ->Into the image screenshot, it will be better to use the same order.
    For example in the firs column we’ll put only the pages with negative page numbers, and into the second I think that it’s can be better to put only others page… :)

    Also… the Javascript code, It work correctly with my modification :D

    My Code…
    $("#leftpage")
    .css("background-position", "0px "+$pageYpos+"px");

    $("#flip")
    .css("background-position", "top right");
    setTimeout ('$("#flip").css("background-position", "top center");', 200);
    setTimeout ('$("#rightpage").css("background-position", "146px "+$pageYpos+"px");', 200);

    ......
    ......
    ......

    $("#rightpage")
    .css("background-position", "146px "+$pageYpos+"px");

    $("#flip")
    .css("background-position", "top left");
    setTimeout ('$("#flip").css("background-position", "top center");', 200);
    setTimeout ('$("#leftpage").css("background-position", "0px "+$pageYpos+"px");', 200);

    This code must be used only with the page order tha I have indicate into the prevoius text rows.

    I have a last question: Can I translate your tutorial and put itsel into my forum? :D
    I love this script :D :D

  • Rags

    I would like to incorporate this on my website, Can you let me know how do i create a page curl effect and the page sliding after page is opened(similar to what you have in your page).
    It would help me greatly to give a real page turn effect on my page.
    and also I would like to know how do I call the pages 1 at a time.(the book I am doing is having more than 250 pages)

  • http://www.sitepoint.com AlexW

    Rags, the post above is a complete explanation on how to achieve the effect, so just follow it through.

    As far as loading new pages as they are called, you would need to use AJAX to preload pages just before they are needed. This is quite doable, but it’s outside the scope of what I was trying to achieve with the effect.

    But if you manage to get it running, we’d be keen to see it in action.

  • sm

    First off awesome script!!!

    One question is there a way I jump to a particular page. Like by putting a button that would skip it say page 2 & 3?

  • chachiisme

    First off awesome script!!!

    One question is there a way I could place a button on the page that would skip to a particular page in the book like say page 3 & 4 with out turning the page?

  • http://www.sitepoint.com AlexW

    First off awesome script!!!

    One question is there a way I could place a button on the page that would skip to a particular page in the book like say page 3 & 4 with out turning the page?

    Thanks chachiisme,

    I would take a little bit more coding, but it wouldn’t be hard. Off the top of my head, you would need to add a new function.That function would be similar to the #leftpage/#rightpage functions used in the example above, except it would hardcode the position of the background image to the exact position of the page you wanted, rather than just keeping track of it’s current Y position ($pageYpos = $pageYpos + $pageheight;) as it does now.

    You’d them have to tie that new function to a button or link to set trigger it.

  • nutkong

    Gorgeous

  • Anonymous

    the finished demo JS is wrong. Right flip.
    Notice that when you right flip, the page displays right-side-left
    Right Turner code should be:

    /* right page turner */
    $("#rightpage").click( function() {
    $pageYpos = $pageYpos - $pageheight; // note: minus page height
    $("#rightpage")
    .css("background-position", "0px "+$pageYpos+"px");

    $("#flip").css("background-position", "top left");
    setTimeout ('$("#flip").css("background-position", "top center");', 200);
    setTimeout ('$("#leftpage").css("background-position", "146px "+$pageYpos+"px");', 200);

  • Devon

    How did you generate the image for the curves and curls? I need to make one without the orange and blue stripes. Thanks!

  • http://www.sitepoint.com AlexW

    Devon, if you use Fireworks, I’d be happy to give you a copy of the working graphics I used. If you don’t have Fireworks, that file isn’t much more use to you than the file used in the example.

  • http://www.sitepoint.com AlexW

    In fact, here is the working PNG if anyone is interested.

    http://www.sitepoint.com/examples/jquery/pageturn-working.png

  • Anonymous

    how do you add a note book images insted of your pages.Then can you add a item to were you can type on the page? if you can E-mail me At sdydy1@aol.com

  • supercal5

    If you are not averse to using flash…
    then this link has a free version available:
    http://www.flashpageflip.com/

    head and shoulders above using javascript…
    just drop in jpgs and minor adjustments to an xml.

  • Bob

    Cool idea but the animation of the page turning does not look good.. It’s a start I guess.

  • suresh

    Hai sir,
    iam very intersting when iam seeing the your code sir,and also one thing i will say i am new to this fields sir,iam intrested to learn more things from u sir , please permit me and try to helpmesir. iam more intrested aboutanimations by using javascript sir.
    thanking you sir.

  • infocyde

    “Safari 2.0.4 doesn’t show it as you intend. But it’s pretty cool in FF”

    Welcome to Safari hell…

    Safari is being updated all the time, maybe it will one day be a class “A” browser, but till then expect this…it is worse the IE for a lot of things.

    Go FF!

  • Anonymous

    sorry to be the kill joy but this animation is downright ugly

  • Nico

    I like the sound when I change the page…… Is it possible?

  • http://www.sitepoint.com AlexW

    Nico, there is a sound plugin for jQuery that uses SWF files.

    http://plugins.jquery.com/project/sound

    Shouldn’t be hard to tie it to the page turn event. Have a go and let us know if you get something going.

  • http://www.facebook.com/Birowsky Daniel Birowsky

    nnnnnice!

    please explain how do you use the mouse to control those multiple sprites fade animations

  • http://www.facebook.com/virtusolutions Venugopal Rao Boddapadu

    nice jquery, very usefull http://www.venub.com – Website Designer