Google Maps JavaScript API

The Google Maps JavaScript API is a powerful tool for mapping solutions. With a minimal amount of code you can map points and directional routes in a clean visual way. We recently used the API to implement a solution that maps an itinerary of things to do in Southwest Virginia. We used the Drupal Services module to save itineraries. Let's take a look at the code to see how easy it is to start using the JavaScript API.

The Right Includes

The first thing you need to do is include the main JS file from Google:

<script type="text/javascript" 
        src="http://maps.google.com/maps/api/js?sensor=false">
</script>

This should give you access to both the mapping API and the directions API.

Initialize the Map

Next setup the map object in your JavaScript code.

 var directionDisplay;
 var directionsService = new google.maps.DirectionsService();
 var map;
 
function initializeMap() {
   directionsDisplay = new google.maps.DirectionsRenderer();
   var virginia = new google.maps.LatLng(38.23818, -80.81543);
   var myOptions = {
     zoom: 6,
     mapTypeId: google.maps.MapTypeId.ROADMAP,
     scrollwheel: false,
     center: virginia
   }
   map = new google.maps.Map(
   document.getElementById("map-canvas"), myOptions);
   directionsDisplay.setMap(map);
 
   //go ahead and calculate route
   plotItineraryRoute();
}

Let's step through this code briefly for an explaination:

  • directionsDisplay: This is a DirectionsRenderer object that controls how the map renders. You can pass it a DirectionsRendererOptions object to control how the map and directions are rendered
  • virginia: arbitrarily named, this variable is a Google Maps point. This will be the center point for the map on initial rendering.
  • myOptions: a MapOptions object that dictates the options for the map. The "scrollwheel" property turns off scrollwheel interactivity. If your cursor is over the map and you scroll the mouse wheel it zooms the map (since it has focus). It does not scroll the page. We found this annoying so we set the value to "false" to turn it off.
  • map-canvas: The item "map-canvas" can be any div element on the page. This is where you want the API to render the map.

Plotting Waypoints

After we have initialized the map we call plotItineraryRoute() to plot the points we want on the map. Let's look at a stripped down version to better understand things:

function plotItineraryRoute() {
 
  var start = "";
  var end = "";
  var waypts = [];
 
  var request = {
      origin: start, 
      destination: end,
      waypoints: waypts,
      optimizeWaypoints: false,
      travelMode: google.maps.DirectionsTravelMode.DRIVING
  };
 
   directionsService.route(request, function(response, status) {
     if (status == google.maps.DirectionsStatus.OK) {
       directionsDisplay.setDirections(response);
     }else{// if (status == google.maps.DirectionsStatus.OK) {
       //error from google
     }
  });
 
}

The free version of the API only allows 10 points to be plotted at once. You can see in the request object that there is an origin, destination, and waypoints property. The origin and destination count as 2 of the 10 points you can pass the API, so the waypoints array can only contain 8 elements. Google does have a paid premium service which allows for more points per call. For more information check Google's documentation and look for the status code "MAX_WAYPOINTS_EXCEEDED."

Waypoints Data

You can see that the origin point and destination point are empty. "waypoints" is also an empty array. So let's take a look at how to get data into these variables. For our solution we were storing point data in html elements, so we looped through those elements to assign values to these variables. How you get data into these variables is not important. How it's formatted is.

  $('.map-element').each(function(index) {
    var points=$(this).attr('latitude')+","+$(this).attr('longitude');
    if(index==0){
       start=points;
    }else if(index==(len-1)){
       end=points;
    }else{
      if(wayptCounter<wayptLimit){
       waypts.push({
           location:points,
           stopover:true
           });
       wayptCounter++;
      }
    }
  });

There are two ways the API receives point data:

  • String literal: this is a string that represents a location in a format that the API understands. ex. "Hillsville, VA, USA"
  • Latitude/Longitude String: this is a the latitude and longitude points separated by a coma. ex. "38.23818,-80.81543"

So either of these formats are acceptable for point data. You can see what's pushed into the waypt array is an object with two properties: location (a point formatted with one of the two options above) and stopover.

Customizing Rendering

We wanted to add a custom icon for each map point, so we hid the markers with following code:

    var  mapRendererOptions = {};
 
    var markerOptions ={};
    markerOptions.visible=false;
 
    var polylineOptions={};
    polylineOptions.strokeColor="#438391";
    polylineOptions.strokeOpacity=.6;
    polylineOptions.strokeWeight=4;
 
     //now assign to map render options
    mapRendererOptions.markerOptions=markerOptions;
    mapRendererOptions.polylineOptions=polylineOptions;
 
    //now set renderer
    directionsDisplay.setOptions(
    new google.maps.DirectionsRenderer(mapRendererOptions));

Now that we have marker options turned off, we need to go through each "leg" of the response object and place a custom marker on the map. We stored some additional metadata about each point in an array called "intineraryArray." We'll use this array as a holder of all point, but more important it contains the "user friendly" display name of the point. We don't want the user seeing "3499 Downing Rd, Denver, Colorado" - we want them to see "Aten's Office." Obviously the Google API doesn't have this display title.

var route = response.routes[0];
var legs = response.routes[0].legs;
 
for (i=0;i<legs.length;i++) {
  itineraryArray[i].address=legs[i].start_address;
  itineraryArray[i].duration=legs[i].duration.text;
 
  var altLineBreak="\n";
 
  if(i==(legs.length-1)){
    itineraryArray[i+1].address=legs[i].end_address;
    createMarker(legs[i].start_location,itineraryArray[i].label+
                          altLineBreak+itineraryArray[i].address, i, 
                         "blue", markersItineraryArray);
    createMarker(legs[i].end_location,itineraryArray[i+1].label+
                          altLineBreak+itineraryArray[i+1].address, i+1, 
                         "blue", markersItineraryArray);
  }else{
    createMarker(legs[i].start_location,itineraryArray[i].label+
                           altLineBreak+itineraryArray[i].address, i, 
                          "blue", markersItineraryArray);
  }
}

So for each leg it fires "createMarker." Here is the createMarker function:

function createMarker(latlng, label, index, color, markerArray) {
    var markerNumber="_"+(index+1);
    if(index==9){
      markerNumber="";
    }
 
    var marker = new google.maps.Marker({
        position: latlng,
        map: map,
        clickable: true,
        icon: new google.maps.MarkerImage(
                '/sites/all/modules/custom/trip_planner/img/'
                +color+'_marker'+markerNumber+'.png'),
        title: label
        });
 
    google.maps.event.addListener(marker, 'click', function() {
      //BLank click handler
    });  
}

Mapping that Makes Sense

The result is a powerful mapping tool that let's users plot destination points (points of interest) and their current itinerary, all on one map. The custom markers help distinguish which points belong to which lists.

Code JavaScript

Read This Next