Приглашаем посетить
Бианки (bianki.lit-info.ru)

Programming the Image and Map Elements

Programming the Image and Map Elements

Images and image maps are fully programmable in Internet Explorer 4.0. You can now change the SRC attribute and size of an image and modify, add, and remove Area elements from an image map. The object model also allows new images to be asynchronously downloaded in the background while the user interacts with the page. This section presents techniques for downloading images and for manipulating the Image element and associated image maps.

Image Animation

One common technique for animating images is to change the image as the mouse enters and exits the element. In Internet Explorer 4.0, this task is trivial—you use the onmouseover and onmouseout events on the Image element itself:

<IMG SRC="start.gif"
   ONMOUSEOVER="this.src = `over.gif';"
   ONMOUSEOUT="this.src = `start.gif';">

Netscape Navigator will ignore this code because it does not currently support onmouseover and onmouseout events on the Image element. Netscape Navigator does support these events on the Anchor element, however. Therefore, with a little forethought it is possible to re-create the preceding scenario in a more compatible way. By wrapping the Image element in an Anchor element, both Netscape Navigator 3.0 or later and Internet Explorer 4.0 will properly change the image:

<A HREF=""
      ONMOUSEOVER="document.myImage.src = `over.gif';"
      ONMOUSEOUT="document.myImage.src = `start.gif';">
   <IMG BORDER=0 NAME="myImage" SRC="start.gif">
</A>

The BORDER=0 attribute must be added so that the default anchor border is not drawn around the image. And while this technique does provide similar support in both Netscape Navigator and Internet Explorer, there is still one key difference. Because no size is supplied to the image, in Internet Explorer the container of the image is automatically resized to match the image and the surrounding contents are reflowed. In Netscape Navigator, the size of the image is fixed when the first image is loaded, so the next image is scaled to fit. To work around this discrepancy, either ensure that the images are the same size or provide width and height attributes on the Image element.

While the preceding code works, a noticeable delay might occur when the second image is initially downloaded. Dynamic HTML supports the ability to preload an image behind the page so that it is immediately available for use.

Image Sequencing

Timer events can be used instead of user-generated events to change an image. Dynamic HTML makes it simple to create an image sequencer that rotates images after a specified amount of time. Images can be preloaded using a special image constructor, and the Image element's SRC attribute can be dynamically changed.

The following code shows the application of this technique, a client-side billboard that cycles through images after a specified amount of time. This scenario uses unrecognized elements to define the list of advertisements. The advantages of this model are that new ads can be added and outdated ads can be removed without having to modify any code. Another technique used in this example is to preload the images before assigning the SRC attribute to ensure a smooth transition from image to image. An error recovery mechanism is included to skip an image if it fails to download.

<HTML>
   <HEAD>
      <TITLE>Ad Sequencing</TITLE>
      <!-- More ads can be added simply by extending this list. -->
      <ADLIST src="ad1.gif" duration=3000>
      <ADLIST src="ad2.gif" duration=5000>
      <ADLIST src="ad3.gif">
      <ADLIST src="ad4.gif" duration=1000>
      <SCRIPT LANGUAGE="JavaScript">
         var adSet = document.all.tags("ADLIST");
         adSet.current = 0;
         var nextImage = document.createElement("IMG");

         function preLoad() {
            // Get next image.
            // If an error occurs, skip to the next image.
            /* Always set up image event handlers before assigning the
               SRC attribute to ensure that no events are missed. */
            nextImage.onerror = preLoad;
            nextImage.src =
               adSet[adSet.current].getAttribute("src");
            // The duration attribute specifies how long the image is 
            // displayed.
            nextImage.duration =
               adSet[adSet.current].getAttribute("duration");
            if (null == nextImage.duration)  // If not specified, use
               nextImage.duration = 2000;    // default 2 seconds.
            if (++adSet.current == adSet.length)
               adSet.current = 0;            // Start over.
         }

         function skipImage() {
            // Check whether next image has been downloaded.
            if (nextImage.complete) {
               document.all.ad.src = nextImage.src;
               var duration = nextImage.duration;
               preLoad();
               window.tm = setTimeout(`skipImage()', duration);
            }
            else  // Quickly iterate until image is available.
               window.tm = setTimeout(`skipImage()', 10);
         }
         preLoad();
      </SCRIPT>
   </HEAD>
   <BODY ONLOAD="window.tm = setTimeout(`skipImage()', 1);"
         ONUNLOAD="clearTimeout(window.tm);">
      <IMG ID="ad" SRC="ad4.gif" STYLE="border:2px solid navy">
   </BODY>
</HTML>

Internet Explorer 4.0 also supports the construction of new images for background downloading using the new operator in addition to the createElement method. This operator is supported for compatibility with Netscape Navigator's JavaScript implementation. The new operator is a language-dependent technique for creating new elements. For example, in the preceding code, the line

nextImage = document.createElement("IMG");

can also be written as

nextImage = new Image();

However, because Netscape Navigator does not expose custom elements to scripts, the code for sequencing advertisements requires further modifications in order to run in Netscape Navigator: the information about the ad graphics needs to be stored by the script, most likely in an array, rather than in custom AdList elements.

Image Maps

Image maps specify different click regions on an image. The most common use for image maps is to create visual navigation maps. When the user clicks in a particular area of the image, the default action is to navigate the user to a specified page. Using the event model, you can override the default action with an alternative action.

Defining an Image Map

HTML provides two types of image maps: server-side and client-side. A server-side image map is specified simply by adding an ISMAP attribute to the image and creating an image map file on the server. When the user clicks on the image, the xy-coordinates are submitted to the server. The server-side image map has two inherent disadvantages: it generally requires a server round-trip, and it is not easily accessible because the click regions are not known to the browser or to scripts.

Client-side image maps use the Map element and have the advantage of not requiring a round-trip to the server. They also allow browsers to intelligently map and outline the click regions of the image. The Map element contains a set of Area elements that define the coordinates for each click region.

Map elements must be named in order to be associated with an image. Once the Map element is named, any number of images can be associated with it through the images' USEMAP attribute. The value for USEMAP must be specified as a link reference. For example, the following code associates an image with an image map named diagram:

<IMG SRC="diagram.gif" USEMAP="#diagram">

Client-side image maps and their syntax are demonstrated in the following examples. However, the complete syntax for defining a server-side or client-side image map is beyond the scope of this book. For details about image map syntax, refer to an HTML reference book or the Microsoft Web site (www.microsoft.com).

Image Maps and Events

You can place an image map anywhere in the document, independent of the image the map is associated with. Because multiple images can share a single image map, the Dynamic HTML object model maintains a special relationship between the image and its image map when firing events.

When an event is fired on an image map, the Area element receives the event, followed by the Map element, followed by the Image element the user clicked on. After the image receives the event, the event continues to bubble up through the image's parent elements. Thus, a single image map and events can be shared, or depending on the circumstances, the image itself can override or add its own behavior to the image map. Elements that contain the image map in the HTML source may never receive the events that originate in the image map.

Accessing the Image Map

An Image element's useMap property contains the name of the associated image map, prefixed with a # character. By removing the leading # character from the useMap property, you can access the image map. The useMap property is read/write, so it allows image maps to be dynamically associated with the image. The following code demonstrates a simple function for obtaining the associated image map from an Image element:

function getMap(elImage) {
   // Be sure that a map is specified for the image.
   if (null != elImage.useMap) {
      // Remove the leading # from the bookmark.
      var strMap = elImage.useMap.substring(1);
      // Return the element with the specified name.
      return document.all[strMap];
   }
   else
      return null;
}

A useful application of dynamically changing an image map is to provide a different level of granularity in a complex image or geographic map. Figure 9-4 shows how a set of items—in this case, cities and states—can be made more manageable by letting the user first define a subset of items of interest. This filtering technique becomes even more powerful when used to distinguish between multiple overlapping regions.

Because the cities in this image overlap the states, the user might find it difficult to make a selection. By allowing the user to decide between cities and states, selection becomes much simpler. This filtering is easily implemented by toggling between two image maps for the image, depending on the user's selection, as shown in the following code.

Programming the Image and Map Elements

Figure 9-4.

An image that can use two different image maps.

<HTML>
   <HEAD>
      <TITLE>Switching Image Maps</TITLE>
      <SCRIPT LANGUAGE="JavaScript">
         function setMap(mapName) {
            document.all.mapImage.useMap = mapName;
         }
      </SCRIPT>
   </HEAD>
   <BODY>
      <P>Select From:<BR>
         <INPUT TYPE=RADIO NAME="feature" ID="States" Value="#States"
            ONCLICK="setMap(this.value);" CHECKED>
         <LABEL FOR="States">States</LABEL><BR>
         <INPUT TYPE=RADIO NAME="feature" ID="Cities" Value="#Cities"
            ONCLICK="setMap(this.value);">
         <LABEL FOR="Cities">Cities</LABEL></P>
      <P><IMG ID="mapImage" SRC="places.gif" BORDER=0
         WIDTH=197 HEIGHT=448 USEMAP="#States"></P>
      <MAP NAME="Cities">
         <AREA SHAPE="POLYGON" HREF="la.htm"
            COORDS="108, 408, 164, 407, 165, 388, 111, 387,          --
               109, 361, 86, 361, 73, 394, 94, 411">
         <AREA SHAPE="POLYGON" HREF="sanfran.htm"
            COORDS="12, 301, 58, 275, 75, 305, 80, 301, 87, 314,     --
               92, 326, 119, 329, 121, 340, 45, 341, 44, 328,        --
               9, 328">
         <AREA SHAPE="POLYGON" HREF="portland.htm"
            COORDS="34, 120, 47, 120, 49, 115, 68, 115, 69, 123,     --
               86, 127, 86, 131, 140, 131, 137, 144, 86, 145,        --
               91, 162, 22, 160, 22, 148, 26, 144">
         <AREA SHAPE="POLYGON" HREF="seattle.htm"
            COORDS="73, 86, 93, 84, 92, 73, 125, 73, 123, 59,        --
               92, 57, 87, 43, 93, 22, 82, 2, 71, 21, 79, 45">
      </MAP>
      <MAP NAME="States">
         <AREA SHAPE="POLYGON" HREF="california.htm"
            COORDS="14, 204, 18, 200, 83, 209, 79, 278, 166, 386,    --
               171, 403, 167, 409, 166, 419, 163, 423, 164, 430,     --
               166, 436, 161, 439, 115, 438, 112, 433, 110, 420,     --
               97, 409, 92, 401, 82, 399, 77, 392, 56, 385, 54       --
               369, 46, 357, 46, 352, 34, 338, 39, 327, 35, 322,     --
               32, 309, 34, 297, 25, 297, 24, 288, 14, 273, 15,      --
               255, 9, 235, 12, 224, 12, 221, 16, 216">
         <AREA SHAPE="POLYGON" HREF="oregon.htm"
            COORDS="16, 199, 136, 216, 140, 178, 143, 171,           --
               138, 164, 153, 132, 147, 122, 103, 120, 80, 123,      --
               72, 121, 55, 121, 51, 109, 37, 105, 22, 163,          --
               23, 166, 18, 173, 14, 189">
         <AREA SHAPE="POLYGON" HREF="washington.htm"
            COORDS="33, 50, 64, 64, 57, 74, 57, 86, 63, 81,          --
               70, 65, 66, 41, 152, 55, 147, 123, 100, 119,          --
               86, 124, 74, 120, 56, 119, 51, 108, 40, 104,          --
               36, 99, 43, 93, 37, 87, 41, 84, 36, 80">
      </MAP>
   </BODY>
</HTML>


NOTE: The coordinate lists in the Area elements cannot be broken onto multiple lines or the code will not run correctly. The lists are broken in the preceding code in order to fit them on the page; artificial line break symbols (--) indicate line breaks that shouldn't appear in the actual code.

Accessing Area Elements

Dynamic HTML exposes the Area elements through the following collections:

Scripts can access the attributes of the Area element in any of these three ways in order to dynamically modify them. The Area element has an HREF attribute that contains a URL, and it exposes the same properties containing parts of that URL that the location and anchor objects expose. The areas collection provides the extra functionality of allowing new Area elements to be added and removed from the image map.

Dynamically modifying the coordinates and shapes within an image map is supported, but it is usually easier and more maintainable to define multiple image maps in the document and switch between them. The exception is when you can calculate the new click regions from the old by a simple transformation. For example, if an image can be scaled, it is easier to scale both the image and the image map. If a zoom function is supported on an image, any associated image map also needs to be zoomed with the image:

<HTML>
   <HEAD>
      <TITLE>Dynamically Scaling Image Maps</TITLE>
      <SCRIPT LANGUAGE="JavaScript">
         function getMap(elImage) {
            // Be sure that a map is specified for the image.
            if (null != elImage.useMap) {
               // Remove the leading # from the bookmark.
               var strMap = elImage.useMap.substring(1);
               // Return the element with the specified name.
               return document.all[strMap];
            }
            else
               return null;
         }

         function zoomImage(elImage, amount) {
            // Expand the image the specified amount.
            var elMap = getMap(elImage);
            elImage.width *= amount;
            elImage.height *= amount;
            // If an image map is available, scale it too.
            if (null != elMap) {
               for (var intLoop = 0; intLoop < elMap.areas.length;
                     intLoop++) {
                  var elArea = elMap.areas[intLoop];
                  // Break the coordinates string into an array.
                  var coords = elArea.coords.split(",");
                  var scaledCoords = "";
                  // Rebuild the new scaled string.
                  for (coord in coords) {
                     scaledCoords += (coords[coord] * amount) + ",";
                  }

                  // Put the scaled coordinates back into the map.
                  elArea.coords = scaledCoords;
               }
            }
         }

         function swapButtons(b1, b2) {
            // Swap the enabled/disabled buttons.
            document.all[b1].disabled = true;
            document.all[b2].disabled = false;
         }
      </SCRIPT>
   </HEAD>
   <BODY>
      <P>
         <INPUT TYPE=BUTTON VALUE="Zoom In"
            ONCLICK="zoomImage(document.all.img1, 2);
               swapButtons(`zoomin', 'zoomout');"
            ID="zoomin">
         <INPUT TYPE=BUTTON VALUE="Zoom Out"
            ONCLICK="zoomImage(document.all.img1, .5);
               swapButtons(`zoomout', 'zoomin');"
            ID="zoomout" DISABLED>
      </P>
      <P>
         <IMG SRC="img001.gif" WIDTH=200 HEIGHT=200
            ID="img1" USEMAP="#map1">
         <MAP NAME="map1">
            <AREA SHAPE="POLYGON"
               COORDS="92, 140, 126, 114, 155, 139, 124, 163"
               HREF="home.htm">
            <AREA SHAPE="CIRCLE" COORDS="30, 105, 30" HREF="cool.htm">
            <AREA SHAPE="RECT" COORDS="62, 28, 200, 79"
               HREF="dhtml.htm">
         </MAP>
      </P>
   </BODY>
</HTML>

Adding and Removing Area Elements

Using the areas collection, Dynamic HTML supports the ability to dynamically add and remove Area elements from an image map. The technique for creating a new Area element is the same as for creating a new image. The primary difference is that this new Area element can be added directly to an existing map's areas collection, whereas a new image object cannot be added to the document.

The areas collection exposes add and remove methods. The add method takes an Area element created with the createElement method and adds it to the areas collection. The remove method is used to remove an existing Area element from the image map. The following example is a simple image map editor written entirely in HTML:

<HTML>
   <HEAD>
      <TITLE>Image Map Editor</TITLE>
      <SCRIPT LANGUAGE="JavaScript">
         var curFocus = null;

         function areaFocus() {
            // Track the last Area element selected.
            if ("AREA" == event.srcElement.tagName)
               curFocus = event.srcElement;
         }

         function removeArea() {
            // Remove an Area element.
            var coll = document.all.dynaMap.areas;
            if (null != curFocus) // Make sure one is selected.
               // Loop over Area elements and find the one selected.
               for (var intLoop = 0; intLoop < coll.length; intLoop++)
                  if (curFocus == coll[intLoop]) {
                     document.all.dynaMap.areas.remove(intLoop);
                     return;
                  }
            alert("No Area element is selected.");
         }

         function addArea(f) {
            /* Be sure that coordinates are specified. This code does
               not perform any extra validation for the coordinates. */
            if ("" != f.coordinates.value) {
               var elArea = document.createElement("AREA");
               elArea.coords = f.coordinates.value;
               // Determine shape selected.
               for (var intLoop = 0; intLoop < f.shape.length;
                     intLoop++)
                  if (f.shape[intLoop].checked)
                     elArea.shape = f.shape[intLoop].id;
               document.all.dynaMap.areas.add(elArea);
            }
            else
               alert("You need to enter a Coords value.");
            event.returnValue = false;
         }
      </SCRIPT>
   </HEAD>
   <BODY>
      <H1>Image Map Editor</H1>
      <H2>Select a Shape</H2>
      <FORM NAME="area">
         <!-- The ID is used to determine the shape attribute. -->
         <P>
            <INPUT TYPE=RADIO NAME="shape" ID="rect" CHECKED>
            <LABEL FOR="rect">Rect</LABEL>
         <BR>
            <INPUT TYPE=RADIO NAME="shape" ID="polygon">
            <LABEL FOR="polygon">Polygon</LABEL>
         <BR>
            <INPUT TYPE=RADIO NAME="shape" ID="circle">
            <LABEL FOR="circle">Circle</LABEL>
         </P>
         <P>
            <LABEL FOR="coords">Coords</LABEL>
            <INPUT TYPE=TEXT ID="coords" NAME="coordinates">
         </P>
         <P>
            <INPUT TYPE=SUBMIT VALUE="Add Area"
               ONCLICK="addArea(this.form)">
            <INPUT TYPE=BUTTON VALUE="Remove Area"
               ONCLICK="removeArea()">
         </P>
      </FORM>
      <IMG SRC="img001.gif" WIDTH=200 HEIGHT=200 USEMAP="#dynaMap">
      <MAP NAME="dynaMap" ONCLICK="areaFocus()">
      </MAP>
   </BODY>
</HTML>

[Содержание]