hi all -
i'm new to this forum and would love some guidance on this.
i'm using a great script from oreilly for an efficient rollover effect on an image map - highly recommend for anyone needing something like this - link is below - my question is how do i modify it so the menu item *stays* highlighted when the page is selected? that is, in the example, if you rollover or click 'home', the image changes, but once you select it, the effect goes away.
i've tried a few things but am getting bogged down as to the best approach.

here's self explanatory link with code:

http://www.oreillynet.com/pub/a/javascript/2003/07/01/bonusrecipe.html

Tanaquil,

I've taken a quick look at the technique and reckon you're bound to run into a problem trying to do what you want. The reason is that the technique uses 'clip' to determine a sub-area of an overlayed image to cause the highlight effect. Because 'clip' can only ever be one contiguous area, you would not be able to have two non-adjacent buttons highlighted at the same time (in the same colour scheme) - which you would need to highlight one for the page you're on and one for the mouseover highlght effect.

You could get around this by introducing a fourth, 'layer' (same image as for mouseover state), and managing that onload to give the current page indication.

However, my preferred approach would be to use a similar technique that has been developed since Danny Doodman wrote that article (maybe by DG again, I don't know). The technique is called a "CSS sprite" and involves using (typically) just one image rather than one image per state. There are many articles, examples and turorials on CSS sprites, so I won't go into detail.

With sprites, to replicate DG's example you would (for example) have just one vertical, three-state image, which would provide the background to all the buttons. The text, Home, Products, Manuals etc. would be overlayed using raw HTML <a>links</a>, hence you get away with a single three-state image (not one per button or one per state).

CSS sprites will allow you to manage each button's state completely independently of the other buttons - which is exactly what you need to achieve what you are after.

Danny Goodman's technique is indeed a good one but things have moved on in this area. Learn the sprite technique and it will serve you well.

Hope this helps.

Airshow

Inside the switch(evt.type) {...} statement, you will need to replace this label case "mouseout" : ... with this one:

case : "click"
   imgStyle = document.getElementById( imgClass + "Over" ).style;
   imgStyle.clip = clipVal;
   imgStyle.visibility = "hidden";
   break;

and from the last part of the label after the case "mouseup" : ...break; add a new line of this:

default :
document.getElementById( imgClass + "Over" ).style.visibility = "hidden";
document.getElementById( imgClass + "Down" ).style.visibility = "hidden";
break;

Don't forget that all of this changes must stay inside the switch statement block.

Ess, please don't appologise. Your code may prove me to be completely wrong about needing to use another technique.

If you have time, read through my post and see if you can follow it. Maybe you can spot a flaw.

Airshow

Your post is considered more suitable for this issue, and offer comfortability of spending less time stripping out the entire code.

The Airshow's concise solution, signature...

wow, airshow - thanks so much for the detailed and encouraging response - you gave me a lot of things to consider - i'm going to try the sprite method you suggested - much obliged!!

hey essential - thanks so much for the suggestion - maybe that's where i went wrong using an 'onclick' case - what happened with that was the links stopped working - this might do it - you guys both are much appreciated. thanks! tania

hey essential - i did try inserting the snippets you suggested - i'm pretty sure the format is ok - inside the switch statement but the problem is that the whole rollover functionality disappeard and i still didn't get the menu highlight - can you advise?

Tanaquil,

Try this fairly light mod to the original O'Reilly code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Airshow :: Untitled</title>
<style type="text/css">
.rollover { height:110px; width:680px; border-width:0; position:absolute; top:0px; left:0px; visibility:hidden; }
#menubarUp { visibility:visible; }
</style>

<script>
var thisPageArea;
function initMaps(map, thisPageId) {
	var i, areas, area;
	areas = document.getElementById(map).getElementsByTagName("area");
	for(i=0; i<areas.length; i++) {
		areas[i].onmousedown = imgSwap;
		areas[i].onmouseout = imgSwap;
		areas[i].onmouseover = imgSwap;
		areas[i].onmouseup = imgSwap;
	}
	thisPageArea = areas[thisPageId];
	imgSwapIt(thisPageArea, "mouseover");
}

function imgSwap(evt){
	evt = evt || event;
	var elem = evt.target || evt.srcElement;
	imgSwapIt(elem, evt.type);
	evt.cancelBubble = true;
	return false;
}

function imgSwapIt(elem, type) {
	var imgClass = elem.parentNode.name;
	var coords = elem.coords.split(",");
	var clipVal = "rect(" +
		coords[1] + "px " +
		coords[2] + "px " +
		coords[3] + "px " +
		coords[0] + "px)";
	switch (type) {
		case "mousedown" :
			var imgStyle = document.getElementById(imgClass + "Down").style;
			imgStyle.clip = clipVal;
			imgStyle.visibility = "visible";
		break;
		case "mouseout" :
			document.getElementById(imgClass + "Over").style.visibility = "hidden";
			document.getElementById(imgClass + "Down").style.visibility = "hidden";
			imgSwapIt(thisPageArea, "mouseover");
		break;
		case "mouseover" :
			var imgStyle = document.getElementById(imgClass + "Over").style;
			imgStyle.clip = clipVal;
			imgStyle.visibility = "visible";
		break;
		case "mouseup" :
			document.getElementById(imgClass + "Down").style.visibility = "hidden";
			if (elem.click) {
				elem.click();
			}
		break;
	}
}

onload = function(){
	initMaps('menubarMap', 2);
}
</script>
</head>

<body>

<div style="position:relative">
	<img id="menubarUp"   class="rollover" src="menubarUp.jpg"   alt="menubar" usemap="#menubar" />
	<img id="menubarOver" class="rollover" src="menubarOver.jpg" alt="menubar" usemap="#menubar" />
	<img id="menubarDown" class="rollover" src="menubarDown.jpg" alt="menubar" usemap="#menubar" />
</div>

<map id="menubarMap" name="menubar">
<area shape="rect" coords="8,22,117,86" href="index.html" alt="new" title="new" />
<area shape="rect" coords="120,22,227,86" href="products.html" alt="products" title="view products" />
<area shape="rect" coords="230,22,337,86" href="manuals.html" alt="manuals" title="download manuals" />
<area shape="rect" coords="340,22,447,86" href="dealers.html" alt="dealers" title="find a dealer" />
<area shape="rect" coords="450,22,557,86" href="support.html" alt="support" title="get support" />
<area shape="rect" coords="560,22,667,86" href="contact.html" alt="contact" title="contact us" />
</map>

</body>
</html>

NOTES:

  1. initMaps() is purged of its outer for loop (it's not necessary) and otherwise tidied up.
  2. initMaps() is passed a second parameter representing the index of the current page (in the example I pass 2 for the third button, "Manuals").
  3. A global variable thisPageArea is daclared, and set within initMaps() to represent the area corresponding to the current page.
  4. A large part of function imgSwap() is moved into a separate function imgSwapIt() , which is free from the evt parameter.
  5. The new function imgSwapIt() is called from three places:
    • within imgSwap() to give the original functionality
    • within initMaps() to give the current page area its "mouseover" appearance on intialisation
    • within itself (single level recursion) to give the current page area back its "mouseover" appearance on mouseout of all buttons.
  6. Styles moved from inline to style sheet and simplified.

Notwithstanding my ealier post, the effect is efficient and not unpleasing, and may be what what you want.

Change "mouseover" to "mousedown", in two places for a slightly different effect.

Airshow

hi airshow - thank you forthe thoughtful reply. it will take me abit to understand what you're suggesting as wel as i can but i am confident it will work - i'll update this post when i try implementing it - in the meantime - thanks again!
tania

This article has been dead for over six months. Start a new discussion instead.