Friday 23 December 2022

Web Tutorial: The Christmas Flipbook (Part 4/4)

The book works now. But it's kind of boring. We need to animate this shit!

I'm going to show you how to make the pages move as if you're physically flipping the page. First of all, we need to look at 3D transforms. Add this code to renderPage(). This adds the rotatable CSS class to the div if the placeholder is left_front or right_front. That's because only those will be "flipping".
renderPage: function(id, obj)
{
    var div = $("<div></div>");
    div.addClass(obj.class);

    if (id == "left_front" || id == "right_front")
    {
        div.addClass("rotatable");
    }


    var pagenumber = $("<div></div>");


For rotatable, left and right sides have slightly different properties. For a page on the left, you will 3D rotate it using the right edge as the point of origin, and vice versa for pages on the right side. Therefore, we use the transform-origin property.
.page
{
    width: 196px;
    height: 296px;    
    padding: 50px;
    margin-top: 2px;            
}

#left_front .rotatable
{
    -webkit-transform-origin: 100% 50%;
    transform-origin: 100% 50%;
    transform: rotateY(0deg);
}

#right_front .rotatable
{
    -webkit-transform-origin: 0% 50%;
    transform-origin: 0% 50%;
    transform: rotateY(0deg);
}


#left .page
{

    background: -moz-linear-gradient(left,  rgb(200, 200, 150) 0%, rgb(200, 200, 150) 25%, rgb(150, 150, 50) 70%, rgb(50, 50, 10) 100%);
    background: -webkit-linear-gradient(left,  rgb(200, 200, 150) 0%, rgb(200, 200, 150) 25%, rgb(150, 150, 50) 70%, rgb(50, 50, 10) 100%);
    background: linear-gradient(to right,  rgb(200, 200, 150) 0%, rgb(200, 200, 150) 25%, rgb(150, 150, 50) 70%, rgb(50, 50, 10) 100%);
    float: right;
}


Now, at flip(), add this. This makes sure that page in right_front rotates when "flipped". Also remove the call to renderView() for now. We will reintroduce it later.
flip: function(dir)
{
    if (this.currentView + dir < 0) return;
    if (this.currentView + dir > this.views.length -1) return;

    this.currentView = this.currentView + dir;

    //this.renderView();

    if (dir > 0)
    {
        $("#right_front .rotatable").attr("style", "transform: rotateY(-85deg); transition-duration: 1s");           }

}    


Test this by clicking the right button. You'll see the cover "flip" in 1 second. And you can now see the underlying page in right_back. Notice the final angle of the cover? Far from perfect. But we can fix this with some perspective!






No, I don't mean questioning the meaning of life. I mean in the CSS. The parent divs for the page, namely left_front and right_front, need to have perspective applied. I find 2000 pixels work for me, but you could try adjusting till you hit your magic number. The lower the number, though, the greater the distortion.
.page
{
    width: 196px;
    height: 296px;    
    padding: 50px;
    margin-top: 2px;            
}

#left_front, #right_front
{
    -webkit-perspective: 2000px;
    perspective: 2000px;
}


#left_front .rotatable
{
    -webkit-transform-origin: 100% 50%;
    transform-origin: 100% 50%;
    transform: rotateY(0deg);
}

#right_front .rotatable
{
    -webkit-transform-origin: 0% 50%;
    transform-origin: 0% 50%;
    transform: rotateY(0deg);
}


Try again. The final angle of the "flipped" cover looks better now. See what else is wrong? The next or previous pages are not shown, so this doesn't feel like a real book with depth.




That's where left_middle and right_middle come in. In renderView(), we populate these divs with appropriate content if the views are after the first page or before the last page.
renderView: function()
{
    $(".pageholder").html("");

    if (this.currentView > 0)
    {
        if (this.currentView > 2)
        {
            this.renderPage("left_back", this.views[1].left);
        }

        if (this.currentView > 1)
        {
            this.renderPage("left_middle", this.views[this.currentView - 1].left);
        }


        this.renderPage("left_front", this.views[this.currentView].left);
    }

    if (this.currentView < this.views.length - 1)
    {
        if (this.currentView < this.views.length - 3)
        {
            this.renderPage("right_back", this.views[this.views.length - 2].right);
        }

        if (this.currentView < this.views.length - 2)
        {
            this.renderPage("right_middle", this.views[this.currentView + 1].right);
        }


        this.renderPage("right_front", this.views[this.currentView].right);
    }
},


Nice!






OK, now for more animation. We need a setTimeout() function. Remember the duration of the animation has been set for 1 second, or 1000 milliseconds. So the timeout will be set at slightly less than that, maybe 990 milliseconds.
//this.renderView();

if (dir > 0)
{
    $("#right_front .rotatable").attr("style", "transform: rotateY(-85deg); transition-duration: 1s");    

    setTimeout(
        ()=>
        {

        },
        990
    )  
             
}


Remember we disabled that call to renderView() earlier? Well, we will move it here now, which means renderView() only gets called when the right side page is done "flipping".
setTimeout(
    ()=>
    {
        this.renderView();
    },
    990
)


And at this point, we set the left side page to rotate, but with the transition-duration property set at 0 so that it is instantaneous. We want to make it look like a continuation of that right side page "flipping" to the left, even though it's now a totally different div! If you're wondering what happened to the previously "flipped" right side page, the renderView() call took care of it by resetting the display.
setTimeout(
    ()=>
    {
        this.renderView();
        $("#left_front .rotatable").attr("style", "transform: rotateY(85deg); transition-duration: 0s");
    },
    990
)


There, see? After "flipping", the view is reset using renderView(), but with the left side page rotated.




What we want to do is complete the "flip". We use another setTimeout() call, this time just after that last statement. 10 milliseconds should do it.
setTimeout(
    ()=>
    {
        this.renderView();
        $("#left_front .rotatable").attr("style", "transform: rotateY(85deg); transition-duration: 0s");
        setTimeout(
            ()=>
            {

            },
            10
        );

    },
    990
)    


And then set transition-duration back to 1 second, and complete the rotation to 0 degrees.
setTimeout(
    ()=>
    {
        this.renderView();
        $("#left_front .rotatable").attr("style", "transform: rotateY(85deg); transition-duration: 0s");
        setTimeout(
            ()=>
            {
                $("#left_front .rotatable").attr("style", "transform: rotateY(0deg); transition-duration: 1s");  
            },
            10
        );
    },
    990
)


Go on, try flipping! To avoid repeating myself, let's do the same for the opposite direction, but reversed.
if (dir > 0)
{
    $("#right_front .rotatable").attr("style", "transform: rotateY(-85deg); transition-duration: 1s");    

    setTimeout(
        ()=>
        {
            this.renderView();
            $("#left_front .rotatable").attr("style", "transform: rotateY(85deg); transition-duration: 0s");
            setTimeout(
                ()=>
                {
                    $("#left_front .rotatable").attr("style", "transform: rotateY(0deg); transition-duration: 1s");        
                },
                10
            );
        },
        990
    )                
}

if (dir < 0)
{
    $("#left_front .rotatable").attr("style", "transform: rotateY(85deg); transition-duration: 1s");    

    setTimeout(
        ()=>
        {
            this.renderView();
            $("#right_front .rotatable").attr("style", "transform: rotateY(-85deg); transition-duration: 0s");
            setTimeout(
                ()=>
                {
                    $("#right_front .rotatable").attr("style", "transform: rotateY(0deg); transition-duration: 1s");                                },
                10
            );
        },
        990
    )                
}


At certain points, I added code to disable the buttons while the page is "flipping". Not absolutely necessary, but it prevents a case where the user keeps repeatedly clicking on the buttons before the animation has had a chance to complete and causing the animation to behave awkwardly.
if (dir > 0)
{
    $("button").prop("disabled", true);
    $("#right_front .rotatable").attr("style", "transform: rotateY(-85deg); transition-duration: 1s");    

    setTimeout(
        ()=>
        {
            this.renderView();
            $("#left_front .rotatable").attr("style", "transform: rotateY(85deg); transition-duration: 0s");
            setTimeout(
                ()=>
                {
                    $("#left_front .rotatable").attr("style", "transform: rotateY(0deg); transition-duration: 1s");    

                    setTimeout(
                        ()=>
                        {
                            $("button").prop("disabled", false);    
                        },
                        1000
                    );    

                },
                10
            );
        },
        990
    )                
}

if (dir < 0)
{
    $("button").prop("disabled", true);
    $("#left_front .rotatable").attr("style", "transform: rotateY(85deg); transition-duration: 1s");    

    setTimeout(
        ()=>
        {
            this.renderView();
            $("#right_front .rotatable").attr("style", "transform: rotateY(-85deg); transition-duration: 0s");
            setTimeout(
                ()=>
                {
                    $("#right_front .rotatable").attr("style", "transform: rotateY(0deg); transition-duration: 1s");    

                    setTimeout(
                        ()=>
                        {
                            $("button").prop("disabled", false);    
                        },
                        1000
                    );  
                                     
                },
                10
            );
        },
        990
    )                
}


See what I mean? The buttons disable while flipping!




One last thing we need to do is remove the blue outline.
.pageholder
{
    width: 100%;
    height: 100%;
    outline: 0px solid blue;
    float: left;
}


And here's your flipbook!




Merry Christmas, readers!

This was fun. A bit long, but totally worth it.

Don't flip out!
T___T

Wednesday 21 December 2022

Web Tutorial: The Christmas Flipbook (Part 3/4)

Now that we have the book object and have created the views property, let's add another property, currentView. This is an integer that tells you what view in views is active at the moment. The default is 0.
let book =
{
    views:
    [
        {
            right:
            {
                class: "cover",
                content: "<p style='text-align:center'><img src='flipbook_cover.png'/></p>"
            }
        },
        {
            left:
            {
                class: "cover",
                content: "<p style='margin-top:10%;color:rgba(10,0,0,0.5);text-align:center'><b>A flipbook project by<br /><i>TeochewThunder</i></b></p><p style='text-align:center'><img src='tt.png' /></p>"                    
            },
            right:
            {
                class: "page",
                pagenumber: 1,
                content: "<p style='text-align:justify'>Christmas is an annual festival commemorating the birth of Jesus Christ, observed primarily on December 25 as a religious and cultural celebration among billions of people around the world.</p><p style='text-align:justify'>A feast central to the Christian liturgical year, it is preceded by the season of Advent or the Nativity Fast and initiates the season of Christmastide, which historically in the West lasts twelve days and culminates on Twelfth Night. Christmas Day is a public holiday in many countries, is celebrated religiously by a majority of Christians, as well as culturally by many non-Christians, and forms an integral part of the holiday season organized around it.</p>"    
            }
        },
        {
            left:
            {
                class: "page",
                pagenumber: 2,
                content: "<img align='left' style='padding:5px' src='flipbook00.jpg'/><p style='text-align:justify'>A special Christmas family meal is traditionally an important part of the holiday's celebration, and the food that is served varies greatly from country to country. Some regions have special meals for Christmas Eve, such as Sicily, where 12 kinds of fish are served. In the United Kingdom and countries influenced by its traditions, a standard Christmas meal includes turkey, goose or other large bird, gravy, potatoes, vegetables, sometimes bread and cider.</p>"                
            },
            right:
            {
                class: "page",
                pagenumber: 3,
                content: "<p><i>A Christmas Carol</i></p><iframe width='200' height='200' src='https://www.youtube.com/embed/iN6IMZFwY50'></iframe>"    
            }
        },
        {
            left:
            {
                class: "page",
                pagenumber: 4,
                content: "<p><i>Joy to the world<br /><br />The Lord is come<br /><br />Let Earth receive her King!<br /><br />Let every heart<br /><br />Prepare him room<br /><br />And heaven and nature sing<br /><br />And heaven and nature sing<br /><br />And heaven, heaven and nature sing</i></p>"                
            },
            right:
            {
                class: "page",
                pagenumber: 5,
                content: "<div style='margin-top:10%;width:200px;height:150px;background: url(flipbook01.jpg) left top no-repeat;filter:opacity(0.5);outline:5px solid rgba(200,200,0,0.5)'></div>"    
            }
        },
        {
            left:
            {
                class: "page",
                content: "<p style='margin-top:10%;text-align:center'><i>Merry Christmas<br />and Happy New Year!</i></p>"                
            },
            right:
            {
                class: "cover",
                content: ""    
            }
        },
        {
            left:
            {
                class: "cover",
                content: ""                
            }
        }
    ],
    currentView: 0

}


After this, we define three methods - flip(), renderView() and renderPage().
currentView: 0,
flip: function()
{

},
renderView: function()
{

},
renderPage: function()
{

}


flip() has a parameter, dir. dir is an integer that defines what direction the book is being flipped - forwards or backwards.
flip: function(dir)
{

},
renderView: function()
{

},
renderPage: function()
{

}


renderPage() has two parameters. The first is id, which is the id of the placeholder to be filled with content. The second is obj, which is an object that houses the various content to populate aforementioned placeholder with.
flip: function(dir)
{

},
renderView: function()
{

},
renderPage: function(id, obj)
{

}


The simplest method of all is flip(). We aren't going to do much for now, just have it perform in a really basic way. dir has two possible values; 1 or -1. currentViews plus the value of dir will determine the resultant view. So naturally, we have guard clauses that ensure that the result can never be below 0 or above the size of views, less 1.
flip: function(dir)
{
    if (this.currentView + dir < 0) return;
    if (this.currentView + dir > this.views.length -1) return;

},


If, at this point, the method has not exited, add the value of dir to currentViews.
flip: function(dir)
{
    if (this.currentView + dir < 0) return;
    if (this.currentView + dir > this.views.length -1) return;
    
    this.currentView = this.currentView + dir;
},


Then follow up with a call to renderView() now that the value of currentView has changed.
flip: function(dir)
{
    if (this.currentView + dir < 0) return;
    if (this.currentView + dir > this.views.length -1) return;
    
    this.currentView = this.currentView + dir;
    
    this.renderView();
},


And since we're on this, make the buttons call this method. The left button calls flip() with an argument of -1, and the right button calls flip() with an argument of 1.
<div id="dashboard">
    <button onclick="book.flip(-1)">&#9664;</button>
    <button onclick="book.flip(1)">&#9654;</button>
</div>


Great! Now let's do renderView(). Begin by clearing all divs that are styled using the placeholder CSS class, of content.
renderView: function()
{
    $(".pageholder").html("");
},


Now things might get slightly crazy. There are cases where you want to populate the left placeholders, cases where you want to populate the right placeholders, and cases where you want to do both. So if currentView is greater than 0, then there is content for the left (see the views array). If currentView is less than the size of views minus 1, then there is content for the right side.
renderView: function()
{
    $(".pageholder").html("");

    if (this.currentView > 0)
    {

    }

    if (this.currentView < this.views.length - 1)
    {

    }

},


Next, we call renderPage() in the If blocks to render the pages. The arguments to pass in are, the ids - left_front for the left and right_front for the right - and the object containing the content. In the case of the latter, we want the current element of views pointed to by currentView, and then we want the left or right property depending on whether we are rendering for the left or right.
renderView: function()
{
    $(".pageholder").html("");

    if (this.currentView > 0)
    {
        this.renderPage("left_front", this.views[this.currentView].left);
    }

    if (this.currentView < this.views.length - 1)
    {
        this.renderPage("right_front", this.views[this.currentView].right);
    }
},


The next series of If blocks are nested. We check if rendering covers as a background (with pages as the foreground) are needed. They are needed for the left side if currentView is 2 or more. They are also needed for the right side if currentView is less than the second last view in views.
renderView: function()
{
    $(".pageholder").html("");

    if (this.currentView > 0)
    {
        if (this.currentView > 2)
        {
            
        }

        
        this.renderPage("left_front", this.views[this.currentView].left);
    }

    if (this.currentView < this.views.length - 1)
    {
        if (this.currentView < this.views.length - 3)
        {
            
        }

        
        this.renderPage("right_front", this.views[this.currentView].right);
    }
},


In these cases, we call renderPage(). We pass in the ids - left_back for the left and right_back for the right - and the object containing the inside covers. You will need to check your views array for this. But the logic is sound!
renderView: function()
{
    $(".pageholder").html("");

    if (this.currentView > 0)
    {
        if (this.currentView > 2)
        {
            this.renderPage("left_back", this.views[1].left);
        }
        
        this.renderPage("left_front", this.views[this.currentView].left);
    }

    if (this.currentView < this.views.length - 1)
    {
        if (this.currentView < this.views.length - 3)
        {
            this.renderPage("right_back", this.views[this.views.length - 2].right);
        }
        
        this.renderPage("right_front", this.views[this.currentView].right);
    }
},


Got all that? Cool. We'll work on renderPage() next. First, create a div. Then use the addClass() method to add the class to the div. obj should have that data, thus div will be styled using either cover or page.
renderPage: function(id, obj)
{
    var div = $("<div></div>");
    div.addClass(obj.class);
}


Declare pagenumber as another div.
renderPage: function(id, obj)
{
    var div = $("<div></div>");
    div.addClass(obj.class);
    
    var pagenumber = $("<div></div>");
}


If pagenumber is a property of obj (remember some of these objects don't have page numbers), use the addClass() method to style pagenumber using the pagenumber CSS Class, and use the html() method to add the pagenumber property into the div. Finally, append the entire thing into div.
renderPage: function(id, obj)
{
    var div = $("<div></div>");
    div.addClass(obj.class);
    
    var pagenumber = $("<div></div>");
    
    if (obj.pagenumber)
    {
        pagenumber.addClass("pagenumber");
        pagenumber.html(obj.pagenumber);
        div.append(pagenumber);
    }

}


Then declare content as another div. Insert the content property of obj using the html() method. And finally, use the append() method to slip content into div. This happens whether or not there's a page number, so we will have this outside of the If block.
renderPage: function(id, obj)
{
    var div = $("<div></div>");
    div.addClass(obj.class);
    
    var pagenumber = $("<div></div>");
    
    if (obj.pagenumber)
    {
        pagenumber.addClass("pagenumber");
        pagenumber.html(obj.pagenumber);
        div.append(pagenumber);
    }
    
    var content = $("<div></div>");
    content.html(obj.content);
    div.append(content);

}


And then use append() to populate the contents of the placeholder with id as its id, with div.
renderPage: function(id, obj)
{
    var div = $("<div></div>");
    div.addClass(obj.class);

    if (id == "left_front" || id == "right_front")
    {
        div.addClass("rotatable");
    }

    var pagenumber = $("<div></div>");

    if (obj.pagenumber)
    {
        pagenumber.addClass("pagenumber");
        pagenumber.html(obj.pagenumber);
        div.append(pagenumber);
    }

    var content = $("<div></div>");
    content.html(obj.content);
    div.append(content);

    $("#" + id).append(div);
}


At this point, you should be running renderView() on page load.
        var content = $("<div></div>");
        content.html(obj.content);
        div.append(content);

        $("#" + id).append(div);
    }
}

$(document).ready
(
    function() { book.renderView(); }
);


See what happens? On page load, renderView() is called and currentView is 0. So the left side of the "book" is not rendered, only the right side. Because the first element of views only has the right property. The CSS class is cover and this is the content!




Click on the left and right buttons. Things should change!



 
Here.


And again.







And right at the end...




...you may notice that clicking the buttons beyond this point does nothing, because we added those guard clauses earlier. Same if you're at the front cover and try to go "back". Nope, not happening.

Also, you may have noticed that in between pages, there appears some kind of gap at the left side. That's because the "page" is slightly smaller than the "cover". Here's how we fix that...
#left .page
{

    background: -moz-linear-gradient(left,  rgb(200, 200, 150) 0%, rgb(200, 200, 150) 25%, rgb(150, 150, 50) 70%, rgb(50, 50, 10) 100%);
    background: -webkit-linear-gradient(left,  rgb(200, 200, 150) 0%, rgb(200, 200, 150) 25%, rgb(150, 150, 50) 70%, rgb(50, 50, 10) 100%);
    background: linear-gradient(to right,  rgb(200, 200, 150) 0%, rgb(200, 200, 150) 25%, rgb(150, 150, 50) 70%, rgb(50, 50, 10) 100%);
    float: right;
}


There, no more gap!




What happened to left_middle and right_middle?

You're probably wondering why we bothered with those, right? Never fear. That's in the next part.

Next

Some cool CSS animation magic!

Sunday 18 December 2022

Web Tutorial: The Christmas Flipbook (Part 2/4)

All right! Time to fill up the pages with some content. The idea here is that basic HTML should be able to be embedded into those pages.

Let's remove the divs in the left_middle and right_middle divs for the time being, so we can work on the cover.
<div id="container">
    <div id="left" class="section">
        <div id="left_back" class="pageholder">
            <div class="cover">

            </div>
        </div>

        <div id="left_middle" class="pageholder">
            <!--                     
            <div class="page">

            </div>
            -->
        </div>

        <div id="left_front" class="pageholder">

        </div>
    </div>

    <div id="right" class="section">
        <div id="right_back" class="pageholder">
            <div class="cover">

            </div>
        </div>

        <div id="right_middle" class="pageholder">
            <!--                     
            <div class="page">

            </div>
            -->
        </div>

        <div id="right_front" class="pageholder">

        </div>
    </div>
</div>


In the cover, let's add some HTML. The image used is a small PNG logo. CSS is embedded in the HTML itself.

tt.png

<div id="left_back" class="pageholder">
    <div class="cover">
        <p style="margin-top:10%;color:rgba(10,0,0,0.5);text-align:center"><b>A flipbook project by<br /><i>TeochewThunder</i></b></p><p style="text-align:center"><img src="tt.png" /></p>
    </div>
</div>


There it is.




On the right side, let's add the image below.

flipbook_cover.png



<div id="right_back" class="pageholder">
    <div class="cover">
        <p style="text-align:center"><img src="flipbook_cover.png"/></p>
    </div>
</div>


This looks good.




Now add the pages back. We will work on them next. Let's start with a page number. For this, we will use a div with the pagenumber CSS class.
<div id="left" class="section">
    <div id="left_back" class="pageholder">
        <div class="cover">
            <p style="margin-top:10%;color:rgba(10,0,0,0.5);text-align:center"><b>A flipbook project by<br /><i>TeochewThunder</i></b></p><p style="text-align:center"><img src="tt.png" /></p>
        </div>
    </div>

    <div id="left_middle" class="pageholder">                                         
        <div class="page">
            <div class="pagenumber">1</div>
        </div>     
    </div>

    <div id="left_front" class="pageholder">

    </div>
</div>

<div id="right" class="section">
    <div id="right_back" class="pageholder">
        <div class="cover">
            <p style="text-align:center"><img src="flipbook_cover.png"/></p>
        </div>
    </div>

    <div id="right_middle" class="pageholder">                                         
        <div class="page">

        </div>
    </div>

    <div id="right_front" class="pageholder">

    </div>
</div>


Here's the styling. I have specified font size and aligned text center, and given it a translucent grey border at the bottom.
#right .cover
{
    background: -moz-linear-gradient(left,  rgb(30, 0, 0) 0%, rgb(50, 0, 0) 20%, rgb(150, 0, 0) 100%);
    background: -webkit-linear-gradient(left,  rgb(30, 0, 0) 0%, rgb(50, 0, 0) 20%, rgb(150, 0, 0) 100%);
    background: linear-gradient(to right,  rgb(30, 0, 0) 0%, rgb(50, 0, 0) 20%, rgb(150, 0, 0) 100%);
    box-shadow: 0 3px 0 rgb(100, 0, 0) inset, -3px 0 0 rgb(100, 0, 0) inset, 0 -3px 0 rgb(100, 0, 0) inset;
}

.pagenumber
{
    font-size: 0.8em;
    font-weight: bold;
    text-align: center;
    height: 19px;
    border-bottom: 1px solid rgba(100, 100, 100, 0.5);
}


Coming along nicely.




Now for content!

This is a typical paragraph. The text is taken from Wikipedia.
<div id="left_middle" class="pageholder">                                         
    <div class="page">
        <div class="pagenumber">2</div>
        <div>
            <p style="text-align:justify">Christmas is an annual festival commemorating the birth of Jesus Christ, observed primarily on December 25 as a religious and cultural celebration among billions of people around the world.</p><p style='text-align:justify'>A feast central to the Christian liturgical year, it is preceded by the season of Advent or the Nativity Fast and initiates the season of Christmastide, which historically in the West lasts twelve days and culminates on Twelfth Night. Christmas Day is a public holiday in many countries, is celebrated religiously by a majority of Christians, as well as culturally by many non-Christians, and forms an integral part of the holiday season organized around it.</p>
        </div>
    </div>     
</div>


See how this turned out? Note that this should be the most amount of text you could squeeze into one page without adjusting font sizes, line heights, padding and the like.




For the next bit, I will use the image below.

flipbook00.jpg


This is a typical paragraph with image. Again, text is from Wikipedia.
<div id="right_middle" class="pageholder">                                         
    <div class="page">
        <div class="pagenumber">1</div>
        <div>
            <img align="left" style="padding:5px" src="flipbook00.jpg"/><p style="text-align:justify">A special Christmas family meal is traditionally an important part of the holiday's celebration, and the food that is served varies greatly from country to country. Some regions have special meals for Christmas Eve, such as Sicily, where 12 kinds of fish are served. In the United Kingdom and countries influenced by its traditions, a standard Christmas meal includes turkey, goose or other large bird, gravy, potatoes, vegetables, sometimes bread and cider.</p>
        </div>
    </div>
</div>


Could be better, but you can always adjust the CSS.




Now add divs into the left_front and right_front divs. Style them using page, and add a page number as we did before, for each one.
<div id="container">
    <div id="left" class="section">
        <div id="left_back" class="pageholder">
            <div class="cover">
                <p style="margin-top:10%;color:rgba(10,0,0,0.5);text-align:center"><b>A flipbook project by<br /><i>TeochewThunder</i></b></p><p style="text-align:center"><img src="tt.png" /></p>
            </div>
        </div>

        <div id="left_middle" class="pageholder">                                         
            <div class="page">
                <div class="pagenumber">1</div>
                <div>
                    <p style="text-align:justify">Christmas is an annual festival commemorating the birth of Jesus Christ, observed primarily on December 25 as a religious and cultural celebration among billions of people around the world.</p><p style='text-align:justify'>A feast central to the Christian liturgical year, it is preceded by the season of Advent or the Nativity Fast and initiates the season of Christmastide, which historically in the West lasts twelve days and culminates on Twelfth Night. Christmas Day is a public holiday in many countries, is celebrated religiously by a majority of Christians, as well as culturally by many non-Christians, and forms an integral part of the holiday season organized around it.</p>
                </div>
            </div>     
        </div>

        <div id="left_front" class="pageholder">
            <div class="page">
                <div class="pagenumber">3</div>
                <div>

                </div>
            </div>     
        </div>

    </div>

    <div id="right" class="section">
        <div id="right_back" class="pageholder">
            <div class="cover">
                <p style="text-align:center"><img src="flipbook_cover.png"/></p>
            </div>
        </div>

        <div id="right_middle" class="pageholder">                                         
            <div class="page">
                <div class="pagenumber">2</div>
                <div>
                    <img align="left" style="padding:5px" src="flipbook00.jpg"/><p style="text-align:justify">A special Christmas family meal is traditionally an important part of the holiday's celebration, and the food that is served varies greatly from country to country. Some regions have special meals for Christmas Eve, such as Sicily, where 12 kinds of fish are served. In the United Kingdom and countries influenced by its traditions, a standard Christmas meal includes turkey, goose or other large bird, gravy, potatoes, vegetables, sometimes bread and cider.</p>
                </div>
            </div>
        </div>

        <div id="right_front" class="pageholder">
            <div class="page">
                <div class="pagenumber">4</div>
                <div>

                </div>
            </div>  
   
        </div>
    </div>
</div>


Let's try embedding a video.
<div id="left_front" class="pageholder">
    <div class="page">
        <div class="pagenumber">3</div>
        <div>
            <p><i>A Christmas Carol</i></p><iframe width="200" height="200" src="https://www.youtube.com/embed/iN6IMZFwY50"></iframe></p>
        </div>
    </div>     
</div>


Wo0t!




Now let's try a heavily customized div. We will use this image.

flipbook1,jpg


<div id="right_front" class="pageholder">
    <div class="page">
        <div class="pagenumber">4</div>
        <div>
            <div style="margin-top:10%;width:200px;height:150px;background: url(flipbook01.jpg) left top no-repeat;filter:opacity(0.5);outline:5px solid rgba(200,200,0,0.5)"></div>
        </div>
    </div>     
</div>


Yep, it works.




And now, remove everything. That was hard-coding we did, and we're not going to do that. We will instead write code to embed that HTML.
<div id="left" class="section">
    <div id="left_back" class="pageholder">
        <!-- <div class="cover">
            <p style="margin-top:10%;color:rgba(10,0,0,0.5);text-align:center"><b>A flipbook project by<br /><i>TeochewThunder</i></b></p><p style="text-align:center"><img src="tt.png" /></p>
        </div> -->
    </div>

    <div id="left_middle" class="pageholder">                                         
        <!-- <div class="page">
            <div class="pagenumber">1</div>
            <div>
                <p style="text-align:justify">Christmas is an annual festival commemorating the birth of Jesus Christ, observed primarily on December 25 as a religious and cultural celebration among billions of people around the world.</p><p style='text-align:justify'>A feast central to the Christian liturgical year, it is preceded by the season of Advent or the Nativity Fast and initiates the season of Christmastide, which historically in the West lasts twelve days and culminates on Twelfth Night. Christmas Day is a public holiday in many countries, is celebrated religiously by a majority of Christians, as well as culturally by many non-Christians, and forms an integral part of the holiday season organized around it.</p>
            </div>
        </div>  -->    
    </div>

    <div id="left_front" class="pageholder">
        <!-- <div class="page">
            <div class="pagenumber">3</div>
            <div>
                <p><i>A Christmas Carol</i></p><iframe width="200" height="200" src="https://www.youtube.com/embed/iN6IMZFwY50"></iframe>
            </div>
        </div>      -->
    </div>
</div>

<div id="right" class="section">
    <div id="right_back" class="pageholder">
        <!-- <div class="cover">
            <p style="text-align:center"><img src="flipbook_cover.png"/></p>
        </div> -->
    </div>

    <div id="right_middle" class="pageholder">                                         
        <!-- <div class="page">
            <div class="pagenumber">2</div>
            <div>
                <img align="left" style="padding:5px" src="flipbook00.jpg"/><p style="text-align:justify">A special Christmas family meal is traditionally an important part of the holiday's celebration, and the food that is served varies greatly from country to country. Some regions have special meals for Christmas Eve, such as Sicily, where 12 kinds of fish are served. In the United Kingdom and countries influenced by its traditions, a standard Christmas meal includes turkey, goose or other large bird, gravy, potatoes, vegetables, sometimes bread and cider.</p>
            </div>
        </div>  -->
    </div>

    <div id="right_front" class="pageholder">
        <!-- <div class="page">
            <div class="pagenumber">4</div>
            <div>
                <div style="margin-top:10%;width:200px;height:150px;background: url(flipbook01.jpg) left top no-repeat;filter:opacity(0.5);outline:5px solid rgba(200,200,0,0.5)"></div>
            </div>
        </div>  -->    
    </div>
</div>


In the script, create the book object. It will have the views property.
<script>
    let book =
    {
        views:
    }

</script>


views is an array of objects. Place 6 objects in there. You will see why soon.
<script>
    let book =
    {
        views:
        [
            {
            
            },
            {
            
            },
            {
            
            },
            {
            
            },
            {
            
            },
            {
            
            }
        ]

    }
</script>


Each element in views is actually a specification of what the book will look like as you progress. The first element will have a property called right, which is another object. Within it is a class property, and that is a string, "cover". For the content property, let's place the HTML we created that had the Christmas tree icon. Note that the double quotes in the HTML are now single quotes, so as not to confuse the engine that parses this object.
views:
[
    {
        right:
        {
            class: "cover",
            content: "<p style='text-align:center'><img src='flipbook_cover.png'/></p>"
        }

    },
    {

    },
    {

    },
    {

    },
    {

    },
    {

    }
]


The second view has both left and right properties. Because after turning the cover, you will see both a left side and a right side, yes?
views:
[
    {
        right:
        {
            class: "cover",
            content: "<p style='text-align:center'><img src='flipbook_cover.png'/></p>"
        }
    },
    {
        left:
        {
                
        },
        right:
        {

        }

    },
    {

    },
    {

    },
    {

    },
    {

    }
]


So for this left property, we do as we did for the right property of the first element. For the content property, I am going with the small logo and text HTML.
views:
[
    {
        right:
        {
            class: "cover",
            content: "<p style='text-align:center'><img src='flipbook_cover.png'/></p>"
        }
    },
    {
        left:
        {
            class: "cover",
            content: "<p style='margin-top:10%;color:rgba(10,0,0,0.5);text-align:center'><b>A flipbook project by<br /><i>TeochewThunder</i></b></p><p style='text-align:center'><img src='tt.png' /></p>"         
           
        },
        right:
        {

        }
    },
    {

    },
    {

    },
    {

    },
    {

    }
]


For the right property, I also have a pagenumber property, in addition to the HTML content.
views:
[
    {
        right:
        {
            class: "cover",
            content: "<p style='text-align:center'><img src='flipbook_cover.png'/></p>"
        }
    },
    {
        left:
        {
            class: "cover",
            content: "<p style='margin-top:10%;color:rgba(10,0,0,0.5);text-align:center'><b>A flipbook project by<br /><i>TeochewThunder</i></b></p><p style='text-align:center'><img src='tt.png' /></p>"                    
        },
        right:
        {
            class: "page",
            pagenumber: 1,
            content: "<p style='text-align:justify'>Christmas is an annual festival commemorating the birth of Jesus Christ, observed primarily on December 25 as a religious and cultural celebration among billions of people around the world.</p><p style='text-align:justify'>A feast central to the Christian liturgical year, it is preceded by the season of Advent or the Nativity Fast and initiates the season of Christmastide, which historically in the West lasts twelve days and culminates on Twelfth Night. Christmas Day is a public holiday in many countries, is celebrated religiously by a majority of Christians, as well as culturally by many non-Christians, and forms an integral part of the holiday season organized around it.</p>"    

        }
    },
    {

    },
    {

    },
    {

    },
    {

    }
]


Repeat for the rest!
views:
[
    {
        right:
        {
            class: "cover",
            content: "<p style='text-align:center'><img src='flipbook_cover.png'/></p>"
        }
    },
    {
        left:
        {
            class: "cover",
            content: "<p style='margin-top:10%;color:rgba(10,0,0,0.5);text-align:center'><b>A flipbook project by<br /><i>TeochewThunder</i></b></p><p style='text-align:center'><img src='tt.png' /></p>"                    
        },
        right:
        {
            class: "page",
            pagenumber: 1,
            content: "<p style='text-align:justify'>Christmas is an annual festival commemorating the birth of Jesus Christ, observed primarily on December 25 as a religious and cultural celebration among billions of people around the world.</p><p style='text-align:justify'>A feast central to the Christian liturgical year, it is preceded by the season of Advent or the Nativity Fast and initiates the season of Christmastide, which historically in the West lasts twelve days and culminates on Twelfth Night. Christmas Day is a public holiday in many countries, is celebrated religiously by a majority of Christians, as well as culturally by many non-Christians, and forms an integral part of the holiday season organized around it.</p>"    
        }
    },
    {
        left:
        {
            class: "page",
            pagenumber: 2,
            content: "<img align='left' style='padding:5px' src='flipbook00.jpg'/><p style='text-align:justify'>A special Christmas family meal is traditionally an important part of the holiday's celebration, and the food that is served varies greatly from country to country. Some regions have special meals for Christmas Eve, such as Sicily, where 12 kinds of fish are served. In the United Kingdom and countries influenced by its traditions, a standard Christmas meal includes turkey, goose or other large bird, gravy, potatoes, vegetables, sometimes bread and cider.</p>"                
        },
        right:
        {
            class: "page",
            pagenumber: 3,
            content: "<p><i>A Christmas Carol</i></p><iframe width='200' height='200' src='https://www.youtube.com/embed/iN6IMZFwY50'></iframe>"    
        }

    },
    {
        left:
        {
            class: "page",
            pagenumber: 4,
            content: "<p><i>Joy to the world<br /><br />The Lord is come<br /><br />Let Earth receive her King!<br /><br />Let every heart<br /><br />Prepare him room<br /><br />And heaven and nature sing<br /><br />And heaven and nature sing<br /><br />And heaven, heaven and nature sing</i></p>"                
        },
        right:
        {
            class: "page",
            pagenumber: 5,
            content: "<div style='margin-top:10%;width:200px;height:150px;background: url(flipbook01.jpg) left top no-repeat;filter:opacity(0.5);outline:5px solid rgba(200,200,0,0.5)'></div>"    
        }

    },
    {
        left:
        {
            class: "page",
            content: "<p style='margin-top:10%;text-align:center'><i>Merry Christmas<br />and Happy New Year!</i></p>"                
        },
        right:
        {
            class: "cover",
            content: ""    
        }

    },
    {

    }
]


The final element, of course, mirrors the first element, in the sense that now this time, it is the right property that is missing.
views:
[
    {
        right:
        {
            class: "cover",
            content: "<p style='text-align:center'><img src='flipbook_cover.png'/></p>"
        }
    },
    {
        left:
        {
            class: "cover",
            content: "<p style='margin-top:10%;color:rgba(10,0,0,0.5);text-align:center'><b>A flipbook project by<br /><i>TeochewThunder</i></b></p><p style='text-align:center'><img src='tt.png' /></p>"                    
        },
        right:
        {
            class: "page",
            pagenumber: 1,
            content: "<p style='text-align:justify'>Christmas is an annual festival commemorating the birth of Jesus Christ, observed primarily on December 25 as a religious and cultural celebration among billions of people around the world.</p><p style='text-align:justify'>A feast central to the Christian liturgical year, it is preceded by the season of Advent or the Nativity Fast and initiates the season of Christmastide, which historically in the West lasts twelve days and culminates on Twelfth Night. Christmas Day is a public holiday in many countries, is celebrated religiously by a majority of Christians, as well as culturally by many non-Christians, and forms an integral part of the holiday season organized around it.</p>"    
        }
    },
    {
        left:
        {
            class: "page",
            pagenumber: 2,
            content: "<img align='left' style='padding:5px' src='flipbook00.jpg'/><p style='text-align:justify'>A special Christmas family meal is traditionally an important part of the holiday's celebration, and the food that is served varies greatly from country to country. Some regions have special meals for Christmas Eve, such as Sicily, where 12 kinds of fish are served. In the United Kingdom and countries influenced by its traditions, a standard Christmas meal includes turkey, goose or other large bird, gravy, potatoes, vegetables, sometimes bread and cider.</p>"                
        },
        right:
        {
            class: "page",
            pagenumber: 3,
            content: "<p><i>A Christmas Carol</i></p><iframe width='200' height='200' src='https://www.youtube.com/embed/iN6IMZFwY50'></iframe>"    
        }
    },
    {
        left:
        {
            class: "page",
            pagenumber: 4,
            content: "<p><i>Joy to the world<br /><br />The Lord is come<br /><br />Let Earth receive her King!<br /><br />Let every heart<br /><br />Prepare him room<br /><br />And heaven and nature sing<br /><br />And heaven and nature sing<br /><br />And heaven, heaven and nature sing</i></p>"                
        },
        right:
        {
            class: "page",
            pagenumber: 5,
            content: "<div style='margin-top:10%;width:200px;height:150px;background: url(flipbook01.jpg) left top no-repeat;filter:opacity(0.5);outline:5px solid rgba(200,200,0,0.5)'></div>"    
        }
    },
    {
        left:
        {
            class: "page",
            content: "<p style='margin-top:10%;text-align:center'><i>Merry Christmas<br />and Happy New Year!</i></p>"                
        },
        right:
        {
            class: "cover",
            content: ""    
        }
    },
    {
        left:
        {
            class: "cover",
            content: ""                
        }

    }
]


What are we doing here?

Oh, are you lost? No worries! This is preparation for what we're about to do next - create code to display content according to what page you're on.

Next

We make the buttons flip the pages.