Sie sind auf Seite 1von 8

Register / Login

The world's best-selling magazine


for web designers and developers
Search .net website Search
Since 1994

HOME NEWS TUTORIALS FEATURES INTERVIEWS OPINIONS SHOP PREMIUM

POPULAR TAGS HTML FLASH CSS NAVIGATION PHOTOSHOP BROWSE BY TAG POPULAR THIS WEEK

Create a page flip effect with HTML5 21 top tools for responsive web design

canvas When perfect code gets FUBAR ... and


how to avoid it!
By Hakim El Hattab on August 05, 2011 | 2 comments Like
Design the perfect footer in Photoshop

Knowledge needed: JavaScript, HTML, CSS


Requires: Text editor, any browser that supports the HTML5 canvas element Project time: 3 hours The top 10 SEO myths
DOWNLOAD SOURCE FILES

VIEW DEMO The future of CSS layouts

Web developer and creative programmer Hakim El Hattab shows us a new take on the
‘Flash page flip’ we all love to hate, using HTML5’s canvas and JavaScript. He explains
how Fi built 20thingsilearned.com

This article first appeared in issue 211 of .net magazine - the world's best-selling magazine
for web designers and developers.

For a long time, web developers leaned on plug-ins to bring truly immersive and rich
interactive experiences to their users. HTML5 has begun to change all this by bringing some
of the most crucial building blocks of these web augmentations to the open web.

We at F-i.com collaborated with the Google Chrome team on an HTML5-based educational


web app called 20 Things I Learned About Browsers and the Web. One of the key ideas
behind this project was that it would be best presented in the context of a book. Since the
contents of the book is very much about open web technologies we felt it was important to
stay true to that by making the container itself an example of what these technologies enable
us to accomplish today.

JOIN THE COMMUNITY!


Comment on articles, get the 'Week in Web Design'
newsletter and receive exclusive offers!

Enter your email to register... Continue

In the time designers spend


redesigning a beautiful yet faux
mock for someone else’s existing
service for free, they could have
been creating something real of
their own.

Yaron Schoen on Don't redesign on spec


READ MORE

We decided that the best way to achieve the feeling of a real-world book would be to
simulate the good parts of the analogue reading experience while leveraging the benefits of
the digital realm in areas such as navigation. A lot of effort went into the graphical and
interactive treatment of the reading flow – especially how the pages of the books flip from
one page to another.

This tutorial will take you through the process of creating your own page flip effect using the
canvas element and plenty of JavaScript. Some of the rudimentary code, such as variable
declarations and event listener subscription, has been left out of the snippets in this article,
so remember to reference the tutorials files for the complete code.

ADVERTISEMENT

The markup
.net magazine on Facebook
It’s always important to remember that what we draw on canvas can’t be indexed by search Like
engines, selected by a visitor or found by in-browser searches. For that reason, the content
we will be working with is put directly in the DOM and then manipulated by JavaScript if it is 5,138 people like .net magazine.

available. The markup required for this is minimal:

VIEW SOURCE
Sam Sally Tom G Harshini Michael
COPY CODE
1. <div id="book">
2. <canvas id="pageflip-canvas"></canvas>
3. <div id="pages"> Bill Pete Rudy Victor Sarah
4. <section> Facebook social plugin
5. <div> <!-- Any type of contents here --> </div>
6. </section>
7. ...
8. </div>
9. </div>

We have one main container element for the book, which in turn contains the different pages
of our book and the canvas element that we will be drawing the flipping pages on. Inside of
the section element there is a div wrapper for the content – we need this to be able to
change the width of the page without affecting the layout of its contents.

The div has a fixed width and the section is set to hide its overflow. This results in the width of
the section acting as a horizontal mask for the div.

The script
The code required to power the page flip is not very complex, but it is quite extensive since it
involves a lot of procedurally generated graphics.

Let’s start by looking at the description of the constant values we’ll be using throughout the
code.

VIEW SOURCE
COPY CODE
1. var BOOK_WIDTH = 830;
2. var BOOK_HEIGHT = 260;
3. var PAGE_WIDTH = 400;
4. var PAGE_HEIGHT = 250;
5. var PAGE_Y = ( BOOK_HEIGHT - PAGE_HEIGHT ) / 2;
6. var CANVAS_PADDING = 60;

The CANVAS_PADDING is added around the canvas so that we can have the paper extend
outside of the book when flipping. Note that some of the constants defined here are also set
in CSS, so if you want to change the size of the book you will also need to update the values
there.

The constant values used throughout the code to track interaction and draw the page flip

Next we need to define a flip object for each page. These will constantly be updated as we
interact with the book to reflect the current level of progress in the flip.

VIEW SOURCE
COPY CODE
1. var book = document.getElementById( "book" );
2. var pages = book.getElementsByTagName( "section" );
3. for( var i = 0, len = pages.length; i < len; i++ ) {
4. pages[i].style.zIndex = len - i;
5. flips.push({ progress: 1, target: 1, page: pages[i], dragging: false });
6. }

First we need to make sure the pages are layered correctly by organising the z-indexes of
the section elements so that the first page is on top and the last page is on the bottom. The
most important properties of the flip objects are the progress and target values. These are
used to determine how far the page should currently be folded: -1 means all the way to the
left, 0 means the dead centre of the book and +1 means the right-most edge of the book.
The progress and target values of the flips are used to determine where the folding page should be drawn on a -1 to +1 scale

Now that we have a flip object defined for each page we need to start capturing and using
the user’s input to update the state of the flip.

VIEW SOURCE
COPY CODE
1. function mouseMoveHandler( event ) {
2. // Offset mouse position so that the top of the spine is 0,0
3. mouse.x = event.clientX - book.offsetLeft - ( BOOK_WIDTH / 2 );
4. mouse.y = event.clientY - book.offsetTop;
5. }
6. function mouseDownHandler( event ) {
7. if (Math.abs(mouse.x) < PAGE_WIDTH) {
8. if (mouse.x < 0 && page - 1 >= 0) {
9. flips[page - 1].dragging = true;
10. } else if (mouse.x > 0 && page + 1 < flips.length) {
11. flips[page].dragging = true;
12. }
13. }
14. // Prevents the text selection cursor from appearing when dragging
15. event.preventDefault();
16. }
17. function mouseUpHandler( event ) {
18. for( var i = 0; i < flips.length; i++ ) {
19. if( flips[i].dragging ) {
20. flips[i].target = mouse.x < 0 ? -1 : 1;
21. if( flips[i].target === 1 ) {
22. page = page - 1 >= 0 ? page - 1 : page;
23. } else {
24. page = page + 1 < flips.length ? page + 1 : page;
25. }
26. }
27. flips[i].dragging = false;
28. }
29. }

The mouseMoveHandler function updates the mouse object so that we are always working
towards the most recent cursor location.

In mouseDownHandler we start by checking if the mouse was pressed down on either the
left or the right page so that we know which direction we want to start flipping towards. We
also ensure that another page exists in that direction since we might be on the first or last
page. If a valid flip option is available after these checks, we set the dragging flag of the
corresponding flip object to true.

Once we reach the mouseUpHandler we go through all of the flips and check if any of them
were flagged as dragging and should now be released. When a flip is released we set its
target value to match the side it should flip to depending on the current mouse position. The
page number is also updated to reflect this navigation.

The next block of code we are going to cover is inside of the render function, which is called
60 times per second to update and draw the current state of all active flips.

VIEW SOURCE
COPY CODE
1. if( flip.dragging ) {
2. flip.target = Math.max( Math.min( mouse.x / PAGE_WIDTH, 1 ), -1 );
3. }
4. flip.progress += ( flip.target - flip.progress ) * 0.2;

If the flip is being dragged we update its target to match the mouse position but on a -1 to 1
scale rather than actual pixels. We also increment the progress by a fraction of the distance
to the target. This will result in a smooth and animated progression of the flip since it updates
on every frame.

VIEW SOURCE
COPY CODE
1. if( flip.dragging || Math.abs( flip.progress ) < 0.997 ) {
2. drawFlip( flip );
3. }

Since we are going over all of the flips on every frame, we need to make sure we only redraw
the ones that are active.

If a flip is not in very close range of the book edge, or if it is flagged as dragging, it will be
rendered.

Now that all of the logic is in place, we need to draw the graphical representation of a flip
depending on its current state. It’s time to look at the first part of the drawFlip(flip) function.

VIEW SOURCE
COPY CODE
1. // Strength of the fold is strongest in the middle of the book
2. var strength = 1 - Math.abs( flip.progress );
3. // Width of the folded paper
4. var foldWidth = ( PAGE_WIDTH * 0.5 ) * ( 1 - flip.progress );
5. // X position of the folded paper
6. var foldX = PAGE_WIDTH * flip.progress + foldWidth;
7. // How far outside of the book the paper is bent due to perspective
8. var verticalOutdent = 20 * strength;
9. // The maximum width of the left and right side shadows
10. var paperShadowWidth = ( PAGE_WIDTH * 0.5 ) * Math.max( Math.min( 1 - flip.progress, 0.5 ), 0 );
11. // Mask the page by setting its width to match the foldX
12. flip.page.style.width = Math.max(foldX, 0) + "px";

This section of the code starts by calculating a number of visual variables that we need to
draw the fold in a realistic manner. The progress value of the flip we are drawing plays a big
part here, since that is where we want the page fold to appear. To add depth to the page flip
effect we make the paper extend outside of the top and bottom edges of the book. This effect
is at its peak when a flip is close to the book’s spine.

Now that all of the logic is set up, we just have to use the values we have gathered to draw
the flip.

VIEW SOURCE
COPY CODE
1. context.save();
2. context.translate( CANVAS_PADDING + ( BOOK_WIDTH / 2 ), PAGE_Y + CANVAS_PADDING );
3. var foldGradient = context.createLinearGradient(foldX - paperShadowWidth, 0, foldX, 0);
4. foldGradient.addColorStop(0.35, '#fafafa');
5. foldGradient.addColorStop(0.73, '#eeeeee');
6. foldGradient.addColorStop(0.9, '#fafafa');
7. foldGradient.addColorStop(1.0, '#e2e2e2');
8. context.fillStyle = foldGradient;
9. context.strokeStyle = 'rgba(0,0,0,0.06)';
10. context.lineWidth = 0.5;
11. context.beginPath();
12. context.moveTo(foldX, 0);
13. context.lineTo(foldX, PAGE_HEIGHT);
14. context.quadraticCurveTo(foldX, PAGE_HEIGHT + (verticalOutdent * 2), foldX - foldWidth, PAGE_HEIGHT +
verticalOutdent);
15. context.lineTo(foldX - foldWidth, -verticalOutdent);
16. context.quadraticCurveTo(foldX, -verticalOutdent * 2, foldX, 0);
17. context.fill();
18. context.stroke();
19. context.restore();

The canvas API’s translate(x,y) method is used to offset the co-ordinate system so that we
can draw our page flip with the top of the spine acting as the 0,0 position. Note that we also
need to save() the current transformation matrix of the Canvas and restore() to the identity
matrix when we are done.

The foldGradient is what we will fill the shape of the folded paper with to give it realistic
highlights and shadows. We also add a very thin line around the paper drawing so that the
paper doesn’t disappear when put against light backgrounds.

All that remains now is drawing the shape of the folded paper using the properties we
defined above. The left and right sides of our paper is drawn as straight lines and the top and
bottom sides are curved to bring that bent feeling of a folding paper across.
That’s it! You’ve now got a fully functional page flip navigation in place. When you download
the files, you might notice that the drawing section of the code has some extra bits in the
JavaScript file: those are shadows that were added as further graphical enhancements.

Going further
This is only one example of what can be accomplished by utilising HTML5 features such as
the canvas element.

I recommend you have a look at the more refined book experience from which this technique
is an excerpt, 20 Things I Learned About Browsers and the Web: check it out at
www.20thingsilearned.com.

The soft page flip becomes even more powerful when paired with other book-like features such as an
interactive hard cover

There you will see how the page flips can be applied in a real application and how powerful it
becomes when paired with other HTML5 features.

263 16 36
Like

TAGS HTML5 JAVASCRIPT

RELATED ARTICLES Hakim El Hattab

hakim.se
Learning the basics of HTML5 canvas
Hakim is a web developer and creative
Add HTML5 video to your site
programmer that is as passionate about
HTML5 features: what you need to know working with animation and interactivity
Save money on the Future of Web Apps as technical implementation. His work
Building a parallax scrolling storytelling experience includes a large variety of
framework projects such as campaign sites, large-
scale portals, experimental
HTML5/CSS3/JS projects and desktop
applications using Adobe AIR. Follow
Hakim on Twitter.

2 COMMENTS

edzis 1
August 08, 2011 at 11:48
I see a bug - once moving the the page and cursor leaves the browser area, the curved page
disappears. From then on the current page does not bend, the next page is revealed by a moving
vertical line.
Tested on Chrome 13 and Firefox 5 on Win7-64

virginieg 2
August 23, 2011 at 22:25

Thank you for the article. Very good content. Here is a white paper on understanding the state of
HTML5 and its potential that might be of interest to other readers: http://slidesha.re/oH5MNw
Thank you
Virginie

You need to login or register to post a comment

Username Password Log in Forgot username/password?

Other .net sections Contact us About .net @netmag


RSS We love to get feedback, and we do our .net is the world’s best-selling magazine Only 125 comments so far. Come on,
very best to answer every email for web designers and developers, we want to hear your web design
Hosting directory
accurately and promptly. If you’ve got an featuring tutorials from leading agencies, song titles. There's a prize in it, too!
Premium area http://t.co/RzZvJX8
idea for an article that you’d like us to interviews with the web’s biggest names,
Advertising enquiries run, a product you’d like to pimp, or if and agenda-setting features on the hottest 2:34PM Sep 2nd via TweetDeck

Terms and Conditions you simply want to ask a question of the issues affecting the internet today.
Privacy Policy team – nothing kinky, mind – then drop Retweet Reply Follow us
Read more about us
us a line. Just click the link below. It
really is that easy. Subscribe to .net magazine
Proud to be
Contact us Current issue of .net
a member of the

Copyright 2006 - 2011 Future Publishing Limited,


30 Monmouth Street, Bath, BA1 2BW, United Kingdom
England and Wales company registration number 2008885

Das könnte Ihnen auch gefallen