CIT041J Index > Lecture Notes - Images

CIT041J Lecture Notes

Image Rollovers

In order to implement mouse rollovers such as the one you see at the right, you will need two new event handlers: onmouseover and onmouseout. (You are already familiar with onclick.) The mouseover event occurs whenever the mouse is over an element; the mouseout event occurs when the mouse leaves that element.

In old browsers, only hypertext links could react to these events, but now, any element can react to these events. Let’s start with an example that will change the background color when you move the mouse over the links below:

Peach | Light Blue | Neon Pink

Here’s the markup:

<a href="#" onmouseover="document.body.style.backgroundColor='#ffcc99';"
    onmouseout="document.body.style.backgroundColor='white'">Peach</a> |
<a href="#" onmouseover="document.body.style.backgroundColor='#99ccff';"
    onmouseout="document.body.style.backgroundColor='white'">Light Blue</a> |
<a href="#" onmouseover="document.body.style.backgroundColor='#ff99cc';"
    onmouseout="document.body.style.backgroundColor='white'">Neon Pink</a>

The Image object

The document object has an images property, which is an array of references to all the <img> elements in your document. For example, you could get access to the first image on this page (if it didn’t have an id) with this code:

var imgObject = document.images[0];

The properties of an image object include .src (corresponding to the src attribute, and also width, height, and alt properties. For example, this code:

function showInfo(n) {
  var imgObject = document.images[n];
  alert(imgObject.src + "\n" + 
    "dimensions: " + imgObject.width + " x " +
    imgObject.height + "\n" +
    "alt text: " + imgObject.alt);
}

It can be invoked with this button:

<input type="button" onclick="showInfo(0)"
  value="Show Image 0 Info"/>

Go ahead; try it:

It turns out that you can not only read the src property, you can also set it. When you set the src property of an image, this causes the server to send you the image (if it’s not already cached), and replace the existing image with the new image. It’s as if you changed the src= attribute of the <img> element. Let’s see this in action. The image below is the second image on the page:

black dot

Here is the HTML:

<img src="rollover/blackdot.png" width="100" height="100"
  alt="black dot" /><br />
<input type="button" value="Red"
  onclick="change1('rollover/reddot.png')" />
<input type="button" value="Black"
  onclick="change1('rollover/blackdot.png')" />

Here is the JavaScript change1() function:

function change1(newSource)
{
  document.images[1].src = newSource;
}

red square, blue dot

Now let’s combine the mouseover and the image. When you mouse over the image at the right, the colors and shapes will flip. Here’s the HTML:

<img src="rollover/colorflip.png" width="100" height="100"
  onmouseover="change2('rollover/colorflip2.png')"
  onmouseout="change2('rollover/colorflip.png')"
  alt="red square, blue dot" class="no-border" />

And here’s the JavaScript. Notice that you need a different function, since the image you are manipulating has an index number 2 on this page.

function change2(newSource)
{
  document.images[2].src = newSource;
}

The Numeric Method

Well, you might be thinking, why not make a generic change function like this:

function change(whichImage, newSource)
{
  document.images[whichImage].src = newSource;
}

and use it as on this page (and yes, you should look at it and figure out how it works!)

Even though this works, it’s not a good technique, because it is dependent on the order of the pictures. If you decide to switch the red and yellow pictures, the HTML will have to change. If you were to add a “cyan” picture at the left, you’d have to change the numbers in all the other <a href...> elements.

Giving Images an id

The obvious answer is to give each image a id= attribute, and use the unique ID. If you give an id to each image, you end up with HTML that looks something like this:

<a href="#" 
<img src="rollover/red0.jpg" id="redImg"
  onmouseover="change('redImg', 'rollover/red1.jpg')"
  onmouseout="change('redImg', 'rollover/red0.jpg')"
  width="100" height="100" alt="Red" />;

<img src="rollover/yellow0.jpg" id="yellowImg"
  onmouseover="change('yellowImg', 'rollover/yellow1.jpg')"
  onmouseout="change('yellowImg', 'rollover/yellow0.jpg')"
  width="100" height="100" alt="Yellow" />

<-- etc. -->

Now the change() function must be modified to use the id:

function change(imageId, newSource)
{
  var imgObject = document.getElementById(imageId);
  imgObject.src = newSource;
}

See this in action

The associative array method

There’s another method to get the image switching, and it depends upon the fact that JavaScript arrays act like associative arrays. Not only can you index an array by number, you can also index an array by name.

When the browser sees an <img> element in your HTML document, it not only adds an entry to the images array; it also adds an associative entry to the images array, using the id= attribute as the index. The first image on this page has a id="evclogo" attribute. That means that all of the following will refer to the src of that image:

With this knowledge, you can write the function for the version of the rollover script that uses associative arrays, which you can see in action here.

function change(imageId, newSource)
{
  document.images[imageId].src = newSource;
}

Preloading Images

Consider this: You’re using a slow Internet connection, and you’re on a page with a mouse rollover. You put the mouse on the button...and wait for a few seconds as the other image downloads. We can make this situation better by preloading the highlighted images.

In the <head> of the document, we will create a an array to hold the “highlighted” images and immediately start loading them. To make the code shorter, we will use another array with the file names.

var onImageURL = new Array( // the "on" images
  "rollover/red1.jpg",
  "rollover/yellow1.jpg",
  "rollover/green1.jpg"
);
var preload = new Array(onImageURL.length);

var imgNum; // a loop counter

The body of the following loop does two things:

  1. Creates an Image object in memory. You can think of this as if the browser creates an <img src="" /> element in memory. It’s not in the document, so no new image appears on the screen.
  2. The src of the in-memory image is set to the filename we want to preload. When the source changes, the browser either loads the image from cache, or if it isn’t cached, sends a message to the server asking it to download.
for (imgNum = 0; imgNum < preload.length; imgNum++)
{
  preload[imgNum] = new Image();
  preload[imgNum].src = onImageURL[imgNum];
}

Note that the code uses preload.length in the test for the loop. That way, you can preload as many images as you want without having to change the loop code.

All of this code happens in the <head> of the document, outside of a function. It occurs before the text of the page even begins to appear. Once the body of the page starts loading, some (if not all) of the rollover images are on their way from the server. The rest of the page stays exactly as it was. You may see it in action. Since you have probably already loaded these images from the other demos, you won’t see any difference in speed. Trust me, though; it does make a difference.

Another Approach

You may be concerned that there’s a lot of text involved in duplicating the image name and the URLs in the onmouseover and onmouseout attributes. Well, as long as there is an array for the images that you want to preload, and it has the “on” URLs in it, why not add a second array with the URLs of all the “off” images, and a third array with the names of the images? Here’s what it looks like:

var onImageURL = new Array(
  "rollover/red1.jpg",
  "rollover/yellow1.jpg",
  "rollover/green1.jpg"
);

var offImageURL = new Array(
  "rollover/red0.jpg",
  "rollover/yellow0.jpg",
  "rollover/green0.jpg"
);

var imgId = new Array(
  "redImg",
  "yellowImg",
  "greenImg"
);

As long as three arrays stay in step with one another, this approach works wonderfully well. The preloading code remains the same, but you now have a new function for highlighting images. The function will take an imageNumber which is an index into your arrays, and a boolean variable named turnOn which tells whether to turn the image on or off:

function highlight(imageNumber, turnOn)
{
  var theURL;
  var theName;

  theName = imgName[ imageNumber ];
  if (turnOn)
  {
    theURL = onImageURL[ imageNumber ];
  }
  else
  {
    theURL = offImageURL[ imageNumber ];
  }
  document.images[theName].src = theURL;
}

Now change the HTML to look like this. Notice that the JavaScript is much more compact.

<img src="rollover/red0.jpg"
  onmouseover="highlight(0, true)"
  onmouseout="highlight(0, false)"
  name='redImg' width="100" height="100" alt="Red" />

Hold on a minute!

You are probably thinking, “Why is he going back to using numbers? What happens if I change the order of the pictures? What happens if I need to add a new picture? Won’t I have to recode everything?”

No, you won’t. This time the code isn’t using the built-in document.images array, whose numbering changes every time we rearrange or add images. Instead, it’s using the arrays that you constructed yourself, and over which you have complete control. If you look at the example, you will see that there is an extra picture at the left and two of the other colors have been rearranged. Look carefully at the HTML; the numbers used in the calls to highlight() match the order in the arrays in the script. When you add new images, you just add them at the end of all the arrays—it doesn’t matter where they land on the screen.

Variations on a Theme

There are many other ways to do mouse rollovers. They truly are the “cole slaw of the Internet,” with a wide variety of recipes ranging from the really wonderful to the really awful. Here’s one other variation. It presumes that you are basing the URLs for the on and off images on the image’s name attribute:

If you have an image with name="xyz", then the “off” image will be file directory/xyz0.jpg and the “on” image will be file directory/xyz1.jpg

Take a look at the result. The function now gets the image name as its first parameter, not the number in the array. This method requires a little bit of extra text in your HTML, but it relies on names instead of numbers. This makes it easier to read, and that makes people feel better.