Web Maps with the Google Map API

Google has provided web developers with a feature rich toolset for representing geographical information.


November 06, 2007
URL:http://www.drdobbs.com/web-development/web-maps-with-the-google-map-api/web-development/web-maps-with-the-google-map-api/202802965

Dionysios is a web engineer at the National Technical University of Athens and a freelance consultant. He can be contacted through his blog at http://synodinos.wordpress.com.


A common challenge for many web developers is the creation of web applications that capture and describe geographical information. Nowadays, online maps are showing up everywhere, either as standalone applications or as modules for larger portals and services.

For such tasks, traditional image-based solutions fall short because the acquisition of the media tends to be expensive as they involve air photographs or copyrighted geopolitical maps. In the case of large-scale maps, the ad hoc use of satellite imaging can prove even more costly. Also, for this imaging to be easily available with the proper degree of usability, it requires lots of coding, which often introduces incompatibilities for many browsers.

Some vendors attack the problem by using proprietary plug-ins and development environments. But this approach still has many of the same problems as the final product is bound to specific environments and requires major funding for licensing.

For the last five years, we had been using a proprietary solution to manage a small percentage of the geographical information about various university locations. This solution had only a few locations and would run in only one browser on one operating system. Moreover, it required users to download a big plug-in. Also, it wasn't stable under heavy use.

For the next version of our service, we wanted to map more locations—in fact, everywhere in the country where the university has locations for labs, research facilities, and the like. The front-end would have to be stable and operate on all major operating systems and browsers. It would also have to be flexible enough for us to build features and functionality. Finally, it should be a solution that has the acceptance of the rest of the market since we wanted to make a long-term investment that would pay off as our service would scale.

In this article, I present our solution—a web front-end that utilizes several aspects of the freely available Google Map API to provide a usable, robust, cross-platform web map.

Getting the Right Coordinates

To get the precise geographical location for specific sites, you could use some kind of a geocoder tool. There are several free ones (the Perl module Geo::Coder::US, for instance), but most work only with U.S. addresses. For our purposes, we used Google Earth (earth.google.com), which in its latest version combines satellite imagery, maps, terrain, and 3D buildings. This tool gives a simple interface to navigate over a global satellite map and manually assign points of interest with markers, polylines, and polygons. This software was so straightforward that we could give it to our team of rural engineers and, after a few minutes of training, they were able to represent a large amount of information that was scattered in a variety of files in different engineering software formats. The original file was converted to KML, short for "Keyhole Markup Language" (code.google.com/apis/kml/documentation), an XML-based language for managing three-dimensional geospatial data. This file contained coordinates, labels, and even HTML descriptions, in a format that was human readable and easy to process using XSLT. Listing One, for instance, is the location of my office in KML.

<Placemark>
  <name>My Office</name>
  <LookAt>
    <longitude>23.78266482649396</longitude>
    <latitude>37.97757782541832</latitude>
    <altitude>0</altitude>
    <range>155.5744724827026</range>
    <tilt>1.639002638135242e-012</tilt>
    <heading>0.001088456620806448</heading>
  </LookAt>
  <Point>
    <coordinates>
      23.78277996313077,37.97773328821575,0
    </coordinates>
  </Point>
</Placemark>
Listing One

Initializing the Map

Although the Map API is free, to embed a map in a web pages you first have to sign up for an API key. A single key is valid for a single "directory" on your web server, so if you sign up for the URL "www.mycompany.com/mysite," the key you get will be good for all URLs in the "www.mygooglemapssite.com/mysite/" directory. You must have a Google Account to get a Maps API key, and your API key is connected to your Google Account. These keys are generated in real time and are required to import the core library in your JavaScript code:

<script
src="http://maps.google.com/maps?file=api&v=2&key=YOUR_KEY"
type="text/javascript">
</script>

For a basic map to appear, the API requires that the construction be made while the body of the page loads with a function similar to Listing Two. In this way, you first check if the browser is compatible with your JavaScript API (most are), then construct a new map object. For our purposes, we added some controls on the map to help us zoom in/out, and change modes between satellite imagery and geopolitical view. Also, we defined the initial center of the map and provided a welcome message window that contains HTML code. Our API also gave us a built-in function GUnload() for cleanup purposes on exiting the map page.

function load() {
  if (GBrowserIsCompatible()) {
    map = new GMap2(document.getElementById("map"));
    map.addControl(new GLargeMapControl());
    map.addControl(new GMapTypeControl());
    map.addControl(new GOverviewMapControl());
map.addControl(new GScaleControl());
map.setCenter(new GLatLng(37.97775399999999, 23.782611), 16);
    map.openInfoWindow(map.getCenter(),"Welcome message");
map.setMapType(map.getMapTypes()[1]);
var pos = new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(250,0));
pos.apply(document.getElementById("control"));
map.getContainer().appendChild(document.getElementById("control"));
  }
}
Listing Two

Printing Markers, Polylines, and Polygons

Adding elements on an embedded map is done in a similar way using the coordinates that are contained in the KML file; see Listing Three.

We've taken it a step further to register listeners every time an element is printed and also have added every element in an array. This way we are able to reference these element in the future, while our application is executed; for example, to remove them from the map using the map.removeOverlay() function, you would use map.removeOverlay(permarkers[4]). The API has several facilities for customizing the way the different kinds of elements appear on the map. The markers can have custom size, icon, and shadows, and we can assign specific color, width, and transparency for polylines and polygons.

For a small number of locations, it is fairly easy to copy the coordinates by hand and insert them in JavaScript code. But as the number of locations increase, it is harder to manipulate these 16-digit numbers and it becomes necessary to use programming to extract them for the KML file. In our project, the number of locations was big! There were several polylines that were described using more than 60 different points that accounted for 100+ different 16-digit numbers. To overcome this, we had to develop XSL filters for the KML file that contained recipes for producing JavaScript code; see Listing Four.

// Adding a Marker
point = new GLatLng(GLat, GLng);
var marker = new GMarker(point, icon);
GEvent.addListener(marker, "click", function() {
    marker.openInfoWindowHtml(PopupMessage);
});
gmarkers.push(marker);
marker.type = myBox;
map.addOverlay(marker);
map.getInfoWindow().hide(); 
marker.openInfoWindowHtml(PopupMessage);

// Adding a Polyline
var polyline = new GPolyline(
    [new GLatLng(37.97790952936251,23.78223936561216),
    new GLatLng(37.97791762387,23.78145356303465)], 
    "#FF0000", 10);
    GEvent.addListener(polyline, "click", function() {
});
rmarkers.push(polyline);
polyline.type = 'polyline';
map.addOverlay(polyline);
// Adding a Polygon
var perimeter = new GPolygon(
    [new GLatLng(37.97635717824197,23.78899058286345),
    new GLatLng(37.97708237409014 ,23.7884251217523),
    new GLatLng(37.97747123844004,23.78810420996354)],
    "#003300", 5, 0.5,"#84FF84", 0.5);
GEvent.addListener(perimeter, "click", function() {
    });
rmarkers.push(perimeter);
perimeter.type = 'perimeter';
map.addOverlay(perimeter);
Listing Three

<!— A KML polygon definition—>
<Placemark>
    <name>ntua</name>
    <Polygon>
        <tessellate>1</tessellate>
        <outerBoundaryIs>
            <LinearRing>
               <coordinates>
23.77640524972817,37.97997329891562,0
23.77662966873682,37.98001305553392,0
23.77648054859569,37.97997328228906,0 
<!-
    185+ similar lines with coordinates
—>
</coordinates>
            </LinearRing>
        </outerBoundaryIs>
    </Polygon>
</Placemark>

<!-The XSL to process the coordinates —>
<xsl:template match="Placemark">
    <xsl:variable name="curpos" select="position()"/>
    <xsl:text>var polygon</xsl:text>
    <xsl:value-of select="$curpos"/>
    <xsl:text> = new GPolygon([</xsl:text>
    <xsl:apply-templates
select="Polygon/outerBoundaryIs/LinearRing/coordinates"/>
    <xsl:text>], "#0000FF", 5,0.5,"#8A8AFF", 0.5);
    map.addOverlay(polygon</xsl:text>
    <xsl:value-of select="$curpos"/><xsl:text>);</xsl:text>
</xsl:template>
<xsl:template match="coordinates">
    <xsl:variable name="in" select="."/>
    <xsl:for-each select="tokenize($in, ' ')">
        <xsl:text>new GLatLng(</xsl:text>
        <xsl:variable name="tokenizedSample"
select="tokenize(.,',')"/>
        <xsl:variable name="before"
select="substring-before(.,',')"/>
        <xsl:variable name="after"
select="substring-after(.,',')"/>
        <xsl:value-of select="$after"/><xsl:text>,</xsl:text>
        <xsl:value-of select="$before"/>
        <xsl:text>),</xsl:text>
    </xsl:for-each>
</xsl:template>
Listing Four

In some situations, it is possible to move the XML-specific processing tasks over to the client and have the browser initially call the original KML file with the XMLHttpRequest API. However, this approach is not advisable in most cases because the overhead on the client's machine may cause the system to respond slowly or even freeze for a considerable amount of time.

Building the Menu

For a large number of locations scattered over a large geographical region (as in our project), it is important to have a well-thought-out menu for navigation since the sheer volume of information can make your UI cluttered or unusable. Also, this menu should be able to scale efficiently since our points of interest will increase by a significant factor every time we roll-out a new version.

To make things more difficult, the heavy use of JavaScript required by the API makes it tricky and error prone to use heavy frameworks for rich Internet clients. The elegant way we worked around this was to embed the structured list of sites on an <iframe> that would have to load inside the page into which our map was embedded. This way we would also achieve the maximum utilization of the page area for a given screen resolution; see Figure 1.

[Click image to view at full size]

Figure 1: The finished product.

Conclusion

With the launch of its most-recent mapping API, Google has provided web developers with a feature-rich toolset for representing geographical information in a web environment. Besides the various functionality that is already present out-of-the-box, the JavaScript-based environment provides the necessary facilities to extend the default behavior and satisfy even the most challenging requirements. It is also remarkable that all these features come in a package that has been developed from the ground up to be compatible with most major environments (browsers). What is left for the web developer is to provide the underlying connection to data and apply these instruments in a manner that will make usable front-ends possible.

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.