reptile7's JavaScript blog
Sunday, August 31, 2008
 
lowEndMapcreate
Blog Entry #124

An image of a monkHorizontal crosshairVertical crosshair

The previous post presented a method of returning coordinates for image-map subregions based on the client-side event object and its clientX/clientY properties, and driven by user mouse clicks; we'll refine this method in today's post via the use of movable crosshairs.

Creating, positioning, and monitoring the crosshairs

We can very easily create crosshairs for overlying an image from the 2px-by-2px 'colored dot' images that Joe makes available in HTML Goodies' "So, You Want A 1 X 1 Image, Huh?" tutorial. For example, for spanning the 262px-by-255px "So You Want A Client-Side Image Map, Huh?" monk.gif image above, we can 'stretch' Joe's blue.gif image horizontally and vertically as follows:

<img id="horizcross" width="262" height="1" src="blue.gif" alt="Horizontal crosshair">

<img id="vertcross" width="1" height="255" src="blue.gif" alt="Vertical crosshair">

The crosshairs can be positioned statically in the usual CSS way; if monk.gif and the crosshair images are wrapped in, say, a positioned div element, then

#horizcross { position: absolute; left: 0px; top: 128px; }
#vertcross { position: absolute; left: 131px; top: 0px; }

will 'quadrisect' monk.gif with the crosshairs as shown above. However, in order to move the crosshairs dynamically (vide infra), I find that the left and top values must be set scriptically:

var xcross, ycross;
if (document.getElementById) {
xcross = document.getElementById("vertcross");
ycross = document.getElementById("horizcross");
xcross.style.left = "131px";
xcross.style.top = 0;
ycross.style.left = 0;
ycross.style.top = "128px";
/* You can also set the position values this way if you prefer:
xcross.style.position = "absolute"; ycross.style.position = "absolute"; */ }

Form input fields provide a convenient way to monitor the crosshair positions:

<form action="">
x-coordinate: <input size="5" name="xcoord"><br>
y-coordinate: <input size="5" name="ycoord">
</form>

In practical terms, the xcoord and ycoord fields will display the coordinates of the crosshair intersection. The following script code loads the initial crosshair positions into the xcoord and ycoord fields:

var xposition, yposition;
xposition = parseInt(xcross.style.left);
yposition = parseInt(ycross.style.top);
document.forms[0].xcoord.value = xposition;
document.forms[0].ycoord.value = yposition;

Are you with me so far?

An image of a monkHorizontal crosshairVertical crosshair
x-coordinate:
y-coordinate:

Moving the crosshairs

For pinpointing the precise coordinates of desired image-map subregions, the crosshairs can be moved statically - change the CSS, reload the page, change the CSS, reload the page, etc. - very tedious, needless to say. It would be much better if we could simply drag the crosshairs to where we want them to be, and this is easily achievable via the capture of user mousemoves at the document object level. (My inspiration for this idea: the 'cat chases the mouse' script of HTML Goodies' JavaScript Script Tip #91.) As described in Blog Entry #108, we can use a

document.onmousemove = moveCrosshairs;

assignment statement to coassociate the document object, a mousemove event, and a moveCrosshairs( ) function that (a) assigns the final coordinates of a mousemove event (e.clientX,e.clientY) to the positions of the crosshairs, in effect dragging the crosshairs to the near vicinity of the mouse cursor, and (b) loads the new crosshair positions into the xcoord and ycoord form fields:

function moveCrosshairs(e) {

e = e ? e : (event ? event : "");
if (e) { // If the browser supports the event object:

xcross.style.left = e.clientX;
document.forms[0].xcoord.value = parseInt(xcross.style.left);
ycross.style.top = e.clientY;
document.forms[0].ycoord.value = parseInt(ycross.style.top); } }

We'll roll out a demo in just a bit. The moveCrosshairs( ) conditional code comes from the Apple Developer Connection's "Supporting Three Event Models at Once" tutorial and allows the function to accommodate both Microsoft's event model and the Mozilla/W3C event model.

Older browsers

My code above is designed for 'modern' browsers that support the DOM getElementById( ) method. Regarding older browsers, both MSIE 4.x and Netscape 4.x do not support the getElementById( ) method but do support the event object, and given that some users somewhere out there are probably still using these browsers, I think, "Why not bring them into the loop if at all possible?"

MSIE 4.x

Only minor modifications are needed to get my code to work with MSIE 4.x, chief among them switching the document.getElementById references to document.all references:

xcross = document.getElementById ? document.getElementById("vertcross") : document.all("vertcross");
ycross = document.getElementById ? document.getElementById("horizcross") : document.all("horizcross");


Also: with MSIE 4.5 on my computer, in order (a) to get accurate xcoord/ycoord readings upon moving the crosshairs and (b) to ensure that the monitoring form appears below the monk.gif image, I found it necessary to wrap monk.gif, the crosshair images, and the monitoring form in an absolutely positioned div element anchored at the viewport origin, i.e., at left:0;top:0;. (In contrast, both MSIE 5.1.6 and Netscape 7.02 allowed me to wrap the images in a relatively positioned, "normal flow" div element without any problems.)

Netscape 4.x

More challenging, but doable. I'm not going to discuss this in detail, but here are the highlights:

(1) We noted in the previous entry that Netscape 4.x will not CSS-position the img element. To create movable crosshairs, I wrapped the horizcross and vertcross images in layer elements

<layer left="0" top="128" id="horizlayer"> ...Horizontal crosshair image... </layer>
<layer left="131" top="0" id="vertlayer"> ...Vertical crosshair image... </layer>

whose corresponding JavaScript objects have writable left and top properties.

(2) Recalling that for MSIE 4.x we placed monk.gif, the crosshair images, and the monitoring form in an absolutely positioned div element, we can access the div container, the horizlayer and vertlayer layers, and the monitoring form via the following hierarchy expressions:

document.layers[0] // For the div container
document.layers[0].document.layers["horizlayer"] // For the horizlayer layer
document.layers[0].document.layers["vertlayer"] // For the vertlayer layer
document.layers[0].document.forms[0] // For the monitoring form

Reference: see "The Layer Object" in Netscape's "Dynamic HTML in Netscape Communicator" resource.

(3) The following command enables mousemove capture at the document object level:

document.captureEvents(Event.MOUSEMOVE);

Demo

Use your mouse cursor to drag the crosshairs to wherever you might like them to be in the div below:

An image of a monkHorizontal crosshairVertical crosshair
x-coordinate:
y-coordinate:

August 2016 Update
In reconfiguring my original moveCrosshairDemo.html demo for a self-contained id="crosshairsdemo" div:
(a) It is necessary to replace the clientX reading with an offsetX reading and the clientY reading with an offsetY reading.
(b) The moveCrosshairs( ) function is associated not with the document as a whole but with the monk.gif image itself via a document.getElementById("img1").onmousemove = moveCrosshairs; assignment.
(c) A #crosshairsdemo { overflow: hidden; } styling keeps the blue.gif crosshairs visually within the div.
(d) The previous section notwithstanding, the MSIE 4.x/Netscape 4.x-accommodating code has been thrown out - no one should be using those browsers in this day and age.

The crosshairs will obviously allow you to delineate image-map subregions with greater precision than would mouse clicks alone. I again trust that you are up to the task of using the xcoord/ycoord readings to directly or indirectly set coords values for anchor/area elements.

Application

I've used my crosshair method to create an image map for the photograph below:

Mischief the CatMischief's headMischief's food bowlMischief's body

No, this is not my cat. His name is Mischief, and he lives in England. Move your mouse cursor over Mischief's head, body, or food bowl to pop up an appropriate alert( ) message.

<img src="Mischief.jpg" width="450" height="422" alt="Mischief the Cat" usemap="#catmap">
<map name="catmap">
<area shape="circle" coords="197,143,48" alt="Mischief's head"
onmouseover="window.alert('Hi - I\'m Mischief.');">
<area shape="circle" coords="156,356,59" alt="Mischief's food bowl" onmouseover="window.alert('You\'ll notice that my food bowl is empty.\nLet\'s get it filled!');">
<area shape="circle" coords="215,238,105" alt="Mischief's body" onmouseover="window.alert('Three stone - impressive, eh?');">
</map>

I thought it would be a good idea to wrap up our discussion of image maps with a look at a 'real-world example', so in the next post we'll check over the image maps appearing at http://www.time.gov/, the U.S. Government's "Official U.S. Time" Web site (if I make it through Gustav).

reptile7

Comments: Post a Comment

<< Home

Powered by Blogger

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