22.1. Scripting ImagesWeb pages include images that use the HTML <img> tag. Like all HTML elements, an <img> tag is part of the DOM and can therefore be scripted like any other element in a document. This section illustrates common techniques. 22.1.1. Images and the Level 0 DOMImages were one of the first scriptable HTML elements, and the Level 0 DOM allows you to access them through the images[] array of the Document object. Each element of this array is an Image object that represents one <img> tag in the document. You can find complete documentation of the Image object in Part IV. Image objects can also be accessed with Level 1 DOM methods such as getElementById( ) and getElementsByTagName( ) (see Chapter 15). The document.images[] array lists Image objects in the order in which they appear in the document. More usefully, however, it provides access to named images. If an <img> tag has a name attribute, the image can be retrieved using the name specified by that attribute. Consider this <img> tag, for example: <img name="nextpage" src="/books/2/427/1/html/2/nextpage.gif"> Assuming that no other <img> tag has the same value for its name attribute, the corresponding Image object is available as: document.images.nextpage or as: document.images["nextpage"] If no other tag (of any type) in the document shares the same name attribute, the Image object can even be accessed through a property of the document object itself: document.nextpage 22.1.2. Traditional Image RolloversThe main feature of the Image object is that its src property is read/write. You can read this property to obtain the URL from which an image was loaded, and, more importantly, you can set the src property to make the browser load and display a new image in the same space. The ability to dynamically replace one image with another in an HTML document opens the door to any number of special effects, from animation to digital clocks that update themselves in real time. In practice, the most common use for image replacement is to implement image rollovers, in which an image changes when the mouse pointer moves over it. (To prevent jarring visual effects, the new image should be the same size as the original.) When you make images clickable by placing them inside your hyperlinks, rollover effects are a powerful way to invite the user to click on the image.[*] This simple HTML fragment displays an image within an <a> tag and uses JavaScript code in the onmouseover and onmouseout event handlers to create a rollover effect:
<a href="help.html" onmouseover="document.helpimage.src='/books/2/427/1/html/2/images/help_rollover.gif';" onmouseout="document.helpimage.src='/books/2/427/1/html/2/images/help.gif';"> <img name="helpimage" src="/books/2/427/1/html/2/images/help.gif" border="0"> </a> Note that in this code fragment, the <img> tag has a name attribute that makes it easy to refer to the corresponding Image object in the event handlers of the <a> tag. The border attribute prevents the browser from displaying a blue hyperlink border around the image. The event handlers of the <a> tag do all the work: they change the image that is displayed simply by setting the src property of the image to the URLs of the desired images. These event handers are placed on the <a> tag for the benefit of very old browsers that support those handlers only on specific tags, such as <a>. In virtually every browser deployed today, you can also put the event handlers on the <img> tag itself, which simplifies the image lookup. The event-handler code can then refer to the Image object with the this keyword: <img src="/books/2/427/1/html/2/images/help.gif" onmouseover="this.src='/books/2/427/1/html/2/images/help_rollover.gif'" onmouseout="this.src='/books/2/427/1/html/2/images/help.gif'"> Image rollovers are strongly associated with clickability, so this <img> tag should still be enclosed in an <a> tag or given an onclick event handler. 22.1.3. Offscreen Images and CachingIn order to be viable, image rollovers and related effects need to be responsive. This means that you need some way to ensure that the necessary images are "prefetched" into the browser's cache. To force an image to be cached, you first create an Image object using the Image( ) constructor. Next, load an image into it by setting the src property of this object to the desired URL. This image is not added to the document, so it does not become visible, but the browser nevertheless loads and caches the image data. Later, when the same URL is used for an onscreen image, it can be quickly loaded from the browser's cache, rather than slowly loaded over the network. The image-rollover code fragment shown in the previous section did not prefetch the rollover image it used, so the user might notice a delay in the rollover effect the first time she moves the mouse over the image. To fix this problem, modify the code as follows: <script>(new Image( )).src = "images/help_rollover.gif";</script> <img src="/books/2/427/1/html/2/images/help.gif" onmouseover="this.src='/books/2/427/1/html/2/images/help_rollover.gif'" onmouseout="this.src='/books/2/427/1/html/2/images/help.gif'"> 22.1.4. Unobtrusive Image RolloversThe image rollover code just shown requires one <script> tag and two JavaScript event-handler attributes to implement a single rollover effect. This is a perfect example of obtrusive JavaScript. Although it is common to see code that mixes presentation (HTML) with behavior (JavaScript) like this, it is better to avoid it when you can. Especially when, as in this case, the amount of JavaScript code is so large that it effectively obscures the HTML. As a start, Example 22-1 shows a function that adds a rollover effect to a specified <img> element. Example 22-1. Adding a rollover effect to an image
The addRollover( ) function defined in Example 22-1 is not completely unobtrusive because in order to use it, you must still include a script in your HTML files that invokes the function. To achieve the goal of truly unobtrusive image rollovers, you need a way to indicate which images have rollovers and what the URL of the rollover image is, without resorting to JavaScript. One simple way to do so is to include a fake HTML attribute on the <img> tags. For example, you might code images that have rollover effects like this: <img src="/books/2/427/1/html/2/normalImage.gif" rollover="rolloverImage.gif"> With an HTML coding convention like this, you can easily locate all images that require rollover effects and set up those effects with the initRollovers( ) function defined in Example 22-2. Example 22-2. Adding rollover effects unobtrusively
All that remains is to ensure that this initRollovers( ) method is invoked when the document has loaded. Code like the following should work in current browsers: if (window.addEventListener) window.addEventListener("load", initRollovers, false); else if (window.attachEvent) window.attachEvent("onload", initRollovers); See Chapter 17 for a more complete discussion of onload handling. Note that if you place the addRollover( ) function and the initRollovers( ) function in the same file as the event-handler registration code, you have a completely unobtrusive solution for image rollovers. Simply include the file of code with a <script src=> tag, and place rollover attributes on any <img> tags that need rollover effects. If you don't want your HTML files to fail validation because you've added a nonstandard rollover attribute to your <img> tags, you can switch to XHTML and use XML namespaces for the new attribute. Example 22-3 shows a namespace-aware version of the initRollovers( ) function. Note, however, that this version of the function does not work in Internet Explorer 6 because that browser does not support the DOM methods that support namespaces. Example 22-3. Initializing rollovers with XHTML and namespaces
22.1.5. Image AnimationsAnother reason to script the src property of an <img> tag is to perform an image animation in which an image is changed frequently enough that it approximates smooth motion. A typical application for this technique might be to display a series of weather maps that show the historical or forecast evolution of a storm system at hourly intervals over a two-day period. Example 22-4 shows a JavaScript ImageLoop class for creating this kind of image animation. It demonstrates the same scripting of the src property and image prefetching techniques shown in Example 22-1. It also introduces the onload event handler of the Image object, which can determine when an image (or, in this case, a series of images) has finished loading. The animation code itself is driven by Window.setInterval( ) and is quite simple: simply increment the frame number and set the src property of the specified <img> tag to the URL of the next frame. Here is a simple HTML file that uses this ImageLoop class: <head> <script src="/books/2/427/1/html/2/ImageLoop.js"></script> <script> var animation = new ImageLoop("loop", 5,["images/0.gif", "images/1.gif", "images/2.gif", "images/3.gif", "images/4.gif", "images/5.gif", "images/6.gif", "images/7.gif", "images/8.gif"]); </script> </head> <body> <img src="/books/2/427/1/html/2/images/loading.gif"> <button onclick="animation.start( )">Start</button> <button onclick="animation.stop( )">Stop</button> The code in Example 22-4 is somewhat more complicated than you might expect because both the Image.onload event handler and the Window.setInterval( ) timer function invoke functions as functions rather than as methods. For this reason, the ImageLoop( ) constructor must define nested functions that know how to operate on the newly constructed ImageLoop. Example 22-4. Image animations
22.1.6. Other Image PropertiesIn addition to the onload event handler demonstrated in Example 22-4, the Image object supports two others. The onerror event handler is invoked when an error occurs during image loading, such as when the specified URL refers to corrupt image data. The onabort handler is invoked if the user cancels the image load (for example, by clicking the Stop button in the browser) before it has finished. For any image, one (and only one) of these handlers is called. Each Image object also has a complete property. This property is false while the image is loading; it is changed to true once the image has loaded or once the browser has stopped trying to load it. In other words, the complete property becomes true after one of the three possible event handlers is invoked. The other properties of the Image object simply mirror the attributes of the HTML <img> tag. In modern browsers, these properties are read/write, and you can use JavaScript to dynamically change the size of an image, causing the browser to stretch or shrink it. |