Chapter 8

Form Modification


CONTENTS

Form modification is the process by which data entered by a user is translated into another format before being submitted to the form's server. When data from a form is submitted to its server, the data has to be formatted in a way that the server can understand. The format is usually in the form

<url>?<field1=value>?<field2=value>...

where <field1>, <field2>, and so forth are the NAME attributes of the INPUT, SELECT, and TEXTAREA elements of the form. The values are, with minor translations made by the browser, the VALUE attributes of those elements.

So why would you need to go to the trouble of form modification? Because the format of the values and the fields are not necessarily very user friendly. If you have to create a Web page to interface to such a server and you have no control over the server's input requirements, you can use form modification to create a superior, easier-to-use Web page.

The scenario

The United States Department of Commerce Bureau of the Census operates the Tiger Map Service. The Tiger Map Service defines a URL, http://tiger.census.gov/cgi-bin/mapgen, and a set of field-value pairs that can be specified. The server responds with a GIF file that displays a made-to-order map specified by the field-value pairs.

The interface defines a very rich set of field-value pairs. One of these actually allows you to shorten the data sent to the server by defining a URL that contains additional field-value pairs. The critical set of pairs, however, define the area that the map will display. These are

These four field-value pairs define the longitude (east-west coordinate), the latitude (north-south coordinate), and the width and height of the area displayed by the map. The values are specified in decimal degrees; you would specify a latitude of 38 degrees, 45 minutes to the server as 38.75 degrees, for example.

Naturally, this scenario requires a Web page with a form for creating a map GIF file.

The requirements

The typical user will want to look at famous U.S. landmarks or at his or her hometown. The typical user will also have, at best, a vague idea of the coordinates of the location he or she wants to see. (You can check a map to get a general idea of the coordinates you need.) The user will usually have no idea at all how to set the width and height to capture the desired level of detail. The greater the values of the wid and ht fields, the larger the area displayed in the map and the less detail displayed. But how small should these field values be to get the desired level of detail? Most users won't know and will need to experiment to get the desired results.

For these reasons, the Web page should let users enter the coordinates and height and width fields as easily as possible, and should make it easy for them to change the fields and try again.

The solution (without JavaScript)

To capture the required fields, you need four INPUT elements with NAME attributes of lat, lon, wid, and ht. To give the user a reasonable map size, let's add iht and iwd fields. These fields describe the image height and image width; both values are specified in pixels. You can make them HIDDEN type INPUT elements, and give them fixed values. Let's use an image area 320 pixels wide and 200 pixels high.

The rest of the Web page has the standard HTML/HEAD/BODY structure, with the fields contained in a FORM element. The FORM ACTION attribute needs to be specified as "http://tiger.census.gov/cgi-bin/mapgen" and the METHOD attribute should be "GET." Listing 8.1 contains the code for this Web page.


Listing 8.1: HTML for non-JavaScript solution
<HTML>
    <HEAD>
        <TITLE>Map Service</TITLE>
    </HEAD>
    <BODY>
        <PRE>
            <FORM ACTION="http://tiger.census.gov/cgi-bin/mapgen"
              METHOD="GET">
Longitude:    <INPUT NAME="lon" TYPE="text" SIZE=1Ø>
Latitude:     <INPUT NAME="lat" TYPE="text" SIZE=1Ø>
Width:        <INPUT NAME="wid" TYPE="text" SIZE=1Ø>
Height:       <INPUT NAME="ht"  TYPE="text" SIZE=1Ø>
<INPUT NAME="iwd" TYPE="hidden" VALUE="32Ø">
<INPUT NAME="iht" TYPE="hidden" VALUE="2ØØ">
<INPUT TYPE="submit"><INPUT TYPE="reset">
            </FORM>
        </PRE>
    </BODY>
</HTML>

Figure 8.1 shows the form with some sample values entered, and Figure 8.2 shows the map GIF file that the server returned as a result.

Figure 8.1 : Non-JavaScript form with sample values.

Figure 8.2 : Result of submitting data from Figure 8.1.

The solution (with JavaScript)

One problem with the Tiger Map Service interface is that it uses decimal degrees. Unfortunately, that doesn't tie in very well with most sources of map data, which usually specify locations in terms of degrees, minutes, and seconds.

Even worse is the fact that most people have no idea how much real estate is covered by one degree of latitude or longitude, or one minute, or one second. How is the average user going to know what to specify for the height and width of the area?

You need a more intuitive interface than the server allows.

First, the user has to be able to specify the latitude and longitude in conventional terms of degrees, minutes, and seconds. Second, you need a more intuitive way to manage the area's height and width. Given that one of the requirements of this page is to make it easy to change these values, let's start with an arbitrary height and width of one degree, and let the user modify the height and width by zooming in and out. Zooming in will be defined as cutting the height and width in half, which places one quarter the area (more or less) in the same image size. Zooming out will be defined as doubling the height and width, placing four times the area in the same image size.

Finally, you can add buttons to allow the user to fine-tune the center coordinates. That will further meet the requirement of allowing the user to easily make quick changes to the map.

You do all this by creating two FORM elements. The first FORM element is very similar to the FORM element in Listing 8.1. There is one big difference: The INPUT elements are HIDDEN type instead of TEXT, and the descriptive text is removed, making the form invisible.

The second FORM element is the form the user will see. It has two BUTTON INPUT elements, one to execute the zoom in and one to execute the zoom out. There is also a TEXT INPUT element for displaying the current magnification factor. This element is useful because the server sometimes cannot meet the request and a "Sorry, Busy" GIF image appears instead of the requested map. Once users have more or less zeroed in on the area of choice, they tend to keep zooming in, and may not recall how far they have zoomed in. Displaying the magnification factor helps them keep track of how far they have zoomed in. This visual feedback helps if the user zooms in but doesn't get a map because the server is busy. There is at least a clue that maybe the user should press the GO! button instead of pressing the Zoom In button again.

In addition to the zoom controls, there are three TEXT INPUT elements for the latitude (one for degrees, one for minutes, and one for seconds) and three for the longitude. There are also four BUTTON INPUT elements that allow the user to make small adjustments to the map, moving it to the west, north, east, or south.

Finally, there is a BUTTON INPUT element to act as a submit button and a RESET INPUT element. You don't want a real SUBMIT INPUT element, because the data in this FORM element is not going to be sent to a server.

Laying Out the Controls

There are a lot of controls for this Web page: seven BUTTON INPUT elements, seven TEXT INPUT elements, and a RESET INPUT element. If you put them in a TABLE element, you can manage them better.

Let's start with one TABLE element. It, in turn, will contain three TABLE elements-one for the zoom controls, one for the location controls, and one for the submit and reset controls. The TABLE element will be inside the FORM element, and the TABLE HTML will look something like this:

<FORM>
    <TABLE>
        <TR>
            <TD>
                <TABLE>
                </TABLE>
            </TD>
            <TD>
                <TABLE>
                </TABLE>
            </TD>
            <TD>
                <TABLE>
                </TABLE>
            </TD>
        </TR>
    </TABLE>
</FORM>

This code describes a TABLE element with a single TABLE ROW (TR) element. The TABLE ROW element contains three TABLE DATA (TD) elements. Each TABLE DATA element contains a TABLE element. This produces an effect of three TABLE elements lined up side by side, as shown in Figure 8.3.

Figure 8.3 : Gross table structure.

The first TABLE element will contain the zoom controls. It looks like this:

<TABLE>
    <TR>
        <TD>
            <INPUT TYPE="button" VALUE="ZOOM IN">
        </TD>
    </TR>
    <TR>
        <TD>
            <INPUT TYPE="text" NAME="mag" SIZE=4>
        </TD>
    </TR>
    <TR>
        <TD>
            <INPUT TYPE="button" VALUE="ZOOM OUT">
        </TD>
    </TR>
</TABLE>

This code creates three rows, with one data cell each. The top cell contains the ZOOM IN button, the middle cell contains the magnification factor display, and the bottom cell contains the ZOOM OUT button, as you can see in Figure 8.4.

Figure 8.4 : Zoom controls.

The second table contains the location controls. The layout of the table is like this:

<TABLE>
    <TR>
        <TD>
            East/West <INPUT TYPE="text" NAME="londeg" SIZE=4><INPUT TYPE="text" 
            NAME="lonmin" SIZE=2><INPUT TYPE="text" NAME="lonsec" SIZE=1Ø>
        </TD>
        <TD ROWSPAN="2">
            <TABLE>
            </TABLE>
        </TD>
    </TR>
    <TR>
        <TD>
        North/South <INPUT TYPE="text" NAME="latdeg" SIZE=2><INPUT TYPE="text" 
        NAME="latmin" SIZE=2><INPUT TYPE="text" NAME="latsec" SIZE=1Ø>
        </TD>
    </TR>
</TABLE>

This code creates three cells in two rows-two cells on the left (one top cell and one bottom cell) and a third cell on the right that's the height of the other two cells combined as shown in Figure 8.5.

Figure 8.5 : Location controls.

The two left-hand cells provide the TEXT INPUT elements for entering the longitude (east-west coordinate) and the latitude (north-south coordinate). The large cell on the right contains another TABLE element that will contain the east-north-west-south adjustment buttons.

The adjustment controls TABLE is laid out like this:

<TABLE>
    <TR>
        <TD>
        </TD>
        <TD>
            <INPUT TYPE="button" VALUE="N">
        </TD>
        <TD>
        </TD>
    </TR>
    <TR>
        <TD>
            <INPUT TYPE="button" VALUE="W">
        </TD>
        <TD>
        </TD>
        <TD>
            <INPUT TYPE="button" VALUE="E">
        </TD>
    </TR>
    <TR>
        <TD>
        </TD>
        <TD>
            <INPUT TYPE="button" VALUE="S">
        </TD>
        <TD>
        </TD>
    </TR>
</TABLE>

This layout produces a simple compass star, as shown in Figure 8.6.

Figure 8.6 : Compass controls.

Finally, the third table contains the submit and reset controls, as laid out here:

<TABLE BORDER="Ø" CELLPADDING="2">
    <TR>
        <TD>
            <INPUT TYPE="button" VALUE="GO!">
        </TD>
    </TR>
    <TR>
        <TD>
            <INPUT TYPE="RESET">
        </TD>
    </TR>
</TABLE>

You can see these controls in Figure 8.7.

Figure 8.7 : The map controls.

Laying Out the Window

Having organized the new FORM element's contents for the screen, you need to give some thought to the setup of the overall screen. One of the problems with the non-JavaScript implementation is that the map replaces the form on the screen; to return to the form data, the user has to use the BACK button. At no time can the user see the data and the map together. You can fix this shortcoming by using frames:

<HTML>
    <HEAD>
        <TITLE>Tiger Map Service</TITLE>
    </HEAD>
    <FRAMESET ROWS="22Ø, *">
        <FRAMESET COLS="*,35Ø,*">
            <FRAME NAME="leftBorder" SRC="wall.htm">
            <FRAME NAME="viewer" SRC="view.htm">
            <FRAME NAME="rightBorder" SRC="wall.htm">
        </FRAMESET>
        <FRAME NAME="control" SRC="mapctrl.htm">
        </FRAME>
    </FRAMESET>
</HTML>

This frame document divides the screen vertically into an upper frame 220 pixels high and a lower frame that occupies the remainder of the screen. The FORM elements will be in the lower frame. The 220 pixel height of the top frame allows most browsers to display the 200 pixel high image without a scroll bar. The top frame is then subdivided vertically into a 350 pixel wide frame flanked by two frames on either side. The 350 pixel width of the viewer frame allows most browsers to display the 320 pixel wide image without a scroll bar. Figure 8.8 shows the resulting screen.

Figure 8.8 : JavaScript solution with map displayed.

<FORM NAME="realForm" ACTION="http://tiger.census.gov/cgi-bin/mapgen"
        METHOD="GET" TARGET="viewer">

The TARGET attribute tells the browser to display the submission results in the viewer frame. Without that, the results would replace the contents of the control frame, and the user would lose his or her view of the data.

Adding Functionality to the Controls

With the two FORM elements defined, the data entered into the second FORM element has to wind up, in modified format, in the first FORM element. This will require event handlers for some of the INPUT elements in the second FORM element.

BUTTON type elements are the easiest INPUT elements to use. The ONCLICK event is very understandable to users, much more so than ONCHANGE, ONFOCUS, and ONBLUR events, which have subtle differences in their behavior from one platform to another. A mouse click behaves pretty much the same on all platforms.

The jobs of the ONCLICK event handlers depend on the BUTTON elements they work on. The GO! and ZOOM controls should display a new map. The compass controls should modify the contents of the longitude or latitude fields, but should not display a new map. The user may want to use more than one compass control to move the image further east and further north, for example, and will not want to wait between adjustments for the wrong area to be displayed.

The E and W buttons can share a function; they both adjust the longitude, just in opposite directions. Similarly, the N and S buttons can share a function. Let's call these functions changeLongitude() and changeLatitude(). Called with a negative value, changeLongitude() moves the center of the picture west and changeLatitude() moves the center of the picture south. Called with a positive value, changeLongitude() moves the center of the picture east and changeLatitude() moves the center of the picture north.

The two functions are nearly identical; this is changeLongitude():

function changeLongitude(dir)
    {
    var delta = Ø.1 / getMagnification();
    var longitude = getLongitude();
    if (dir < Ø)
        {
        longitude -= delta;
        }
    else
        {
        longitude += delta;
        }
    setLongitude(longitude);
    }

The current magnification factor is obtained by a call to getMagnification() and a value of one-tenth of a degree is divided by the magnification factor. Because the image spans a degree divided by the magnification factor, this is a delta of one tenth of the image. The longitude is then obtained by a call to getLongitude(). The delta is either subtracted from it or added to it. The new longitude is written back out with setLongitude().

The changeLatitude() function is identical except that it deals with latitude instead of longitude.

The getMagnification() function obtains the value from the TEXT INPUT element named "mag":

function getMagnification()
    {
    var magnification = 1;
    if (document.showForm.mag.value.length != Ø)
        {
        magnification =
            Math.abs(parseFloat(document.showForm.mag.value));
        if (magnification == Ø)
            {
            magnification = 1;
            }
        }
    return magnification;
    }

The return value is set to 1 as a default. If anything is entered on screen, parseFloat() is called to evaluate the contents. The absolute value of the result is taken-a negative magnification factor doesn't make sense. If the result is 0, the value is replaced with the default value of 1.

The getLongitude() function calculates a decimal longitude from the three TEXT INPUT elements in which the user has entered the longitude in degrees, minutes, and seconds:

function getLongitude()
    {
    var londeg = Ø;
    if (document.showForm.londeg.value.length != Ø)
        {
        londeg = Math.abs(parseInt(document.showForm.londeg.value));
        }
    var lonmin = Ø;
    if (document.showForm.lonmin.value.length != Ø)
        {
        lonmin = Math.abs(parseInt(document.showForm.lonmin.value));
        }
    var lonsec = Ø;
    if (document.showForm.lonsec.value.length != Ø)
        {
        lonsec = Math.abs(parseFloat(document.showForm.lonsec.value));
        }
    var lon = -(londeg + ((lonmin + (lonsec / 6Ø)) / 6Ø));
    return lon;
    }

As with the magnification value calculated in getMagnification(), values are calculated for the three fields, with 0 as the default value for each field. Because the degrees and minutes fields are assumed to be integer values, parseInt() rather than parseFloat() is used to evaluate their values.

The calculation of the result from the degrees, minutes, and seconds values is straightforward, with one interesting quirk: The value has to be negative. The Tiger Map Service delivers maps for the continental United States, and longitudes are, by convention, negative west of the Prime Meridian.

There is an equivalent function to evaluate the latitude fields, getLatitude(). It is identical to the getLongitude() function except that the return value is positive. (Again, by convention, latitudes in the northern hemisphere are positive values.)

The setLongitude() function translates the decimal longitude back into degrees, minutes, and seconds and writes the values back to the TEXT INPUT elements:

function setLongitude(longitude)
    {
    longitude = Math.abs(longitude);
    var degrees = Math.floor(longitude);
    longitude = longitude - Math.floor(longitude);
    longitude *= 6Ø;
    var minutes = Math.floor(longitude)
    // complicated math to eliminate eensy teensy fractions of seconds
    var seconds = 6Ø * (longitude - Math.floor(longitude))
    seconds *= 1ØØØ;
    seconds = Math.round(seconds);
    seconds /= 1ØØØ;
    if (seconds >= 6Ø)
        {
        seconds -= 6Ø;
        minutes++;
        }
    if (minutes >= 6Ø)
        {
        minutes -=6Ø;
        degrees++;
        }
    document.showForm.londeg.value = -degrees;
    document.showForm.lonmin.value = minutes;
    document.showForm.lonsec.value = seconds;
    }

The longitude value is made positive by a call to Math.abs(). The integer portion is extracted using Math.floor(); this is the degrees part of the value. The remaining fractional part is obtained and multiplied by 60, and the integer portion of the result is taken with Math.floor(); this is the minutes part of the value. The remaining fractional part is obtained and multiplied by 60; this is the seconds part of the value, which is allowed to have a fractional part.

You might think that that's enough, but from the standpoint of user interaction, it isn't. The seconds field on the form is defined as displaying ten digits, but Netscape's math functions result in a value with more than ten digits of precision. Furthermore, the act of translating the three input fields into decimal degrees and then translating that result back into degrees, minutes, and seconds may introduce a tiny discrepancy into the result. This is due to the limitations inherent in representing fractions such as one third in the computer's binary memory: There is no value expressible in a finite set of powers of 2 that exactly equals one third.

So the seconds value is multiplied by 1,000, rounded off with Math.round(), and divided by 1,000. This gives a precision of 1/1,000 of a second. At the equator, where one degree of longitude is widest, 1/1,000 of a second is approximately an inch and a quarter, or about three centimeters. That should be good enough.

Because of rounding, the seconds value may now equal 60, which is one minute. This scenario has to be handled, and the carry effect may propagate to the degrees, as would happen if the initial calculation of minutes and seconds arrived at values of 59 and 59.99999.

Finally, after you have calculated acceptable values for degrees, minutes, and seconds, the values are written to the appropriate TEXT INPUT elements. The degrees are written as a negative value.

As with getLongitude() and getLatitude(), setLongitude() has a matching function, setLatitude(). The calculations are identical, and the difference is that the degrees latitude are written back as a positive value.

So that's how the compass point buttons work. Let's look at the zoom buttons next.

The zoom buttons cause two things to occur: First, they change the current magnification factor. Second, they update the hidden form-the one that contains the fields that the Tiger Map Service needs-and submit the data to the server. This function does the work for both buttons:

function zoom(dir)
    {
    var magnification = getMagnification();
    if (dir < Ø)
        {
        magnification /= 2;
        }
    else
        {
        magnification *= 2;
        }
    display(magnification);
    }

If the parameter dir is negative, the user is zooming out; if dir is positive, the user is zooming in. So, the magnification factor is obtained by a call to getMagnification and either halved or doubled. The new magnification factor is then passed to display(), which is shown here:

function display(magnification)
    {
    document.showForm.mag.value = magnification;
    var lon = getLongitude();
    setLongitude(lon);
    document.realForm.lon.value = lon;
    document.realForm.wid.value = 1 / magnification ;
    var lat = getLatitude();
    setLatitude(lat);
    document.realForm.lat.value = lat;
    document.realForm.ht.value = 1 / magnification;
    document.realForm.submit();
    }

First, the new magnification factor is written back to the TEXT INPUT field. Then the decimal longitude is obtained, the display is updated, and the decimal longitude is written to the hidden form's lon field. The hidden form's wid field is set to the inverse of the magnification factor. Remember, the higher the factor, the smaller of an area you're looking at.

The analogous calls are then made to set the hidden form's lat and ht values, and the hidden form's submit method is called, sending the request to the server.

Finally, the Go button's ONCLICK event handler is extremely simple: It just calls getMagnification() and sends the result to display(), like this:

display(getMagnification())

Putting Everything Together

Listing 8.2 shows the finished mapctrl.htm file.


Listing 8.2: HTML for the JavaScript solution
<HTML>
    <HEAD>
        <TITLE>Map Service</TITLE>
        <SCRIPT LANGUAGE="JavaScript">
<!--

function getMagnification()
    {
    var magnification = 1;
    if (document.showForm.mag.value.length != Ø)
        {
        magnification = Math.abs(parseFloat(document.showForm.mag.value));
        if (magnification == Ø)
            {
            magnification = 1;
            }
        }
    return magnification;
    }

function setLongitude(longitude)
    {
    longitude = Math.abs(longitude);
    var degrees = Math.floor(longitude);
    longitude = longitude - Math.floor(longitude);
    longitude *= 6Ø;
    var minutes = Math.floor(longitude)
    // complicated math to eliminate eensy teensy fractions of seconds
    var seconds = 6Ø * (longitude - Math.floor(longitude))
    seconds *= 1ØØØ;
    seconds = Math.round(seconds);
    seconds /= 1ØØØ;
    if (seconds >= 6Ø)
        {
        seconds -= 6Ø;
        minutes++;
        }
    if (minutes >= 6Ø)
        {
        minutes -=6Ø;
        degrees++;
        }
    document.showForm.londeg.value = -degrees;
    document.showForm.lonmin.value = minutes;
    document.showForm.lonsec.value = seconds;
    }

function setLatitude(latitude)
    {
    latitude = Math.abs(latitude);
    var degrees = Math.floor(latitude);
    latitude = latitude - Math.floor(latitude);
    latitude *= 6Ø;
    var minutes = Math.floor(latitude)
    // complicated math to eliminate eensy teensy fractions of seconds
    var seconds = 6Ø * (latitude - Math.floor(latitude))
    seconds *= 1ØØØ;
    seconds = Math.round(seconds);
    seconds /= 1ØØØ;
    if (seconds >= 6Ø)
        {
        seconds -= 6Ø;
        minutes++;
        }
    if (minutes >= 6Ø)
        {
        minutes -=6Ø;
        degrees++;
        }
    document.showForm.latdeg.value = degrees;
    document.showForm.latmin.value = minutes;
    document.showForm.latsec.value = seconds;
    }

function getLongitude()
    {
    var londeg = Ø;
    if (document.showForm.londeg.value.length != Ø)
        {
        londeg = Math.abs(parseInt(document.showForm.londeg.value));
        }
    var lonmin = Ø;
    if (document.showForm.lonmin.value.length != Ø)
        {
        lonmin = Math.abs(parseInt(document.showForm.lonmin.value));
        }
    var lonsec = Ø;
    if (document.showForm.lonsec.value.length != Ø)
        {
        lonsec = Math.abs(parseFloat(document.showForm.lonsec.value));
        }
    var lon = -(londeg + ((lonmin + (lonsec / 6Ø)) / 6Ø));
    return lon;
    }

function getLatitude()
    {
    var latdeg = Ø;
    if (document.showForm.latdeg.value.length != Ø)
        {
        latdeg = Math.abs(parseInt(document.showForm.latdeg.value));
        }
    var latmin = Ø;
    if (document.showForm.latmin.value.length != Ø)
        {
        latmin = Math.abs(parseInt(document.showForm.latmin.value));
        }
    var latsec = Ø;
    if (document.showForm.latsec.value.length != Ø)
        {
        latsec = Math.abs(parseFloat(document.showForm.latsec.value));
        }
    var lat = latdeg + ((latmin + (latsec / 6Ø)) / 6Ø);
    return lat;
    }

function display(magnification)
    {
    document.showForm.mag.value = magnification;
    var lon = getLongitude();
    setLongitude(lon);
    document.realForm.lon.value = lon;
    document.realForm.wid.value = 1 / magnification ;
    var lat = getLatitude();
    setLatitude(lat);
    document.realForm.lat.value = lat;
    document.realForm.ht.value = 1 / magnification;
    document.realForm.submit();
    }

function zoom(dir)
    {
    var magnification = getMagnification();
    if (dir < Ø)
        {
        magnification /= 2;
        }
    else
        {
        magnification *= 2;
        }
    display(magnification);
    }

function changeLongitude(dir)
    {
    var delta = Ø.1 / getMagnification();
    var longitude = getLongitude();
    if (dir < Ø)
        {
        longitude -= delta;
        }
    else
        {
        longitude += delta;
        }
    setLongitude(longitude);
    }

function changeLatitude(dir)
    {
    var delta = Ø.1 / getMagnification();
    var latitude = getLatitude();
    if (dir < Ø)
        {
        latitude -= delta;
        }
    else
        {
        latitude += delta;
        }
    setLatitude(latitude);
    }

//-->
        </SCRIPT>
    </HEAD>
    <BODY BGCOLOR="#ØØØØØØ" TEXT="#FFØØØØ">
        <FORM NAME="realForm"
            ACTION="http://tiger.census.gov/cgi-bin/mapgen"
            METHOD="GET" TARGET="viewer">
            <INPUT NAME="lon" TYPE="hidden" SIZE=1Ø>
            <INPUT NAME="lat" TYPE="hidden" SIZE=1Ø>
            <INPUT NAME="wid" TYPE="hidden" SIZE=1Ø>
            <INPUT NAME="ht"  TYPE="hidden" SIZE=1Ø>
            <INPUT NAME="iwd" TYPE="hidden" SIZE=1Ø VALUE="32Ø">
            <INPUT NAME="iht" TYPE="hidden" SIZE=1Ø VALUE="2ØØ">
        </FORM>
        <CENTER>
        <FORM NAME="showForm">
            <TABLE BORDER="2" CELLPADDING="2">
            <TR>
                <TD>
                <TABLE BORDER="Ø" CELLPADDING="2">
                <TR>
                    <TD ALIGN="center">
                        <INPUT TYPE="button" ONCLICK="zoom(1)"
                            VALUE="ZOOM IN">
                    </TD>
                </TR>
                <TR>
                    <TD ALIGN="center">
                        <INPUT TYPE="text" NAME="mag" SIZE=4>
                    </TD>
                </TR>
                <TR>
                    <TD ALIGN="center">
                        <INPUT TYPE="button" ONCLICK="zoom(-1)"
                        VALUE="ZOOM OUT">
                    </TD>
                </TR>
                </TABLE>
                </TD>
                <TD>
                <TABLE BORDER="Ø" CELLPADDING="2">
                <TR>
                    <TD>
                        East/West <INPUT TYPE="text" NAME="londeg"
                            SIZE=4><INPUT TYPE="text" NAME="lonmin"
                            SIZE=2><INPUT TYPE="text" NAME="lonsec"
                            SIZE=1Ø>
                    </TD>
                    <TD ROWSPAN="2">
                    <TABLE BORDER="Ø" CELLPADDING="Ø">
                    <TR>
                        <TD></TD>
                        <TD>
                            <PRE><INPUT TYPE="button" VALUE="N" 
                            ONCLICK="changeLatitude(1)"></PRE>
                        </TD>
                        <TD></TD>
                    </TR>
                    <TR>
                        <TD>
                            <PRE><INPUT TYPE="button" VALUE="W" 
                            ONCLICK="changeLongitude(-1)"></PRE>
                        </TD>
                        <TD></TD>
                        <TD>
                            <PRE><INPUT TYPE="button" VALUE="E" 
                            ONCLICK="changeLongitude(1)"></PRE>
                        </TD>
                    </TR>
                    <TR>
                        <TD></TD>
                        <TD>
                            <PRE><INPUT TYPE="button" VALUE="S" 
                            ONCLICK="changeLatitude(-1)"></PRE>
                        </TD>
                        <TD></TD>
                    </TR>
                    </TABLE>
                    </TD>
                </TR>
                <TR>
                    <TD>
                    North/South <INPUT TYPE="text" NAME="latdeg"
                        SIZE=2><INPUT TYPE="text" NAME="latmin"
                        SIZE=2><INPUT TYPE="text" NAME="latsec" SIZE=1Ø>
                    </TD>
                </TR>
                </TABLE>
                </TD>
                <TD>
                <TABLE BORDER="Ø" CELLPADDING="2">
                <TR>
                    <TD ALIGN="center">
                    <INPUT TYPE="button"
                        ONCLICK="display(getMagnification())"
                    VALUE="GO!">
                    </TD>
                </TR>
                <TR>
                    <TD ALIGN="center"><INPUT TYPE="RESET"></TD>
                </TR>
                </TABLE>
                </TD>
            </TR>
            </TABLE>
        </FORM>
        </CENTER>
    </BODY>
</HTML>

Improving the solution

There are many ways of enhancing the JavaScript solution. For starters, you can change the image size and you can give the user control over the image size. If you do that, it might be a good idea to define a new window for the image, because the current 320x200 image size already crowds the screen.

Also, as mentioned, the Tiger Mapping Service defines a lot of additional parameters. (For additional details, see the online documentation, which is listed in the Quick Reference). You can add support for such parameters as markers for locations on the map, information layers (grids, place names, and so on), and statistical information.

Modifying the example for your own use

In your work, you may need to write Web pages that talk to servers whose interfaces you have no control over. Two common kinds of servers are relational databases, which may require their input in SQL, and search engines like Alta Vista or Yahoo!. These interfaces may not meet the needs of your users, or they may be too complicated for your target audience. Using JavaScript and the principle of form modification, you can create simple, easy-to-use interfaces that meet your user's needs while satisfying the requirements of the server.