reptile7's JavaScript blog
Saturday, September 24, 2011
I Love an Image Parade
Blog Entry #227

We continue today our discussion of HTML Goodies' "Web Developer Tutorial: Build Your Own Image Scrollbar". In the previous post we deconstructed the tutorial's image scrollbar code. How does that code work in practice?

The scrollbar example

Just before the tutorial code is a parenthetical note providing a link to a demo. Originally the demo link pointed to (h/t commenter stephan), which is still live as of this writing. Within a couple of days of the tutorial's posting three readers had left comments complaining about the demo page, for example:
Chris 54 said on March 9, 2010 at 8:58 am
The example page doesn't work properly - the next and previous buttons don't work, so you can't see any other images (if any) Tried with Chrome and IE7
In a reply the author attempted to rationalize the demo page behavior by claiming that the html, head, and body tags got dropped from my example. How can that be? And so what? The start-tags and end-tags of the HTML html, head, and body elements are all optional - the absence of these tags shouldn't make any difference whatsoever.

After about a week the demo page had been moved off-site to its current location, Shortly thereafter the author made the following comment:
Curtis Dicken said on March 16, 2010 at 2:07 pm
I just wanted to let everyone know that we figured out why the example did not work properly. There is nothing wrong with the code. Instead it turns out that the server is configured to attach certain JavaScript libraries to every page it serves up which was causing conflicts and odd behavior with the example. We have moved the example to another server and the example now functions as it should. I apologize for any problems this may have caused. It's always something. ;-)
Actually, when I first visited the (new) demo page the demo didn't function as it should. None of the images would load, although I could mouse over the Next >> button and the << Previous button label color immediately changed from silver to black and the Next >> button label color changed from black to silver within a few seconds. Moreover, Safari (but no other browser) threw a set of twelve "Failed to load resource: the server responded with a status of 403 (Forbidden)" errors. Doesn't sound very promising, does it? Fortunately, inspection of the demo source proved instructive and eventually enabled me to get the demo sorted out - as it happens, neither missing HTML tags nor attached JavaScript libraries are to blame.

The demo images themselves are off-site with respect to both the new and old demo pages. Check out the "image1.png" URL:


All ten URLs are like that. Chopping off the query string doesn't lead to an image but rather a "400 Bad Request" page; interestingly, whittling down the URL to results in redirection to, the Web site of Getty Images, Inc.

The complete URLs are live and do lead to the images you are supposed to see. Following those URLs to look at the images will cache the images, and once the images are cached, the demo at either the new or old demo page works like a charm, or at least that's how things go on my iMac.

The author seems to have had an inkling that the demo had an image-caching problem because the new demo page's source contains a block of image-preloading code that is not present in the old demo page's source or in the tutorial's The Image Scroller Code section.

<body onload="javascript:preloadThumbnails( );">
<!-- No, it is not necessary to use a JavaScript URL to trigger the preloadThumbnails( ) function. -->
// This function preloads the thumbnail images
function preloadThumbnails( ) {
    imageObject = new Image( );
    for (i = 0; i < imagePath.length; ++i)
        imageObject.src = imagePath[i]; }

The preloadThumbnails( ) function is problematic in that it creates a single imageObject object and then writes the src property of that object over and over vis-à-vis creating ten image objects with differing src values. preloadThumbnails( ) would thus seem to cache the imagePath images consecutively but not concurrently, that is, only the last imagePath image (imagePath[9]) should be preloaded at the end of the for loop: experimentation at my EarthLink server space revealed that this is indeed what happens when using Firefox, Opera, or Camino. However, preloadThumbnails( ) does in fact cache all ten images when using Safari, Chrome, or IE 5.2.3.

This Netscape example provides a template for preloading a set of ordinalized images in a cross-browser manner:

imageObjects = new Array( );
for (i = 0; i < imagePath.length; i++) {
    imageObjects[i] = new Image( );
    imageObjects[i].src = imagePath[i]; }

Something else I found out:
I was originally of the impression that it was necessary to reference the image object representing a preloaded image in order to act on the image

document.getElementById(ImageToChange).src = imageObjects[currentIndex].src;

but this is not true; once cached, the image is directly available via its URL.

document.getElementById(ImageToChange).src = imagePath[currentIndex];

One more point before moving on:
In the last entry I briefly discussed IE's support for the DOM setAttribute( ) method, linking to an MSDN page that seemed to specify that support as Windows Internet Explorer 8 and later (I've now removed that link). The image scrollbar code uses setAttribute( ) to set
(1) style attributes for the Next >>/<< Previous buttons and
(2) src attributes for the thumbnail placeholders.
On my computer, IE 4.x-5.x balk at (1) but do execute (2); noteworthily, fingers IE 4 as the starting point for IE's setAttribute( ) support. So perhaps we can leave the changeImage( ) function alone vis-à-vis exchanging its setAttribute( ) command for an imageObject.src = URL; assignment statement (although I do the latter in my demo below, 'to be on the safe side').

The image scroller code, take 2

In the tutorial's Conclusion section the author says:
Now, before you start sending your emails telling me how I can consolidate my code, keep in mind I intentionally was more verbose than necessary for the beginners.
I guess I'm not the only one who has taken him to task for his long-winded code, huh? If truth be told, the "Build Your Own Image Scrollbar" code isn't nearly as verbose as the "Making a Wizard with JavaScript" code we slogged through a few entries ago, but that doesn't mean it can't be profitably tightened up.

The scrollImages( ) function's if (scrollDirection == "up") and else clauses are superficially symmetrical and I initially hoped to roll them into a single block of code. My (admittedly not exhaustive) efforts in this regard were unsuccessful - there were too many variables to juggle going back and forth - and I ultimately decided that I was better off 'going the other way': IMO the cleanest, most straightforward way to code the scrollbar is to split the scrollImages( ) function into individual functions that respectively handle forward and backward scrolling.

Here's the function that replaces the if (scrollDirection == "up") clause:

var timer1;
function scrollLeft( ) {
    var currentIndex;
    if (imageIndexLast != maxIndex) {
        document.getElementById("scrollPreviousCell").style.color = "black";
        currentIndex = imageIndexLast;
        var delay = 0;
        for (var i = 4; i > 0; i--) {
            window.setTimeout("document.getElementById('scrollThumb" + i + "').src = imageArray[" + currentIndex + "].src", delay);
            delay += 250;
            currentIndex--; }
    timer1 = window.setTimeout(scrollLeft, 1000); }
    else {
        document.getElementById("scrollNextCell").style.color = "silver";
        window.clearTimeout(timer1); } }
document.getElementById("scrollNextCell").onmouseover = scrollLeft;
document.getElementById("scrollNextCell").onmouseout = function ( ) { window.clearTimeout(timer1); }

The use of separate functions for forward and backward scrolling eliminates the need for the scrollDirection variable, thereby simplifying calls to those functions.

My intuition told me that the scrollNext( ) function, the scrollPrevious( ) function, the scrollAgain( ) function, the scrollStop( ) function, and the continueScroll on/off switch were all excess baggage, and I was right: they are easily eliminated by making recourse to the setTimeout( ) and clearTimeout( ) methods of the window object.

Finally, I wrote loops to automate the loading of images into the thumbnail placeholders; these loops incorporate the src-setting command of the changeImage( ) function, which was also thrown out.


To try out my revamped image scrollbar code, mouse over and out from the Next >> and << Previous strings flanking the thumbnail images in the div below.

<< PreviousNext >>
The scrollbar images have been given ordinalized file names - image1.jpg, image2.jpg, etc. (they're all .jpgs, not .pngs) - and are arrayed and preloaded via: imageArray = new Array(10); for (j = 0; j < 10; j++) {     imageArray[j] = new Image( ); } imageArray[0].src = "image_path/image1.jpg"; imageArray[1].src = "image_path/image2.jpg"; ... /* It was not possible to automatedly set the imageArray src values as the demo images were given irregular URLs when I uploaded them to Blogger. */ You can download the scrollbar images directly from me via the links below (right-click or control-click on each link and then select the "Save Linked File As..." or equivalent command in the contextual menu that pops up). image1.jpg image2.jpg image3.jpg image4.jpg image5.jpg image6.jpg image7.jpg image8.jpg image9.jpg image10.jpg
"Build Your Own Image Scrollbar" has a companion "JavaScript Tutorial: Build Your Own Image Viewer with Scrollbar" that connects the scrollbar to the large first-row image and we'll check it over in the next entry.


Comments: Post a Comment

<< Home

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)