Drawing On Maps — Not Just For Surveyors and Destructive Children

by

There’s really no excuse for not incorporating the Google Maps API into your applications these days. It’s free, easy to use, and with version 3 you don’t even need an api key anymore (although you can still use one).  What’s that I hear? You don’t need interactive maps on your site? Not good enough.
We’ll be using the Javascript V3 API.

The Map

Basic usage is so simple it’s almost frightening. You include the api library, create a DOM container to house your map, and create a map object which gets inserted into your container.

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

 <div id="map-container" style="width:400px; height:400px;"></div> 

 <script type="text/javascript">  var latlng = new google.maps.LatLng(-34.397, 150.644); var mapOptions = {      zoom: 8,       mapTypeId: google.maps.MapTypeId.ROADMAP,      center: latlng }; var myMap = new google.maps.Map(document.getElementById("map-container"), mapOptions); </script>

That’s it. There’s your basic map. The latitude and longitude settings have put you in Sydney, Australia. I can’t find this confirmed anywhere, but it looks like the zoom value goes from 0 (viewing the whole world) to 22 (pressing your face against the ground)

A few points that I may have glossed over:

  • The mapOptions object is required, as are the three elements it contains (zoom, center, and mapTypeId) here. There are a number of other optional values that you can add to mapOptions to configure your map, but these three are essential.
  • You’ll probably want to defer creation of the map object until the dom is loaded with your favorite document.onReady() -type of construct, as well as checking to make sure the API is available if(google).

Now we’ve got a map. Let’s put it through its paces.

Geolocation

The easiest way to get the user’s location is with a browser that enables HTML5 geolocation. The Maps Api documentation describes a few other possibilities, but since all major current browsers support HTML5 geolocation, we won’t bother with anything else at the moment.

navigator.geolocation.getCurrentPosition(function(position) {  initialLocation = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);    myMap.setCenter(initialLocation);   },   function() {    alert("couldn't get your location");});

This should send your map to Moosejaw, Saskatchewan, or wherever you happen to be sitting at the moment. navigator.geolocation.getCurrentPosition is of course provided by the browser, not the maps API.

Overlays

You can add a wide variety of graphical elements to your map: markers (most often seen as a pin in the map, but they can be any graphic you choose), polylines, polygons, circles and “ground overlays” (we won’t look at these last here, but here’s an example).

Placing a marker on the map

 var latLng = new google.maps.LatLng(-34.397, 150.644); var marker = new google.maps.Marker({   icon: 'http://url.of.image',   position: latlng,   map: myMap,   title: "If you lived on this marker, you'd be home right now." });

position and map are required if you want your marker to display. Other parameters are optional. You can set create the marker first and add position and map later however, with marker.setPosition() and marker.setMap().

Removing a marker (or other overlay) from the map

marker.setMap(null);

if you want to actually delete the marker, set the marker variable itself to null.

Circles and polygons are nearly as simple.

Drawing a circle

var latLng = new google.maps.LatLng(-34.397, 150.644); var circle = new google.maps.Circle({   strokeColor: "#FF0000",   strokeOpacity: 0.8,   strokeWeight: 2,   fillColor: "#FF0000",   fillOpacity: 0.35,   map: myMap,   center: latLng,   radius: 200 });

One thing to note is that all measurements (in this case, radius) are in meters.

Drawing a polygon (this example from the documentation draws the Bermuda Triangle)

var pathsArray = [   new google.maps.LatLng(25.774252, -80.190262),   new google.maps.LatLng(18.466465, -66.118292),   new google.maps.LatLng(32.321384, -64.75737),   new google.maps.LatLng(25.774252, -80.190262) ]; var polygon = new google.maps.Polygon({   paths: pathsArray,   strokeColor: "#FF0000",   strokeOpacity: 0.8,   strokeWeight: 2,   fillColor: "#FF0000",   fillOpacity: 0.35,   map: myMap });

Note that it’s not necessary to close the polygon (the end point does not have to be the same as the initial point).

Pixels to Map Coordinates and Vice-Versa

One particular problem I encountered was converting between screen pixels and the latitude/longitude measurements that are the units the api generally works with. Either this is a rare example of the documentation being insufficient, or I was just obtuse, because it took me a while to figure out.

The application I was working on called for a user to be able to draw a polygon by clicking several times on the map. Finally I wanted to close the polygon when the user clicked on or near the original point. But what’s “close?” If the map is zoomed way in, close on screen may be a distance of a few meters, but if the map window is viewing all of Asia, a difference of a few pixels may mean 100 miles. Here’s what I did to see whether the user has clicked within 6 pixels of the initial polygon point.

In order to get this to work, I needed to get an OverlayView object from the map and from that get a Projection object to manipulate the Latitute/Longitude data. Incidentally, in order to use an OverlayView, you have to override its draw method.

function pointsAreClose(latLng1, latLng2, map) {   var pointThreshold = 6;   var overlay = new google.maps.OverlayView();   overlay.draw = function(){};   overlay.setMap(map);   var projection = overlay.getProjection();   var areClose = false;   if (projection != undefined) {     var coords1 = overlay.getProjection().fromLatLngToContainerPixel(latLng1);     var coords2 = overlay.getProjection().fromLatLngToContainerPixel(latLng2);     if ( Math.sqrt( Math.pow(coords1.x - coords2.x,2) + Math.pow(coords1.y - coords2.y,2)) < pointThreshold) {       areClose = true;     } else {       areClose = false;     }   }   overlay.setMap(null);   return areClose; }

Loading Libraries

Currently there are five additional libraries, some of which are related to drawing. Google, being Google, can be expected to add more in short order:

  • AdSense (I’m not really sure what this is. It requires a Google AdSense account)
  • Drawing (provides tools for user-initiated drawing without having to create your own interface)
  • Geometry (contains advanced methods for calculating spherical projections and the like)
  • Panoramio (allows the adding of photos from Panoramio)
  • Places (provides access to a database of specific places e.g. The Empire State Building, provides an autocomplete feature)

You include libraries by adding this query string parameter to your javascript src attribute: libraries=library1,library2,library3 e.g. https://maps.googleapis.com/maps/api/js?sensor=false&libraries=drawing,places

Wrap-Up

I’ve barely scratched the surface of the Maps API’s drawing capabilites here, much less the power of the API overall. It’s powerful, versatile, and I really enjoy using it. Check it out for yourself. This is one area at least where Google’s all-seeing eye seems to be working in the service of the public.

2 Comments

  1. True enough. I should have mentioned that. However, for the project I worked on those features were excessive. I wanted to limit the user interaction.

Leave a Reply

Your email address will not be published. Required fields are marked *