reptile7's JavaScript blog
Thursday, August 21, 2008
 
Image Maps: Then and Now
Blog Entry #123

The map element and the area element were introduced in 'HTML 3'; the W3C discusses them here in the HTML 3.2 Specification. (Had Microsoft or Netscape implemented them proprietarily before that? I don't know.) In its original incarnation, the map element had a more restrictive content model than it does now; specifically, it could only contain area elements:

<!ELEMENT MAP - - (AREA)+>
<!-- Recall that the area element is an empty element that does not contain other elements or even text. -->

As noted two entries ago, the map element can now hold block-level elements for containing anchor elements that define the map's subregions. And given that area elements do not have an external-to-the-image rendering (e.g., in a visual context, area elements do not generate inline boxes before or after the image) whereas anchor elements do, the W3C prefers that you build your map elements with anchor elements: Authors should use this method to create more accessible documents. Accordingly, most of the W3C's client-side image map examples feature map elements composed of anchor elements wrapped in p elements. (Another relevant example: check out this page's map image map, whose subregion-defining anchor elements appear as items in an unordered list (ul element).)

Let's get back now to the monkareas image map of HTML Goodies' "So You Want A Client-Side Image Map, Huh?" tutorial. I don't know when exactly this tutorial was written, but it is clearly of the 'HTML 4 era' and does not date to the 'HTML 3 era' because the monkareas map contains a shape="default" area element; default was not a valid value for the shape attribute in HTML 3.2:

<!-- From the post's first link, the shape attribute's data type designation is %SHAPE, whose declaration is: -->
<!ENTITY % SHAPE "(rect|circle|poly)">

So Joe definitely could have formulated the monkareas map in terms of anchor elements had he wanted to, for example:

<map name="monkareas">
<p>
<a shape="rect" coords="91,30,186,98" href="http://www.nfl.com">NFL.com</a> |
<a shape="circle" coords="25,72,28" href="http://www.cnn.com">CNN.com</a> |
<a shape="poly" coords="9,115, 86,79, 98,116, 69,131, 86,175, 48,206" href="http://www.usatoday.com">USATODAY.com</a> |
<a shape="circle" coords="107,158,132" href="http://www.cbs.com">CBS.com</a> |
<a shape="default" href="http://www.htmlgoodies.com">HTML Goodies</a>

</p>
</map>
<!-- N.B.: The alt attribute is shared by the area, img, and input elements but is not valid for the anchor element. -->

Understandably, the first wave of browsers to support image maps did not support anchor element-based image maps - on my iMac, I can confirm that Internet Explorer 4.5, Netscape 4.79, and Opera 6.03 do not apply the preceding map to the monk.gif image - and Joe almost certainly used area elements in his map in order to accommodate such browsers. But this isn't an 'either/or situation', at least with respect to HTML. The W3C notes, Authors may wish to mix content so that older user agents will handle map geometries specified by area elements and new user agents will take advantage of richer block content; in other words, we can load all of Joe's area elements and my anchor elements - the whole shebang - into a single map element for maximum browser support:

<map name="monkareas">
<p>
<a shape="rect" coords="91,30,186,98" href="http://www.nfl.com">NFL.com</a> |
<a shape="circle" coords="25,72,28" href="http://www.cnn.com">CNN.com</a> |
<a shape="poly" coords="9,115, 86,79, 98,116, 69,131, 86,175, 48,206" href="http://www.usatoday.com">USATODAY.com</a> |
<a shape="circle" coords="107,158,132" href="http://www.cbs.com">CBS.com</a> |
<a shape="default" href="http://www.htmlgoodies.com">HTML Goodies</a>
</p>
<area shape="rect" coords="91,30,186,98" href="http://www.nfl.com" alt="NFL Home Page">
<area shape="circle" coords="25,72,28" href="http://www.cnn.com" alt="CNN Home Page">
<area shape="poly" coords="9,115, 86,79, 98,116, 69,131, 86,175, 48,206" href="http://www.usatoday.com" alt="USA TODAY Home Page">
<area shape="circle" coords="107,158,132" href="http://www.cbs.com" alt="CBS Home Page">
<area shape="default" href="http://www.htmlgoodies.com" alt="HTML Goodies Home Page">

</map>

Here's what we get when we apply our new-and-improved monkareas map to the monk.gif image:

An image of a monk

NFL.com | CNN.com | USATODAY.com | CBS.com | HTML GoodiesNFL Home PageCNN Home PageUSA TODAY Home PageCBS Home PageHTML Goodies Home Page

Validation note
Block-level content and area elements cannot be validly mixed in a map element in XHTML. Consider the HTML 4.01 and XHTML 1.0 map element content models:

HTML 4.01: <!ELEMENT MAP - - ((%block;) | AREA)+ -- client-side image map -->
XHTML 1.0: <!ELEMENT map ((%block; | form | %misc;)+ | area+)>

The difference in the respective positions of the + quantifiers in these content models is crucial:
• For HTML, the external quantifier of ((%block;) | AREA)+ means that the map element can contain one or more block-level elements or area elements, i.e., mixing block-level content and area elements is OK.
• For XHTML, the internal quantifiers of ((%block; | form | %misc;)+ | area+) mean that the map element can contain one or more block-level elements OR one or more area elements, but not both.



Using mouse clicks to define image-map subregions

In justifying his use of the Mapedit program to create the monkareas map, Joe laments, It's impossible to eyeball the size of the map and pick out points. Impossible? Not with a bit of help from the browser. In this section, I'll describe a quick-and-dirty method for nailing down map coordinates via the 'capture' of mouse clicks. Here's what you do, it's real simple:

(1) Put the image to be mapped in a separate file and push the image into the document content area's upper-left-hand corner so that the viewport and image x-y coordinate systems line up:

img { position: absolute; left: 0px; top: 0px; }

<img src="myImage.gif" alt="Alternate text">

(2) Add the following event handler to the img tag:

onclick="window.alert('The x-coordinate is: ' + event.clientX + '\nThe y-coordinate is: ' + event.clientY);"

(We previously discussed the cross-browser clientX and clientY properties of the event object in Blog Entry #108.)

That's it! Now, with the preceding code in place, click on the image - each click pops up an alert( ) message giving the click coordinates, e.g.:

An alert( ) box showing the coordinates of a click on the image

These coordinates can be used to set the coords attribute values for rect, circle, and poly shapes in the anchor and/or area elements of your image map - I trust you can take it from here.

This method should work for all browsers that support the event object except Netscape 4.x, which (a) does not support the CSS position, left, or top properties* (or most other CSS properties, for that matter), (b) does not support the clientX/clientY event object properties, and (c) supports onclick for the button, document, checkbox, link, radio, reset, and submit objects but not for the image object - what a party pooper, huh? (*Hold it - later experimentation has revealed that Netscape 4.79 does in fact apply these properties to a variety of block-level and inline elements, just not to the img replaced element.) But don't despair, Netscape 4.x users - here's what you can do instead to achieve the same effect:

(1) Wrap the img element in a layer element:

<layer><img src="myImage.gif" alt="Alternate text"></layer>

(2) Use the event object's layerX and layerY properties** and event capture at the document object level to capture mouse clicks on the image via the following script, which can be placed before or after the layer element:

<script type="text/javascript">

if (document.layers) {
document.captureEvents(Event.CLICK);
document.onclick = getCoords;

function getCoords(e) {
window.alert("The x-coordinate is: " + e.layerX + "\nThe y-coordinate is: " + e.layerY); } }

</script>

**Use of the layerX/layerY properties (as opposed to the event object's pageX/pageY properties) renders unnecessary the lining up of viewport and layer/image coordinate systems.

You can try out the above code for yourself by clicking on the monk.gif image in the div below:

An image of a monk

In the next entry, I'll outline an alternate, crosshair-based method of determining coordinates for image-map subregions.

reptile7

Comments: Post a Comment

<< Home

Powered by Blogger

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