Demo 
Download

The page flip effect used to be the quintessential Flash animation. On the web, it has powered everything from magazines to presentations, with its popularity declining over time, only to be reinvented on mobile devices as ebook reading apps.
In this tutorial we are going to use PHP and the turn.js plugin, an implementation of the page flip effect with pure CSS3 and jQuery, to build a pretty magazine. We will fetch the most popular images from Instagram every hour, and use them as pages.

HTML

First we need to lay down the foundations of today’s example. We will use a single page design, which combines HTML5 markup and PHP in the same file for greater simplicity. You can see the resulting layout below:

index.php

01<!DOCTYPE html>
02<html>
03    <head>
04        <meta charset="utf-8" />
05        <title>Making an Instagram Magazine | Tutorialzine Demo</title>
06 
07        <!-- Our Stylesheet -->
08        <link rel="stylesheet" href="assets/css/styles.css" />
09 
10        <!--[if lt IE 9]>
11          <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
12        <![endif]-->
13    </head>
14 
15    <body>
16 
17        <div id="magazine" class="centerStart">
18 
19        <!-- PHP will go here -->
20 
21        </div>
22 
23        <!-- JavaScript includes - jQuery, turn.js and our own script.js -->
24        <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
25        <script src="assets/js/turn.js"></script>
26        <script src="assets/js/script.js"></script>
27 
28    </body>
29</html>
We include styles.css in the head, and our JavaScript files at the bottom. The latter are the jQuery library, the turn.js plugin and script.js, where we will be initializing the plugin and listening for keyboard events. The PHP code that we will be writing in the next section will go in the #magazine div. PHP will have the job of generating the pages of our magazine, which will be used by turn.js.
As an example, here is the markup of the first three pages of the magazine:

Generated code

01<div id="page1" class="page">
02    <div class="img1">
03 
04        <!-- The pageNum span can be either on the left,
05                or the right if the page is odd/even. -->
06 
07        <span class="pageNum right">1 // 32</span>
08        <img src="assets/img/cover.jpg" alt="Cover" />
09    </div>
10</div>
11 
12<div id="page2" class="page">
13    <div class="img2">
14        <span class="pageNum left">2 // 32</span>
15        <img src="http://distilleryimage7.instagram.com/..." alt="Little tulips" />
16    </div>
17</div>
18 
19<div id="page3" class="page">
20    <div class="img3">
21        <span class="pageNum right">3 // 32</span>
22        <img src="http://distilleryimage2.instagram.com/..." alt="My style" />
23    </div>
24</div>
The divs you see above are direct descendants of the #magazine div. This is the only requirement imposed by turn.js. You don’t need to have any special classes or data attributes for the elements to be interpreted as pages. With this we are ready to move on with the PHP code!
Page Flip Magazine with CSS3 and jQuery
Page Flip Magazine with CSS3 and jQuery

PHP

PHP will have the task of communicating with Instagram’s API, caching the results, and generating the markup you saw above.
The first step is to register at the Instagram developer website. After you obtain your client_id key, place it in index.php as the value of $instagramClientID. We won’t be needing any of the advanced functionality of the API, we will only be requesting the most popular images. This frees us from having to implement OAuth authentication, which would make today’s example significantly more complex.
Note that if you want to modify the magazine and show photos other than the most popular, say your latest images, you will need to implement OAuth and authenticate your app to have access to your photos. Consult the docs for further information.
Here is an example JSON response of the currently popular images on Instagram. I have omitted some of the attributes to make the code easier to read.

Popular images JSON response

01{    "meta": {
02        "code": 200
03    },
04    "data": [{
05        "tags": ["beautiful", "sky"],
06        "location": "null",
07        "comments": {
08            "count": 31,
09            "data": [...]
10        },
11        "filter": "Normal",
12        "created_time": "1331910134",
13        "link": "http:\/\/instagr.am\/p\/IPNNknqs84\/",
14        "likes": {
15            "count": 391,
16            "data": [..]
17        },
18        "images": {
19            "low_resolution": {
20                "url": "http:\/\/distilleryimage8.instagram.com\/03c80dd86f7911e1a87612313804ec91_6.jpg",
21                "width": 306,
22                "height": 306
23            },
24            "thumbnail": {
25                "url": "http:\/\/distilleryimage8.instagram.com\/03c80dd86f7911e1a87612313804ec91_5.jpg",
26                "width": 150,
27                "height": 150
28            },
29            "standard_resolution": {
30                "url": "http:\/\/distilleryimage8.instagram.com\/03c80dd86f7911e1a87612313804ec91_7.jpg",
31                "width": 612,
32                "height": 612
33            }
34        },
35        "caption": {
36            "created_time": "1331910148",
37            "text": "Goodnight.\ue056",
38            "from": {
39                "username": "jent99",
40                "profile_picture": "http:\/\/images.instagram.com\/profiles\/profile_6227738_75sq_1319878922.jpg",
41                "id": "6227738",
42                "full_name": "jent99"
43            },
44            "id": "148395540733414783"
45        },
46        "type": "image",
47        "id": "148395420004568888_6227738",
48        "user": {
49            "username": "jent99",
50            "website": "",
51            "bio": "Mostly nature pics.\ue32b\ue32b\ue32b Hope you like them.\ue056\ue32a     \ue334gi\ue334                    ",
52            "profile_picture": "http:\/\/images.instagram.com\/profiles\/profile_6227738_75sq_1319878922.jpg",
53            "full_name": "jent99",
54            "id": "6227738"
55        }
56    }, {
57        /* More photos here*/
58    }]
59}
The API is limited to returning only 32 pics, but this is plenty for our example. You can see that each photo has three image sizes, but we will only be needing the standard one. There is also various other information that you can use like caption, dimensions, tags, comments, and more.
PHP will cache the results of this API call so we hit Instagram’s servers only once per hour. This will make our application more responsive and limit the number of calls.

index.php

01// You can obtain this client ID from the Instagram API page
02$instagramClientID = '-- place your client id key here --';
03 
05$cache = 'cache.txt';
06 
07if(file_exists($cache) && filemtime($cache) > time() - 60*60){
08    // If a cache file exists, and it is
09    // fresher than 1 hour, use it
10    $images = unserialize(file_get_contents($cache));
11}
12else{
13    // Make an API request and create the cache file
14 
15    // Fetch the 32 most popular images on Instagram
16    $response = file_get_contents($api);
17 
18    $images = array();
19 
20    // Decode the response and build an array
21    foreach(json_decode($response)->data as $item){
22 
23        $title = '';
24 
25        if($item->caption){
26            $title = mb_substr($item->caption->text,0,70,"utf8");
27        }
28 
29        $src = $item->images->standard_resolution->url;
30 
31        $images[] = array(
32            "title" => htmlspecialchars($title),
33            "src" => htmlspecialchars($src)
34        );
35    }
36 
37    // Remove the last item, so we still have
38    // 32 items when when the cover is added
39    array_pop($images);
40 
41    // Push the cover in the beginning of the array
42    array_unshift($images,array("title"=>"Cover", "src"=>"assets/img/cover.jpg"));
43 
44    // Update the cache file
45    file_put_contents($cache,serialize($images));
46}
47 
48# Generate the markup
49$totalPages = count($images);
50foreach($images as $i=>$image){
51 
52    ?>
53 
54    <div id="page<?php echo $i+1?>" class="page">
55        <div class="img<?php echo $i+1?>">
56            <span class="pageNum <?php echo ($i+1)%2? 'right' : 'left'?>"><?php echo $i+1?> // <?php echo $totalPages?></span>
57            <img src="<?php echo $image['src']?>" alt="<?php echo $image['title']?>" />
58        </div>
59    </div>
60 
61    <?php
62 
63}
Caching is straightforward: we are using a temporary file – cache.txt – to store a serialized representation of the image array. If the cache file is non-existing or is older than an hour, we issue a new API request.
Notice the calls to array_pop and array_unshift. These are necessary as to make room for the custom cover image that is stored in assets/img. The magazine works best if we have an even number of pages, otherwise we would be unable to turn the last one, which would feel unnatural.
We are now ready for the plugin!

jQuery

Using turn.js is really simple. As we already have the markup of the magazine, we just need to call the turn() method. While we are at it, we will also listen for presses on the arrow keys, which will trigger page transitions.

assets/js/script.js

01$(function(){
02 
03    var mag = $('#magazine');
04 
05    // initiazlie turn.js on the #magazine div
06    mag.turn();
07 
08    // turn.js defines its own events. We are listening
09    // for the turned event so we can center the magazine
10    mag.bind('turned', function(e, page, pageObj) {
11 
12        if(page == 1 && $(this).data('done')){
13            mag.addClass('centerStart').removeClass('centerEnd');
14        }
15        else if (page == 32 && $(this).data('done')){
16            mag.addClass('centerEnd').removeClass('centerStart');
17        }
18        else {
19            mag.removeClass('centerStart centerEnd');
20        }
21 
22    });
23 
24    setTimeout(function(){
25        // Leave some time for the plugin to
26        // initialize, then show the magazine
27        mag.fadeTo(500,1);
28    },1000);
29 
30    $(window).bind('keydown', function(e){
31 
32        // listen for arrow keys
33 
34        if (e.keyCode == 37){
35            mag.turn('previous');
36        }
37        else if (e.keyCode==39){
38            mag.turn('next');
39        }
40 
41    });
42 
43});
You can read more about what events the plugin emits and how to use them, in the turn.js reference.
Now let’s make it pretty!

CSS

We need to set explicit dimensions of the magazine and style the pages and page numbers. turn.js will handle the rest.

assets/css/styles.css

01#magazine{
02    width:1040px;
03    height:520px;
04    margin:0 auto;
05    position:relative;
06    left:0;
07 
08    opacity:0;
09 
10    -moz-transition:0.3s left;
11    -webkit-transition:0.3s left;
12    transition:0.3s left;
13}
14 
15#magazine .page{
16    width:520px;
17    height:520px;
18    background-color:#ccc;
19    overflow:hidden;
20}
21 
22/* Center the magazine when the cover is shown */
23#magazine.centerStart{
24    left:-260px;
25}
26 
27/* Center the magazine when the last page is shown */
28#magazine.centerEnd{
29    left:260px;
30}
31 
32.page img{
33    height:520px;
34    width:520px;
35    display:block;
36}
37 
38/* Show a dark shadow when the cover is shown */
39.centerStart .turn-page-wrapper:first-child{
40    box-shadow:0 0 10px #040404;
41}
42 
43/* Page Numbers */
44 
45span.pageNum{
46    background-color: rgba(0, 0, 0, 0.3);
47    bottom: 25px;
48    box-shadow: 0 0 3px rgba(0, 0, 0, 0.25);
49    color: #FFFFFF;
50    font-size: 11px;
51    height: 24px;
52    line-height: 22px;
53    opacity: 0.9;
54    position: absolute;
55    text-align: center;
56    width: 55px;
57}
58 
59span.pageNum.left{
60    left:0;
61    right:auto;
62}
63 
64span.pageNum.right{
65    left:auto;
66    right:0;
67}
68 
69/* Hide the page number on the cover */
70#page1 .pageNum{
71    display:none;
72}
With this our magazine is complete!

We’re done!

This example works in all recent browsers – Firefox, Chrome, Safari, Opera and even IE. It is even usable on iOS and Android. You can use this effect as part of photo galleries, templates or even real magazines. However you will have to create a fallback version for older browsers, which don’t have what it takes to display it properly.

1 nhận xét:

  1. Great jod!
    I have no idea about creating page flipping magazine with codes and computer language, so I often turn to some third party software like flip page software for solution.
    Helpful for me, so I can try to follow your codes to create...really hard for me.

    Trả lờiXóa

 
Top