ImageMap {
field SFString defaultURL ""
field SFString defaultDescription ""
field MFString parameters []
field SFBool loadURL TRUE
field SFBool setDescription TRUE
eventIn SFVec2f texCoord
eventIn SFBool isActive
eventOut MFString descOver
eventOut SFInt32 choice_changed
field MFInt32 type []
field MFVec2f point []
field MFString url []
field MFString description []
}
MappedShape {
field SFString defaultURL ""
field SFString defaultDescription ""
field MFString parameters []
field SFBool loadURL TRUE
field SFBool setDescription TRUE
eventOut MFString descOver
eventOut SFInt32 choice_changed
field MFInt32 type []
field MFVec2f point []
field MFString url []
field MFString description []
exposedField SFNode material NULL
exposedField SFNode texture NULL
exposedField SFNode textureTransform NULL
exposedField SFNode geometry NULL
}
| meaning | value | vertex format |
|---|---|---|
| point | 0 | x,y |
| circle/ellipse | 1 | centerX,centerY radiusX,radiusY |
| rectangle | 2 | minX,minY maxX,maxY |
| polygon | vertices (>=3) | x1,y1 x2,y2 x3,y3 [ x4,y4 ... ] |
| end of list | -1 | N/A |
These PROTOs offer the same functionality as the server-side imagemap CGI script included with most HTTP servers, including points (nearest wins), rectangles, circles, and polygons. The code is written in both Java and JavaScript, so they will work on all browsers. Note that MappedShape is just a convenience wrapper around ImageMap, which is why they are grouped together here.
An example use of the MappedShape PROTO uses a rectangular area, two circular areas, a polygonal area, and two points. The rectangle, circles, and polygon are shown in green lines. The equivalent imagemap in HTML can be seen below (minus the points, which are not supported by netscape's client-side imagemaps).
| The texCoord eventIn should receive an MFVec2f, almost certainly from a TouchSensor. The PROTO is useless if it does not receive this event. |
| The isActive eventIn should receive an SFBool eventIn, probably from the same TouchSensor as the texCoord. This eventIn need not receive events, since its only function is to load a URL on a true value. The PROTO can be used to simply describe or choose based on the region it is over (see below). |
| The descOver eventOut is a single-element MFString chosen from the description (or the defaultDescription) field and is suitable for ROUT'ing to the set_string eventIn of a Text node. If setDescription is TRUE, that same description string will be sent to a Browser.setDescription() call (generally setting the status line of the HTML browser). |
| The choice_changed eventOut is an SFInt32 indicating which region (or point) was chosen. If gotourl is TRUE, an event is sent in response to every texCoord eventIn; if gotourl is FALSE, an event is sent in response to every TRUE isActive eventIn. It is suitable for ROUT'ing to the set_whichChoice eventIn of a Switch node. If no points are defined and we are not inside a region, the value will be -1. |
| If loadURL is TRUE, a TRUE isActive eventIn will trigger a Browser.loadURL() of the current URL (computed from the texCoord eventIn) with the parameters MFString field as its parameters argument. This allows an ImageMap to control another frame in the web browser. |
I have an imagemap to VRML converter, written (by John Messina) in perl (requires perl5) here. This converts an imagemap config file suitable for the server-side imagemap CGI script to an ImageMap node, with the additional information of the dimensions of the image on the first line of the file (e.g. for a 320 by 240 pixel image, the first line of the file should be #320x240). The specific information on how to convert files is below for the technical types and any imagemap tool vendors who might want to include VRML support in their products.
First of all, some information on the server-side imagemap CGI script config file format. Each (relevant) line contains one of the following (the second coordinate pair for a circle is any point on the circle):
To explain how to convert I will start with an imagemap file for a 250x250 pixel image:
#250x250 point point.html 250,250 poly poly.html 22,16 80,19 26,42 7,26 rect rect.html 14,58 54,96 circle circle.html 200,84 227,119
The first thing to notice is that while HTML browser imagemapping treats an image as a discrete grid of integer pixel locations from 0 to the width/height of the image in pixels with the origin at the top left, VRML treats an image as a continuous grid of floating point locations from 0.0 to 1.0 with the origin at the lower left. Converting a single point from image-space to texture-space requires the following two equations, with the exception of circles:
Circles are a special case in which we cannot represent them as they are represented in the original imagemap file format, i.e. center + point on circumference. The specifics of the problem involve the aspect ratio, causing circles to become ellipses unless the texture is exactly square. The equations for the circle are (note that radius is a temporary value and not needed in the resulting file):
The file now becomes:
default default.html point point.html 1.0,0.0 poly poly.html .088,.936 .32,.924 .104,.832 .028,.896 rect rect.html .056,.768 .216,.616 circle circle.html .8,.664 0.177,0.177
Now that we have converted all of the points, we concatenate them and place them in the point field. The URLs (except the default) go in the url field. Optional descriptions for each URL go in the description field. The default's URL goes in the defaultURL field and a description for the default URL goes in the defaultDescription field. We now have a node like this, missing the type field:
ImageMap {
defaultURL "default.html"
defaultDescription "The default"
type []
point [ 1.0,0.0
.088,.936 .32,.924 .104,.832 .028,.896
.056,.768 .216,.616
.8,.664 0.177,0.177 ]
url [ "point.html", "poly.html", "rect.html", "circle.html" ]
description [ "A point", "A polygon", "A rectangle", "A circle" ]
}
Filling in the type field is simple; a point becomes 0, a circle becomes 1, a rectangle becomes 2, and a polygon becomes its number of vertices. We also need to remember to end the list with a -1. Our type field is therefore
type [ 0, 4, 2, 1, -1 ]
...and we have a complete node.