Sunday 16 August 2020

Web Tutorial: The Fade Carousel

Welcome to another carousel-based web tutorial.

This one's gonna be short, because we will be, in classic lazy-bastard programmer fashion, leveraging upon the code from the last carousel-based web tutorial. This time, instead of making the images slide in and out of view, we'll make them fade instead.

So let's go ahead and just copy all the code over. And then change all instances of "slide" to "fade". Which means that instead of calling them "slides", we will now call them "fades". Which is kind of lame, but it works for keeping things consistent, so there you go.
<!DOCTYPE html>
<html>
    <head>
        <title>Fade Carousel</title>

        <style>
            div {outline: 0px solid #FF0000;}
           
            body
            {
                font-size: 12px;
                font-family: verdana;
            }

            #carouselContainer
            {
                width: 800px;
                height: 600px;
                margin: 0 auto 0 auto;
            }

            .margin
            {
                width: 10%;
                height: 100px;
                float: left;
                text-align: center;
                font-size: 5em;
            }

            .margin input[type="button"]
            {
                color: rgba(0, 0, 0, 1);
                cursor: pointer;
                margin-top: 250px;
                width: 50px;
                height: 50px;
                border-radius: 50%;
                border: 0px solid red;
                background-color: rgba(255, 200, 0, 1);
                color: rgba(255, 255, 255, 1);
            }

            .margin input[type="button"]:hover
            {
                background-color: rgba(255, 200, 0, 0.5);
            }

            #viewport
            {
                width: 80%;
                height: 100%;
                float: left;
                overflow: hidden;
                border-radius: 15px;
            }

            #contentContainer
            {
                width: 200%;
                height: 100%;
                background-color: #004400;
            }

            .content
            {
                width: 50%;
                height: 100%;
                float: left;
                background-color: #000044;
                background-size: cover;
                background-position: 50% 50%;
                background-repeat: no-repeat;
                padding-top: 1em;               
            }

            .content div
            {
                padding: 1em;
                background-color: rgba(255, 255, 255, 0.5);
                color: rgba(0, 0, 0, 1);
                font-weight: bold;
                width: 80%;
                border-radius: 5px;
                margin: 0 auto 0 auto;
            }
        </style>

        <script>
            var carousel =
            {
                fades:
                [
                    {
                        bg: "00.jpg",
                        content: "<div><h2>Phasellus ullamcorper</h2><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent fringilla molestie pellentesque. Aliquam auctor scelerisque mattis. Donec maximus ipsum non eros gravida suscipit. Sed vulputate massa orci, non placerat lectus suscipit mollis. Fusce faucibus lorem eu lectus mattis, et dictum urna semper. Maecenas massa magna, commodo at pulvinar ac, lacinia nec augue. Nullam pretium consectetur ultricies. In a mattis justo. Suspendisse potenti. Vivamus scelerisque, urna imperdiet faucibus facilisis, orci elit dictum ex, blandit rutrum metus diam eget mi. Phasellus ullamcorper eu purus eu venenatis. Nullam vestibulum dolor vel felis facilisis, ac rutrum tellus rutrum. Sed vehicula elementum erat, eget mattis tortor rhoncus a. Phasellus ut nisl volutpat, dictum lectus ut, dictum lectus.</p><h2>Quisque pharetra</h2><p>Lorem ipsum vel felis facilisis, ac rutrum tellus rutrum. Sed vehicula elementum erat, eget mattis tortor rhoncus a.</p><p>Vestibulum porta mattis quam a gravida. Aliquam quis quam nulla.</p></div>"
                    },
                    {
                        bg: "01.jpg",
                        content: "<div><h2>Phasellus mattis</h2><p>Lorem ipsum vel felis facilisis, ac rutrum tellus rutrum. Sed vehicula elementum erat, eget mattis tortor rhoncus a.</p></div>"
                    },
                    {
                        bg: "02.jpg",
                        content: "<div><h2>In diam nisi erat</h2><p>Vestibulum porta mattis quam a gravida. Aliquam quis quam nulla. Pellentesque nisi erat, elementum ut maximus sed, euismod vel dui. Curabitur vitae dui nec justo rhoncus imperdiet. In diam risus, egestas dictum viverra vel, pretium sed nisl.</p></div>"
                    },
                    {
                        bg: "03.jpg",
                        content: "<div><h2>Nullam ullamcorper</h2><p>Lorem ipsum scelerisque, urna imperdiet faucibus facilisis, orci elit dictum ex, blandit rutrum metus diam eget mi. Phasellus ullamcorper eu purus eu venenatis. Nullam vestibulum dolor vel felis facilisis, ac rutrum tellus rutrum. Sed vehicula elementum erat, eget mattis tortor rhoncus a. Phasellus ut nisl volutpat, dictum lectus ut, dictum lectus.</p><h2>Quisque pharetra</h2><p><img src='img/03.jpg' height='150' align='right' />Vestibulum porta mattis quam a gravida. Aliquam quis quam nulla. Pellentesque nisi erat, elementum ut maximus sed, euismod vel dui. Curabitur vitae dui nec justo rhoncus imperdiet. In diam risus, egestas dictum viverra vel, pretium sed nisl. Nam mi risus, imperdiet sed purus id, posuere feugiat nibh. Curabitur dignissim ipsum eget est pretium, ut luctus leo dapibus. Praesent in vehicula felis. Nullam quis faucibus justo. Praesent ac turpis tempor elit lobortis sodales laoreet pulvinar velit. Nam vel leo arcu. Cras magna nulla, lacinia in turpis vel, efficitur sagittis sem. Interdum et malesuada fames ac ante ipsum primis in faucibus. In congue consectetur lacus, ac venenatis elit gravida at.</p></div>"
                    },
                    {
                        bg: "04.jpg",
                        content: "<div><h2>Quisque pharetra</h2><p>Quisque eget aliquam urna. Integer tortor justo, fringilla ut diam in, ornare maximus sem. Nam dictum mauris nisl, id posuere sem sodales sit amet. Sed ac nulla ut nunc molestie vestibulum id a ipsum. Duis nec elementum libero. Etiam porttitor turpis eu venenatis porta. Quisque pharetra diam vel dui porta luctus. Duis sed odio viverra, molestie orci et, hendrerit erat. Duis ut tortor nec orci suscipit finibus nec non massa. </p></div>"
                    }
                ],
                currentFadeIndex: 0,
                contentContainer: undefined,
                c0: undefined,
                c1: undefined,
                canMove: true,
                begin: function()
                {
                    this.contentContainer = document.getElementById("contentContainer");
                    this.c0 = document.getElementById("content0");
                    this.c1 = document.getElementById("content1");

                    this.setContent(this.currentFadeIndex + 1, "left");

                    setInterval
                    (
                        function()
                        {
                            carousel.animateFader();
                        },
                        5000
                    );                   
                },       
                animateFader: function()
                {
                    if (this.canMove)
                    {
                        this.fade("left");   
                    }
                },               
                fade: function(dir)
                {
                    var nextFade;
                    var currentMarginLeft;
                    var nextMarginLeft;

                    this.setTransitionSpeed(0);

                    if (dir == "left")
                    {
                        if (this.currentFadeIndex == this.fades.length - 1)
                        {
                            nextFade = 0;
                        }
                        else
                        {
                            nextFade = this.currentFadeIndex + 1;
                        }

                        currentMarginLeft = 0;
                        nextMarginLeft = -100;
                    }

                    if (dir == "right")
                    {
                        if (this.currentFadeIndex == 0)
                        {
                            nextFade = this.fades.length - 1;
                        }
                        else
                        {
                            nextFade = this.currentFadeIndex - 1;
                        }   

                        currentMarginLeft = -100;
                        nextMarginLeft = 0;
                    }

                    this.setMargin(currentMarginLeft);
                    this.setContent(nextFade, dir);

                    setTimeout
                    (
                        function()
                        {
                            carousel.setTransitionSpeed(1);
                        },
                        250
                    );

                    setTimeout
                    (
                        function()
                        {
                            carousel.setMargin(nextMarginLeft);
                            carousel.currentFadeIndex = nextFade;
                        },
                        500
                    );

                    setTimeout
                    (
                        function()
                        {
                            carousel.canMove = true;
                        },
                        5000
                    );
                },
                setTransitionSpeed: function(interval)
                {
                    this.contentContainer.style.webKitTransition = interval + "s all";
                    this.contentContainer.style.transition = interval + "s all";
                },
                setMargin: function(margin)
                {
                    this.contentContainer.style.marginLeft = margin + "%";
                },
                setContent: function(next, dir)
                {
                    if (dir == "left")
                    {
                        this.c0.innerHTML = this.fades[this.currentFadeIndex].content;
                        this.c0.style.backgroundImage = "url(img/" + this.fades[this.currentFadeIndex].bg + ")";

                        this.c1.innerHTML = this.fades[next].content;
                        this.c1.style.backgroundImage = "url(img/" + this.fades[next].bg + ")";
                    }

                    if (dir == "right")
                    {
                        this.c0.innerHTML = this.fades[next].content;
                        this.c0.style.backgroundImage = "url(img/" + this.fades[next].bg + ")";

                        this.c1.innerHTML = this.fades[this.currentFadeIndex].content;
                        this.c1.style.backgroundImage = "url(img/" + this.fades[this.currentFadeIndex].bg + ")";
                    }
                },
                faderButtonClick: function(dir)
                {
                    this.canMove = false;
                    this.fade(dir);
                }
            }
        </script>
    </head>

    <body onload = "carousel.begin();">
        <div id="carouselContainer">
            <div class="margin">
                <input type="button" onclick="carousel.faderButtonClick('left')" value="&#9668;"/>
            </div>

            <div id="viewport">
                <div id="contentContainer">
                    <div id="content0" class="content"></div>
                    <div id="content1" class="content"></div>
                </div>
            </div>

            <div class="margin">
                <input type="button" onclick="carousel.faderButtonClick('right')" value="&#9658;"/>
            </div>   
        </div>
    </body>
</html>


Set divs to have that red outline, because we don't want to be developing blind.
div {outline: 1px solid #FF0000;}


There will be no change to the HTML, and very little to the CSS. For the contentContainer div, instead of having it 200% of its parent, it now fits the parent's width exactly at 100%. For the content CSS class, we remove the background-color property because now we're doing a fade-in/fade-out thing and we don't want the background to show up unexpectedly. Also, change its width to 100%.
#contentContainer
{
    width: 100%;
    height: 100%;
    background-color: #004400;
}

.content
{
    width: 100%;
    height: 100%;
    float: left;
    /*background-color: #000044;*/
    background-size: cover;
    background-position: 50% 50%;
    background-repeat: no-repeat;
    padding-top: 1em;                   
}


And add a new rule for content0, setting its margin-right property to negative 100%. This means that the divs content0 and content1 will overlap each other within contentContainer.
.content
{
    width: 100%;
    height: 100%;
    float: left;
    background-size: cover;
    background-position: 50% 50%;
    background-repeat: no-repeat;
    padding-top: 1em;               
}

#content0
{
    margin-right: -100%;
}


The result of this is that now your slide carousel doesn't show the next slide while sliding. Remember now content0 and content1 overlap and contentContainer is no longer twice as wide as viewport? That's OK, because we no longer want it to slide and that's the next thing we will take care of.


The JavaScript

The begin() method of the carousel object operates on the same principle as the Slide Carousel's, and no change needs to be made here save for the naming of the callback, which is now animateFader(). animateFader(), in turn, has no change except that the callback is now fade() rather than slide(). It's fade() that we have to tweak.

The If blocks that determine which slide fade comes next, is logically the same, so no change there. However, we no longer want to change the margin-left property. Instead, we want to change the opacity property. So let's remove the variables. And instead of callng the setMargin() method, we call the setOpacity() method, passing in 100 and 0 as arguments, in different orders. You'll see why later.

Also remove the dir argument for the call to setContent().
fade: function(dir)
{
    var nextFade;
    //var currentMarginLeft;
    //var nextMarginLeft;

    this.setTransitionSpeed(0);

    if (dir == "left")
    {
        if (this.currentFadeIndex == this.fades.length - 1)
        {
            nextFade = 0;
        }
        else
        {
            nextFade = this.currentFadeIndex + 1;
        }

        //currentMarginLeft = 0;
        //nextMarginLeft = -100;
    }

    if (dir == "right")
    {
        if (this.currentFadeIndex == 0)
        {
            nextFade = this.fades.length - 1;
        }
        else
        {
            nextFade = this.currentFadeIndex - 1;
        }   

        //currentMarginLeft = -100;
        //nextMarginLeft = 0;
    }

    //this.setMargin(currentMarginLeft);
    this.setOpacity(100, 0);
    this.setContent(nextFade/*, dir*/);

    setTimeout
    (
        function()
        {
            carousel.setTransitionSpeed(1);
        },
        250
    );

    setTimeout
    (
        function()
        {
            //carousel.setMargin(nextMarginLeft);
            carousel.setOpacity(0, 100);
            carousel.currentFadeIndex = nextFade;
        },
        500
    );

    setTimeout
    (
        function()
        {
            carousel.canMove = true;
        },
        5000
    );
},


Next, we rename the setMargin() method to setOpacity(). It will now accept two parameters, c0_opacity and c1_opacity.
setOpacity: function(c0_opacity, c1_opacity)
{
    //this.contentContainer.style.marginLeft = margin + "%";
},


In here, we want c0 and c1 to take on the opacities specified by their respective arguments. So if one is 100 and the other is 0, and there's a transition speed of more than 0 involved, it will look like one is fading out in favor of the other! Now you see why the need for the 100 and 0 values passed to the setOpacity() method earlier?
setOpacity: function(c0_opacity, c1_opacity)
{
    //this.contentContainer.style.marginLeft = margin + "%";
    this.c0.style.filter = "opacity(" + c0_opacity + "%)";
    this.c1.style.filter = "opacity(" + c1_opacity + "%)";
},


The setTransitionSpeed() method also needs changing. Remove the code inside.
setTransitionSpeed: function(interval)
{
    //this.contentContainer.style.webKitTransition = interval + "s all";
    //this.contentContainer.style.transition = interval + "s all";
},


Instead of altering the properties of contentContainer, we will alter the properties of content0 and content1.
setTransitionSpeed: function(interval)
{
    //this.contentContainer.style.webKitTransition = interval + "s all";
    //this.contentContainer.style.transition = interval + "s all";

    this.c0.style.webKitTransition = interval + "s all";
    this.c0.style.transition = interval + "s all";

    this.c1.style.webKitTransition = interval + "s all";
    this.c1.style.transition = interval + "s all";
},


OK, now we can modify the setContent() method. Get rid of all the code inside because we won't need it. Remember a fade is different from a slide - whether you're transitioning through the array in ascending or descending order, visually it's all the same. In a slide motion, you gave to cater for sliding left and right; in a fade motion, you simply adjust the opacity. You also won't need dir (as mentioned, it no longer matters what direction the animation is in), so remove it..
setContent: function(next/*, dir*/)
{
    /*if (dir == "left")
    {
        this.c0.innerHTML = this.fades[this.currentFadeIndex].content;
        this.c0.style.backgroundImage = "url(img/" + this.fades[this.currentFadeIndex].bg + ")";

        this.c1.innerHTML = this.fades[next].content;
        this.c1.style.backgroundImage = "url(img/" + this.fades[next].bg + ")";
    }

    if (dir == "right")
    {
        this.c0.innerHTML = this.fades[next].content;
        this.c0.style.backgroundImage = "url(img/" + this.fades[next].bg + ")";

        this.c1.innerHTML = this.fades[this.currentFadeIndex].content;
        this.c1.style.backgroundImage = "url(img/" + this.fades[this.currentFadeIndex].bg + ")";
    }*/
},


What you need to do is ensure that content0 shows the current fade, and content1 shows the next fade. Always.
setContent: function(next/*, dir*/)
{
    /*if (dir == "left")
    {
        this.c0.innerHTML = this.fades[this.currentFadeIndex].content;
        this.c0.style.backgroundImage = "url(img/" + this.fades[this.currentFadeIndex].bg + ")";

        this.c1.innerHTML = this.fades[next].content;
        this.c1.style.backgroundImage = "url(img/" + this.fades[next].bg + ")";
    }

    if (dir == "right")
    {
        this.c0.innerHTML = this.fades[next].content;
        this.c0.style.backgroundImage = "url(img/" + this.fades[next].bg + ")";

        this.c1.innerHTML = this.fades[this.currentFadeIndex].content;
        this.c1.style.backgroundImage = "url(img/" + this.fades[this.currentFadeIndex].bg + ")";
    }*/

    this.c0.innerHTML = this.fades[this.currentFadeIndex].content;
    this.c0.style.backgroundImage = "url(img/" + this.fades[this.currentFadeIndex].bg + ")";

    this.c1.innerHTML = this.fades[next].content;
    this.c1.style.backgroundImage = "url(img/" + this.fades[next].bg + ")";
},


Remember how I said we didn't have to change the begin() method? That wasn't exactly true. setContent() now only accepts a single argument, so you have to remove the second argument. Also, since we're no longer preparing for a slide left motion, we can take away the plus one from currentFadeIndex.
begin: function()
{
    this.contentContainer = document.getElementById("contentContainer");
    this.c0 = document.getElementById("content0");
    this.c1 = document.getElementById("content1");

    this.setContent(this.currentFadeIndex/* +1, "left"*/);

    setInterval
    (
        function()
        {
            carousel.animateFader();
        },
        5000
    );                   
},


Can you see the fade-in/fade-out effect?


Remove the red outline now, and things will look even prettier.
div {outline: 0px solid #FF0000;}




You might want to increase the transition speed here to make it fade even slower so the user can properly appreciate it. But be careful not to set it to a value greater or equal to the interval specified in animateFader(). Because that would be just messy.
setTimeout
(
    function()
    {
        carousel.setTransitionSpeed(3);
    },
    250
);


That's it, we're done!

I promised this would be short.

Unfortunately, this tutorial will make a whole lot more sense if you were present during the previous one. But this tutorial was maybe 80% similar to the last one and I hate repeating myself, so...

Fading out,
T___T

No comments:

Post a Comment