As precursors to true Dynamic HTML powers of more recent browsers, Navigator 3 (and Internet Explorer 3.01 for the Macintosh only) gave us a glimpse of things to come with image swapping. The basis for this technique is a document object model that defines an img element as an object whose properties can be changed on the fly. One of those properties, src, defines the URL of an image loaded initially by virtue of an <img> tag and currently displayed in the page. Change that property and the image changes, within the same rectangular space defined by the <img> tag's height and width attributes (or, lacking those attribute settings, the first image's dimensions as calculated by the browser), while all the other content around it stays put. In browsers that reflow dynamic content (IE 4 and later and Netscape 6 and later), you can swap images of different sizes, and the surrounding content adjusts its layout accordingly.
Working in tandem with the img element object is the static Image object from which new "virtual" images can be created in the browser's memory with the help of scripts. These kinds of images do not appear in the document, but can be scripted to preload images into the browser's image cache as the page does its original download. Thus, when it comes time to swap an image, the switch is nearly instantaneous because there is no need for network access to grab the image data.
The example in this section shows you how to precache and swap images for the buttons of an imaginary video controller. There are four controls—Play, Stop, Pause, and Rewind. Each control has its own image that acts as a button. As the user rolls the mouse atop a button, a highlighted version of the button icon appears in the image space; as the mouse rolls off the button, the original unhighlighted version reappears.
When preloading images (and later retrieving them for swapping), it is convenient to create an array for each state that the images will be in. Identifiers that you assign to the actual img elements (name, id, or both attributes) serve as the best index values for the arrays, rather than numeric sequences. Not only do the names help you keep the abstract objects, elements, and image files straight while you build your script, but the swapping scripts work even if you alter the page layout and image sequence.
In Example 5-6, there are two image states: highlighted and unhighlighted (more conveniently referred to as "on" and "off"). The head portion of the document contains a series of script statements that generate the new Image objects (in memory) and assign the URLs for the associated image files to the src properties of those memory image objects. Example 5-6 shows the sequence of statements that makes this happen for the four "on" images and the four "off" images. Encase these statements in an object detection block for document.images so that older browsers won't choke on a missing Image object.
if (document.images) { // create "on" array and populate with Image objects var onImgArray = new Array( ); onImgArray["play"] = new Image(75,35); onImgArray["stop"] = new Image(75,35); onImgArray["pause"] = new Image(75,35); onImgArray["rewind"] = new Image(75,35); // set URLs for the "on" images onImgArray["play"].src = "images/playon.gif"; onImgArray["stop"].src = "images/stopon.gif"; onImgArray["pause"].src = "images/pauseon.gif"; onImgArray["rewind"].src = "images/rewindon.gif"; // create "off" array and populate with Image objects var offImgArray = new Array( ); offImgArray["play"] = new Image(75,35); offImgArray["stop"] = new Image(75,35); offImgArray["pause"] = new Image(75,35); offImgArray["rewind"] = new Image(75,35); // set URLs for the "off" images offImgArray["play"].src = "images/playoff.gif"; offImgArray["stop"].src = "images/stopoff.gif"; offImgArray["pause"].src = "images/pauseoff.gif"; offImgArray["rewind"].src = "images/rewindoff.gif"; }
The act of stuffing the URL for each image file into the src property of each Image object is enough to force the browser to actually fetch the image and store it in its image cache without displaying the image anywhere.
Now it's time to look at the HTML that displays the images within the document. For the sake of this example, the surrounding HTML is of no importance. Since img element objects in a document don't respond to mouse events prior to IE 4 or Netscape 6, the images are wrapped inside links. You may prefer to use <a> tags for newer browsers as well, if clicking on the images navigates to new pages. To prevent the normal link color border from appearing around the images, the border attribute of each <img> tag is set to zero. The event handlers of the surrounding links trigger all the action for the image swapping. Example 5-7 shows the four image elements and their surrounding links.
<a href="javascript:playVideo( );" onmouseover="imageOn('play'); return setMsg('Play/Continue the clip');" onmouseout="imageOff('play'); return setMsg('');"> <img src="images/playoff.gif" name="play" id="play" height="35" width="75" border="0" alt= "play"> </a> <a href="javascript:stopVideo( );" onmouseover="imageOn('stop'); return setMsg('Stop video');" onmouseout="imageOff('stop'); return setMsg('');"> <img src="images/stopoff.gif" name="stop" id="stop"height="35" width="75" border="0" alt="stop"> </a> <a href="javascript:pauseVideo( );" onmouseover="imageOn('pause'); return setMsg('Pause video');" onmouseout="imageOff('pause'); return setMsg('');"> <img src="images/pauseoff.gif" name="pause" id="pause" height="35" width="75" border="0" alt="pause"> </a> <a href="javascript:rewindVideo( );" onmouseover="imageOn('rewind'); return setMsg('Rewind to beginning');" onmouseout="imageOff('rewind'); return setMsg('');"> <img src="images/rewindoff.gif" name="rewind" id="rewind"height="35" width="75" border="0" alt="rewind"> </a>
The onmouseover and onmouseout event handlers in each link have two tasks. The first is to change the image and the second is to display an appropriate message in the status bar of the browser window (to avoid displaying the javascript: pseudo-URL there). All this is handled with three simple functions, shown in Example 5-8.
function imageOn(imgName) { if (document.images) { document.images[imgName].src = onImgArray[imgName].src; } } function imageOff(imgName) { if (document.images) { document.images[imgName].src = offImgArray[imgName].src; } } function setMsg(msg) { window.status = msg; return true; }
Image swapping is accomplished by setting the src property of the visible img element to the src property of the desired memory image. Notice how string values used as index values for both the preloaded and document.images arrays avoid the need for the highly inefficient JavaScript eval( ) function. The setMsg( ) function returns true, so that the last statement of all mouse-related event handlers evaluates to true. This allows the status bar setting to take hold.
If image preloading does not appear to work for your pages in IE for Windows, your server may be returning HTTP 1.1 headers that instruct the browser to check with the server each time an image URL is changed. This can cause severe thrashing behavior with mouse rollovers because the onmouseover event fires repeatedly while the mouse is atop the element, forcing repeated server requests.
You may be able to override the server settings by including a meta element in your document that specifies an extended expiration date, such as the following:
<meta http-equiv="EXPIRES" content="Fri 31 Dec 2010 23:00:00 GMT">
But controlling caching from the server is a better solution.
Copyright © 2003 O'Reilly & Associates. All rights reserved.