Working with the Google Maps Client-Side API

Use Google's open-source API objects to add custom-mapping functions to your website

Brian Mains

October 30, 2009

14 Min Read
ITPro Today logo

As just about all technical professionalsknow, Google is a leading company in the search engine business. But that's notall that Google does. Google also heavily invests in open-source developmentprojects such as Google Maps. The Google Maps client-side API is freelyavailable to the public for various uses. Google's primary purpose in enablingdevelopers to embed its mapping functions in their websites is to encourage useof Google's product over that of a competitor like Yahoo. Another reason is toallow you to build custom mapping features into your website. For instance, ifyour company's website provided a weather service like weather.com, the Googlemap could serve as the map and, by using the Google API, the map could haveclouds or other objects overlaying it.

Instead of making the mapping service availablethrough web services, Google exposes a reference to a service that downloadsscripts to the client to enable this mapping functionality. Although Googledefines components that use the browser's capabilities, whenever I can I usethe ASP.NET AJAX architecture instead, to show that Google can fit within whatMicrosoft has done in its client-side library. Let's take a look at the GMap2object and walk through examples of how to add various custom mappingfunctions zoom and pan controls, location, markers, panoramic view, directions,and more to your website.

The GMap2 Object

The core component in the Google Maps client-sideAPI is the GMap2 object. GMap2 is a constructor, which takes a reference to anHTML element that defines the region to place the map. Typically, this is a DIVelement that defines map's width and height. The method that Figure 1 shows initializesa GMap2 object; the method is defined in a helper class that will perform commonGoogle mapping tasks. The initializeMap method is responsible for setting upthe map on load, setting the center of the map using coordinates, andestablishing a proper zoom level.

initializeMap: function(mapElement, coords, zoom) {
this._map = newGMap2(mapElement);
this._map.setCenter(coords, zoom);
this._map.setUIToDefault();
}


Figure 1:Core setup: Initializing a GMap2 object

Maps work with coordinates (latitude and longitude);along with the zoom level, the Google Maps API uses these parameters to serveup the map image to the target DIV. As the user changes the parameters (e.g., zoomin or out), the Google Maps API serves up an image that's generated on Google'sservers and linked from the client. The map gets or sets coordinates using thegetCenter or setCenter method (this setting also takes the zoom level);consequently, the map can also get or set the zoom using the getZoom or setZoommethod.

These coordinates are actually objects of typeGLatLng. This object represents the latitude and longitude of a location on themap. This method has a lat() method and a lng() method to extract the latitudeand longitude values for later use. Take note that a good amount of the objectswork with this GLatLng class. In the rest of the article, where you see thevariable coords or point, most likely this is a GLatLng instance.

Have you noticed in Google Maps the zoom and pancontrols available within the map? These controls inherit from GMapTypeControl.The controls can be instantiated and added to the map by using the GMap2.addControl()method; however, the easiest way to add the default controls is to call thesetUIToDefault() method. Doing so adds the default controls within the UI. Formore information about the various types of controls that can be added, consultthe Google Maps API documentation at http://code.google.com/apis/maps/documentation/controls.html.




Changing a Location on a Map

So what if you want to change the location on themap? The map can use the setCenter method to change this location, or it canuse the panTo method to provide a pan effect of the map moving to the newlocation, if the new location is within a relatively short distance. Take alook at two methods used to change the location in Figure 2.

changeMapLocation: function(coords) {
this._map.panTo(coords);
},
changeMapLocationByAddress: function(address) {
var geo = newGClientGeocoder();
geo.getLatLng(address,function(point) {
if (point)
this.changeMapLocation(point);
});
}


Figure 2:Changing a map's location

Notice the second method using a new object? GoogleMaps also works with street addresses, as you'd know if you've visitedmaps.google.com. An address has to be translated into valid coordinates, andGoogle provides a geocoding service that performs this translation. The encodertranslates the address, and if there is a valid point, the location changeoccurs. An invalid address may be a reason why the point returns a null value.I won't go in-depth into geocoding; see the Google Maps documentation at http://code.google.com/apis/maps/documentation/services.htmland "GotMaps?", December 2008.

Markers, Events, and Windows

Google also includes markers points on the mapadded to illustrate a point of interest. Points of interest are identified withthe GMarker object. This object uses a latitude and longitude to specify itslocation. A marker may also specify a variety of configuration options, such asthe icon to use, some marker-moving effects, and more. To create a marker, callthe GMarker's constructor and supply a valid latitude and longitude by usingthe GLatLng object. Add this marker to the map using the addOverlay method, asFigure 3 shows.


addMarker: function(coords) {
var marker = newGMarker(coords,
{ draggable: true, bouncy: false });
this._map.addOverlay(marker); //_map is GMap2
Array.add(this._markers, marker); //store locally
return marker;
},


Figure 3:Adding a marker to a map

The marker specifies two UI settings: draggable,specifying whether the marker can be dragged and dropped; and bouncy, specifyingwhether the marker bounces when it's dropped. I'm not quite sure why Googleinvested the time to create a bouncing marker, but nevertheless, it'sconfigurable. Our addMarker method accepts a GLatLng object and passes this tothe constructor. This marker may appear on the map, if the latitude andlongitude are within the map boundaries.

We've gone to the trouble to create a marker, butwhat can the marker actually do? After all, it seems pointless just to host amarker that does nothing. Fortunately, the Google Maps API includes some othercool features. One such feature is events. All events flow through the GEventobject; this event object is very easy to attach event handlers to. The biggestchallenge with events is to know what the signature is, as every event changesits event-handler signature. The only way to figure this out is to consult the GoogleMaps API documentation (http://code.google.com/apis/maps/documentation/index.html),or guess.

I have to first explain how events in Google work,as they're similar to ASP.NET AJAX. Google event handlers recode the this keyword to point to a reference ofthe object having an event handler attached to it. This means that using the this keyword points to an instance ofthe GMarker object. This will pose some problems, as we'll see shortly.



When we add markers in an addMarker method, itwould also be beneficial to centralize the event-handler attachment process. Figure4 shows an updated version of the addMarker method, with event-handling added.

addMarker: function(coords) {
var marker = newGMarker(coords,
{ draggable: true, bouncy: false });
marker.AspNetComponent = this;
GEvent.addListener(marker, "click", function(latLng) {
this.AspNetComponent.showInfoWindow(latLng,
this.AspNetComponent._createMarkerWindow(this),
true);
});
GEvent.addListener(marker, "dragstart", function() {
this.AspNetComponent.hideInfoWindow();
});
GEvent.addListener(marker, "dragend", function() {
this.AspNetComponent.showInfoWindow(this.getLatLng(),
this.AspNetComponent._createMarkerWindow(this),
true);
});


Figure 4:Handling events

The GMarker class itself supports clicking themarker and dragging the marker around the map. The GEvent object attaches eventhandlers to the marker's click, dragstart, and dragend events. When the userbegins or ends the dragging, the event handler attached to these events fires.

Did you notice all the references toAspNetComponent? This reference handles a very specific problem. Because Googleevent handlers recode the thispointer to point to the GMarker instance, there's no easy way to access theASP.NET AJAX utility class that defines the addMarker method. It needs toaccess this class to call its methods.

The workaround works only too well in JavaScript: Attachanother property to the marker referencing the ASP.NET AJAX component. Thisway, this new property can be referenced directly and have all the methods itneeds to call called.

A better way is to attach the AspNetComponentreference to the window object. Sinceonly one instance of the component runs in the browser at a time, the browser'swindow object can be referenced anywhere in the application, and thisAspNetComponent reference can be made directly without the need for the "this"prefix. Note: I considered trying to use the $addHandler object, but becausethese aren't DOM object events; $addHandler is meant for DOM, not JavaScript,objects.

The second great feature is information windows.Google automatically provides a pop-up balloon notification. This notificationis triggered through the openInfoWindow or openInfoWindowHtml method of theGMap2 or GMarker class. There may be other Google objects that inherit this aswell. These two methods display a message to the user stating some informationabout the marker or point on the map at hand. Again, the information windowuses a coordinate value to display itself and isn't necessarily tied to aspecific marker. In this case, the marker events tie the informational windowto the marker's location, using some helper methods, as shown in Figure 5.

hideInfoWindow: function() {
this._map.closeInfoWindow();
},
showInfoWindow: function(coords, content, isHtmlText, options) {
if (isHtmlText)
this._map.openInfoWindowHtml(coords,content, options);
else
this._map.openInfoWindow(coords, document.createTextNode(content),options);
}


Figure 5:Showing and hiding informational windows

In this case, the map triggers an informationalwindow. Please note that the showInfoWindow and hideInfoWindow are helpermethods that wrap the underlying Google functionality and that the actual workis performed via the Google methods themselves. At any point, an informationalwindow can be closed using the closeInfoWindow() method; this window doesn'tcause any issues if no informational windows are present.

In the included example, the map displays thecoordinates of the current point that's clicked or dropped on the map. This isuseful to have to find starting coordinates for the map.



Panoramic View

Recently, Google included a new feature into itsmapping control: a 360-degree street panoramic view that allows anyone to viewthe actual details of a specific street. This feature targets more popularareas but is gaining ground in the amount of the United States and the worldthat it covers. This panoramic view works similarly to the GMap2 control: Ittargets a DIV element and uses it as its host. Panoramic view uses Flash, soFlash must be installed on the computer. You can configure this view can beconfigured; there are a couple of necessary settings. Some of these settingsare

  • Yaw defines the rotation around the camera topoint. The value provided is a floating point value relative from due north.

  • Pitch the degrees up or down from the defaultpitch of the camera (zero).

  • Zoom the zoom level of the street-view picture.

All this functionality is part of theGStreetviewPanorama class. Take a look at a method to initialize a panoramicview, shown in Figure 6.

initializePanorama: function(panoramaElement, coords) {
this._panElement =panoramaElement;
this._pan = newGStreetviewPanorama(panoramaElement);
panoramaElement.style.display = "none";
//Errors occur becauselocation isn't available (600) or service has issues (500)
GEvent.addListener(this._pan, "error", function(errorCode) {
panoramaElement.style.display = "none";
});
},


Figure 6:Initializing the panoramic view

The GStreetviewPanorama object works similar to theGMap2 class in that it uses a coordinate-based approach and takes an HTMLelement that it will use as its host in its constructor. The panoramic viewalso has a few events, the most important of which is the error event. If, forwhatever reason, the GLatLng instance used to show a specific street view isn'tsupported (i.e., no views are available), an error event is fired with an errorcode of 600, signaling this.

Because some of the views may not be available, theapproach I took to displaying the street view is by turning the DIV elementthat hosts it on and off whenever the map is or isn't available. This isimportant because the street-view panoramic object doesn't have a successevent.

The street view can use its own coordinates, butoften it's useful to marry the map and the street view together. To do this,every time a marker is added, clicked, or dropped on the map, the street viewattempts to do its thing and display a map. These methods and event handlersall call the changePanoramaLocation method to change the street view to a new coordinate/pointof view (POV), as Figure 7 shows. The POV entails using the yaw, pitch, andzoom as described earlier.

changePanoramaLocation: function(coords, pov) {
if (pov == null)
pov = { yaw: 0,pitch: 0, zoom: 1 };
this._panElement.style.display = "block";
this._pan.setLocationAndPOV(coords, pov);
},
addMarker: function(coords) {
.
.
.
this._map.addOverlay(marker);
Array.add(this._markers, marker);
this.changePanoramaLocation(coords);
}


Figure 7:Changing the panoramic view

Notice that the map element is displayed wheneverthe coordinates are established; if the coordinates happen to be bad, the mapelement is quickly hidden when the 600 error occurs, as previously shown.

Directions

Directions are essential to the mapping process. Inthe Google Maps API, the direction process is a cinch. Directions also involvethe use of a map and an HTML element to render them in. The directions part ofthe API, however, is more self-sustaining; it renders each directionalstatement itself as well as manages the points and route on the map.

As with the maps and steet-view features, thedirections feature has an initialize function, which instantiates ourGDirections object. Take a look at the following methods to initialize the mapand display the driving directions, as Figure 8 shows.

initializeDirections: function(directionsElement) {
if (this._map == null)
throwError.invalidOperation("The initializeMap() method must be called beforedirections can be established");
this._dir = newGDirections(this._map, directionsElement);
},
showDirections: function(from, to, options) {
var query =String.format("from: {0} to: {1}", from, to);
this._dir.load(query,options);
}


Figure 8:Initializing the map and showing directions

Displaying driving directions is pretty easy; it'sdone using a query structure format. To display driving directions, simplycreate a string specifying the from: and to: locations. Some additional optionsare available, such as excluding highways in the driving directions, if that'spossible.




The local search feature is an add-on that's availableby including another Google script in our application. LocalSearch is a controlthat can be displayed within the Google map. It consists of a text box andbutton that searches the currently available location for anything of aspecific venue: restaurants, barber shops, malls, and so on.

It's really easy to add the LocalSearch control tothe script. To do so, you need to download an extra script from www.google.com/uds/solutions/localsearch/gmlocalsearch.js.This URL makes available a LocalSearch class within the google.maps namespace.You can add it to a Google map by using the line of code in Figure 9 shows.

this._map.addControl(new google.maps.LocalSearch(), newGControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(10, 20)));


Figure 9:Adding the LocalSearch control

Once this control is within the map, it works likethe driving direction; it's self-sustaining in that it renders its owninterface and the result set. There is one other external dependency however;for the control to look "pretty," it requires importing two CascadingStyle Sheets (CSS) files that contain the styles for the control.

Putting It All Together

You may not have realized it, but the script withinthis article is embedded in a helper component called GoogleMapUtility. Thisutility class simply wraps all our common mapping logic into one common place. Theshell of this component, reiterating the methods we created throughout thearticle, is outlined in Figure 10.

Type.registerNamespace("AjaxSamples");
AjaxSamples.GoogleMapUtility = function() { }
AjaxSamples.GoogleMapUtility.prototype = {
get_map: function() {},
get_mapZoom:function() { },
set_mapZoom:function(value) { },
get_panorama:function() { },
addMarker:function(coords) { },
changeMapLocation:function(coords) { },
changeMapLocationByAddress: function(address) { },
changePanoramaLocation: function(coords, pov) { },
clearMarkers:function() { },
_createMarkerWindow:function(marker) { },
dispose: function() {},
hideInfoWindow:function() { },
initializeDirections:function(directionsElement) { },
initializeMap:function(mapElement, coords, zoom) { },
initializePanorama:function(panoramaElement, coords) { },
removeMarker:function(marker) { },
showDirections:function(from, to, options) { },
showInfoWindow:function(coords, content, isHtmlText, options) {}
}
AjaxSamples.GoogleMapUtility.registerClass(
"AjaxSamples.GoogleMapUtility", Sys.Component);


Figure 10:Helper class shell

The sample ASP.NET page (code shown in Figure 11)implements most, if not all, of these functions in a test application. At page-loadingtime, all the initialization methods get called in a specific order. A locationof 51.231,-0.609 is used as the center of the map, along with a zoom at level8.

Read more about:

Alphabet Inc.
Sign up for the ITPro Today newsletter
Stay on top of the IT universe with commentary, news analysis, how-to's, and tips delivered to your inbox daily.

You May Also Like