Custom Javascript Banner Rotator - Part 1

These days, a feature that city websites should never be without is the banner rotator, that is, an image up at the top of the site that cycles through various featured photos. The City of McAllen naturally was no exception, as you can see for yourself. The problem was that, being relatively inexperienced in Javascript, I've never made my own 'slideshow' type application before. Usually I will either download an existing script (or [[shudder]] a FLASH object...) and modify it to fit my needs.

In my search to find the perfect rotator, I went through dozens, including the Teleirk Rad Rotator, obout Show, both of which, for the most part, worked pretty well and weren't TOO difficult to customize...

Unfortunately, I didn't like the approach that these (and as I discovered, most) controls used. Basically what happens is they load up a full array of images, create separate elements for each one, then toggle the visibility of each one in a cycle. This is pretty much the same problem I had that led me to build my Ajax News Rotator. Even worse, if javascript is disabled, the Rad Rotator renders an empty element! Other controls would experience erratic behavior as well, either rendering blank, or worse, showing ALL the elements in a mishmash of images. This problem was compounded by the fact that some of these controls (such as Rad Rotator) load all of the elements at once, meaning load time is stalled while all the content and images are loaded into their own separate frame!

And that's when it dawned on me. All of these frames are exactly the same, so why do we need one for every single element? Ideally, we would only need the ONE frame, instead replacing it over and over with the content, loaded on demand with javascript. While this is certainly possible, having only one frame prevents us from doing transition effects, such as fade or slide, or anything that requires two elements to be blended together.

so my solution was to narrow it down to TWO frames, one for the start element, which is added statically on the page, and a second to "swap" the image, loaded dynamically at run time. Doing things this way allows the page to render correctly if Javascript is disabled, because it will just show the first frame. All I have to do now is swap the image back and forth across the two elements!

Neat huh? Alright, enough background, on to the code!

I'd like to start first by giving credit here to Rob Watson, because I used his excellent Fading Image Slide Show tutorial as a basis for my solution. His entry is pretty thorough, so I'm only going to touch on my changes.

The first thing to do was to remove the for-loop that appended every element, instead only adding a second img element to "swap" to. See instead of using the array to CREATE the img elements, I'm instead using the array to REPLACE the two elements with the SRC from the current item in the array!

// create new img element for rotation
var t = document.createElement('img');
t.setAttribute('src', images[nextImage]);
t.setAttribute('width', imageWidth);
t.setAttribute('height', imageHeight);
t.style.position = 'absolute';
t.style.visibility = 'hidden';
el.appendChild(t);

Next we want to grab a reference to these two elements so we can load them on demand and start the cycle.

// grab references to the two img elements
imgs = el.getElementsByTagName('img');

// begin 
rotationwindow.setTimeout(startFading, imageTimeout);

both startFading and setOpacity work pretty much the same as Rob's:

function startFading()
{
    // grab the next element and fade it in 
    var el = imgs[curImg];
    el.style.visibility = 'visible';
    el.style.zIndex = 2;
    setOpacity(el, 0);
    fadeImage(el, 0);

    // swap to the next img element 
    curImg = (curImg == 1) ? 0 : 1;
}

function setOpacity(el, opacity)
{
    opacity /= 100;
    el.style.opacity = opacity;
    el.style.MozOpacity = opacity;
    el.style.filter = "alpha(opacity=" + (opacity * 100) + ")";
}

The biggest change comes in the fadeImage method. Basically the idea is to populate the NEXT image with the src from the images array and set it as hidden. Once that's complete, all we have to do is fade it in:

function fadeImage(el, currentOpacity)
{
    // increase opacity 
    currentOpacity += 2;

    // if full opaque 
    if (currentOpacity > 100)
    {
        // reset in case over 
        setOpacity(el, 100);

        // move to next image in array 
        if (++nextImage > 4) nextImage = 0;

        // reset swapped img element to next image 
        var prevEl = imgs[curImg];
        prevEl.setAttribute('src', images[nextImage]);
        prevEl.style.visibility = 'hidden';
        el.style.zIndex = 1;

        // continue rotation 
        window.setTimeout(startFading, imageTimeout);
    }
    else {
        // fade in 
        setOpacity(el, currentOpacity);
        window.setTimeout(function() { fadeImage(el, currentOpacity); }, 50);
    }

}

All that's left to do now is call the function! Remember that we pre-populate the container div with the first image, that way if Javascript is disabled, users will still see the first (and only) image.

<asp:ScriptManagerProxy ID="ScriptManager" runat="server"> 
    <Scripts> 
        <asp:ScriptReference Path="/files/scripts/BannerSwapper.js" /> 
    </Scripts>
</asp:ScriptManagerProxy>

<div id="fading_image_container"> 
    <img src="/images/banners/banner10.jpg" alt="" style="width: 930px; height: 230px;
            position: absolute" />
</div> 
<script type="text/javascript">
    Init();
</script>

As you can see, I used a scriptmanagerproxy control to register my external js file, then call the Init function to get things started. Unfortunately this Init gets called on every page load, including partial postbacks (ajax) so if you're using these, make sure to add a check in the javascript file to make sure that the second img element hasn't already been added:

// make sure we're in the init phase
var el = document.getElementById('fading_image_container');
var count = el.getElementsByTagName('img').length;
if (count > 1) return;

And that's all there is to it! You can see this in action at McAllen.net. The banner up at the top uses this script! But it won't be up for long because it's soon to get replaced with Part 2, where I wrap this script in a jQuery plugin! stay tuned!

Enjoyed this post and/or found it useful?
SelArom Dot Net Profile Image
SelAromDotNet

Josh loves all things Microsoft and Windows, and develops solutions for Web, Desktop and Mobile using the .NET Framework, Azure, UWP and everything else in the Microsoft Stack.

His other passion is music, and in his spare time Josh spins and produces electronic music under the name DJ SelArom.



Scroll to top