reptile7's JavaScript blog
Friday, August 20, 2010
Double-Flip Your Pleasure
Blog Entry #188

We have discussed 'image flipping' and its applications several times previously, and we'll do so again today with a look at HTML Goodies' "So, You Want A Dual Image Flip, Huh?" tutorial.

Like the "So, You Want A SlideShow, Huh?" tutorial we covered earlier in the Beyond HTML : JavaScript sector, "So, You Want A Dual Image Flip, Huh?" offers a script and a set of images for creating a simple slide show. Joe doesn't describe the effect of the latter tutorial's script as a "slide show", but the term is apropos as we'll be loading a series of images into a common img placeholder.

The user moves through the "So, You Want A SlideShow, Huh?" slide show by clicking Next and Back links. The "So, You Want A Dual Image Flip, Huh?" slide show's interface is a bit more involved:
(a) Each new slide is loaded into the slide show placeholder via its own "button": not an actual push button but a link whose content is an image of a button.
(b) Upon mousing over the link, the current slide changes to a new slide, and the link's button image changes to a pressed-button image as though you have pressed the original "button" - that's the "dual" part of the script.

Joe has conveniently combined the tutorial's script and various images in a .zip file that is posted here, and he provides a functioning demo for the script in the tutorial's introduction.

The images

OK, what do we have here? Let's begin with the img placeholder that the slide show's images will be loaded into:

<img name="global" width="130" height="130" src="white.gif" alt="[ ]" />

The script will reference this placeholder via its global name, more specifically, with document.images["global"]; the button image placeholders discussed below are also referenced in this way. Today the W3C would want us to change the img name attributes to id attributes and then reference the placeholders with document.getElementById("imgID") - indeed, the name attribute of the img element has been deprecated by XHTML 1.0 - but you have to remember when HTML Goodies' JavaScript scripts were written (most of them in the late 1990s); as late as Netscape 4.x, Netscape did not support the id attribute for the img element or for most other elements.

We will load three images into the global placeholder:

(1) A white.gif image (this is the file name that appears in the tutorial's "The Code" section and in the imagetwo.htm document containing the script in the package, but at some point the file name was changed to dualflip.gif for the tutorial demo):
['The Goodies/Click Here']

(2) An hg_banner.gif image: ['HTML Goodies/'] (3) A jg_banner.gif image: ['Java Goodies/']

Although the white.gif image says (inter alia) "CLICK HERE" and the hg_banner.gif and jg_banner.gif images sport the domain name, clicking these images won't take you anywhere; unlike the button image placeholders, the global placeholder is not wrapped in a link.

To the left of the global placeholder - we'll have more to say about the script's display layout later - are two placeholders for the aforementioned button images that seem* to trigger global image flipping (*as we'll see in the next section, the 'heavy lifting' is actually done by the placeholders' anchor element parents):

<img name="one" width="96" height="36" border="0" src="but1.gif" alt="[ ]" />
<img name="two" width="96" height="36" border="0" src="but2.gif" alt="[ ]" />

The one placeholder initially holds a but1.gif image:
['Button 1', unpressed]
(In the package, this file is named but1.GIF: be sure to lowercase the GIF to gif before using this file.)

Note that but1.gif has a small decoration in its upper-left-hand corner that makes the image's button look as though it were coming out of the screen. Mousing over but1.gif flips white.gif, the first global slide, to hg_banner.gif, and also flips but1.gif itself to a but1b.gif image:
['Button 1', pressed]

but1b.gif is a 'pressed' version of but1.gif: by
(a) subtracting the upper-left-hand corner decoration,
(b) cutting the button's 'borders' in half, and
(c) slightly shifting the "Button 1" label's top offset,
the "Button 1" button now looks like it's been pushed into the screen. Mousing out from but1b.gif flips hg_banner.gif back to white.gif and but1b.gif back to but1.gif.

Analogously, the two placeholder initially holds a but2.gif image
['Button 2', unpressed]
that when mouseovered flips white.gif to jg_banner.gif and itself to a 'pressed' but2b.gif image
['Button 2', pressed]
and vice versa when but2b.gif is mouseouted.

Before white.gif, but1.gif, and but2.gif are loaded into their respective placeholders, all seven images are preloaded by the following statements at the top of the script's script element:

alt0 = new Image( ); alt0.src = "white.gif";
alt1 = new Image( ); alt1.src = "hg_banner.gif";
alt2 = new Image( ); alt2.src = "jg_banner.gif";
graphic1 = new Image( ); graphic1.src = "but1.gif";
graphic1on = new Image( ); graphic1on.src = "but1b.gif";
graphic2 = new Image( ); graphic2.src = "but2.gif";
graphic2on = new Image( ); graphic2on.src = "but2b.gif";

As a dial-up user myself, I can confirm that the above code will definitely speed up the first "Button 1"/"Button 2" image flips for those with slow Web connections.

Flip mechanics

For all of the img placeholders, image flipping is carried out by the imageChange( ) function that follows the preloading code:
function imageChange(imageID, imageName, imageID2, imageName2) {
	document.images[imageID].src = eval(imageName + ".src");
	document.images[imageID2].src = eval(imageName2 + ".src"); }
The imageChange( ) parameter names are a bit misleading; in practice, here's what we'll be feeding to imageChange( ):

• In all cases, imageID will be global, the name of the slide show placeholder.
imageName will be an object reference, set by the preloading code, for one of the global images: alt1, alt0, or alt2.
imageID2 will be the name of one of the button image placeholders, i.e., one or two.
imageName2 will be an object reference, again set by the preloading code, for one of the button images: graphic1on, graphic1, graphic2on, or graphic2.

So whereas names are indeed identifiers and object references can informally be viewed as 'names', the imageChange( ) declaration should be written as:

function imageChange(imgName, imageObject, imgName2, imageObject2)

The one and two button image placeholders are wrapped in anchor elements equipped with onmouseover and onmouseout event handlers that call imageChange( ) and supply it with img name and image object reference inputs:

<a href="/" onmouseover="imageChange('global', 'alt1', 'one', 'graphic1on');" onmouseout="imageChange('global', 'alt0', 'one', 'graphic1');">
<img name="one" width="96" height="36" border="0" src="but1.gif" alt="[ ]" /></a><br /><br />

<a href="" onmouseover="imageChange('global', 'alt2', 'two', 'graphic2on');" onmouseout="imageChange('global', 'alt0', 'two', 'graphic2');">
<img name="two" width="96" height="36" border="0" src="but2.gif" alt="[ ]" /></a>

You may be thinking, "Why don't we ditch the links and then put the onmouseover and onmouseout event handlers in the img tags?" To be sure, we could do that today, but let me put on my archivist's hat once again and point out that pre-Gecko versions of Netscape only supported the onmouseover and onmouseout attributes for the anchor, area, layer, and ilayer elements - that's why the links are there.

Historical note: The link wrapper for the two placeholder points to, Joe's one-time "Java Goodies JavaScript Repository". (Some of the scripts are still there and we may be mining this material in the future.) As an independent site, disappeared sometime in late 1999/early 2000 and now redirects to ("").

All that remains for us to do, deconstruction-wise, is to plug the onmouseover- and onmouseout-passed values into imageChange( ) and verify that the resulting assignments produce the image flips described in the preceding section. I trust you're up to the task of doing that, but we can quickly go through one example. Mousing over the links[0] link effectively generates the following imageChange( ) statements:

document.images["global"].src = eval("alt1" + ".src");
document.images["one"].src = eval("graphic1on" + ".src");

Concatenation of the strings "alt1" and ".src" gives the string "alt1.src", which is evaluated with the eval( ) function to give "hg_banner.gif", which is then assigned to the src property of the document.images["global"] placeholder, thereby replacing white.gif with hg_banner.gif. Similarly, concatenation of "graphic1on" and ".src" gives "graphic1on.src", which is evaluated with eval( ) to give "but1b.gif", which is assigned to the src property of the document.images["one"] placeholder, thereby replacing but1.gif with but1b.gif.

The eval( ) function is not unproblematic, and imageChange( )'s use thereof can be eliminated if, instead of concatenating object reference strings with ".src", we were to concatenate the corresponding pre-extension file name strings with ".gif":
function imageChange(imgID, imageFileName, imgID2, imageFileName2) {
	document.images[imgID].src = imageFileName + ".gif";
	document.images[imgID2].src = imageFileName2 + ".gif"; }
<a href="/" onmouseover="imageChange('global', 'hg_banner', 'one', 'but1b');" onmouseout="imageChange('global', 'white', 'one', 'but1');">
<a href="/" onmouseover="imageChange('global', 'jg_banner', 'two', 'but2b');" onmouseout="imageChange('global', 'white', 'two', 'but2');">
<!-- For that matter, the intact myImage.gif URLs themselves could be fed to imageChange( ), if you'd rather do that. -->
Layout, and a demo

Joe lays out his demo in a one-row, two-cell table - the one and two img placeholders and their link wrappers are placed in the left cell, and the global img placeholder is placed in the right cell - but as we all know, the W3C frowns on the use of tables for document layout. The state-of-the-art way to achieve Joe's layout (to which you of course are not restricted, as Joe himself points out) is to load everything into a div element with an appropriate width and then float the global placeholder right.

We wrap up this post with a demo. In the div below, move your mouse cursor over the "Meow" or "Woof" button to flip the parrot photo to a new photo:

[ ]

My demo uses real buttons, and not images thereof - you shouldn't have to go running to a graphics editor to make slide controls. I mimic the un/pressed business by toggling the buttons' borders between 7px outset #ff00ff (unpressed) and 3px inset #ff00ff (pressed). Push buttons are typically clicked and not mouseovered, and the demo script can be set up so that alternate clicks toggle simultaneously a button's border and the global image, but I prefer the mouseover/mouseout interface in this case, so I stuck with it.

I myself don't see the point in returning to the original global image upon mouseouting the slide controls, so I simplified the controls' onmouseout code accordingly:
onmouseout=" = '7px outset #ff00ff';"

A final thought:
I find it a bit surprising that Joe didn't play up the each-slide-has-its-own-control aspect of the "So, You Want A Dual Image Flip, Huh?" script, as this type of slide show would be generally useful for illustrating the items of a list - a list of PCs for sale, a list of vintage automobiles, a list of dog breeds, whatever. Let's say you run a Web site dedicated to your favorite musical artist. Your site features a "Discography" page listing the artist's album releases; mousing over each album name could load a reproduction of the album's front cover into an img placeholder to the right of the album list.

The next Beyond HTML : JavaScript tutorial, "So, You Want An External JavaScript, Huh?", is too basic to discuss - I trust y'all know how to externalize a script via a <script type="text/javascript" src="myScript.js"></script> element - so we won't be discussing it. The tutorial after that, "So, You Want A Scrolling JavaScript, Huh?", serves up another scrolling text script. Do we really want to go through one of those guys again so soon in the following entry? Yeah, why not?


Comments: Post a Comment

<< Home

Powered by Blogger

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