Wednesday, February 29, 2012

Measuring distance with markers

https://files.nyu.edu/hc742/public/googlemaps/distance2.html
Double-click to remove point, click on line to add intermediary point.

maps.google.com has a tool that measures the distance along a path created by successive mouse clicks. To activate the tool, open the Maps Labs link (at the bottom of the left sidebar), activate the Distance Measurement Tool, and then click on the small icon at the bottom left corner of the map.


Once active, clicking on the map allows you to draw a path, whose distance will be shown on the sidebar.

A reproduction of this tool uses Markers, a Polyline, the Geometry library, and some event listeners.

Click on the map to add Markers. A path will be drawn between the markers, and return the distance of the path. Drag a marker to change the path, and double-click one to delete it.



First we declare a marker array and the polyline:

    function initialize() {
      var map;
      var mapOptions = {
        center: new google.maps.LatLng(42.3584308, -71.0597732),
        zoom: 16,
        mapTypeId: google.maps.MapTypeId.ROADMAP
      };


      var markers = [];
      var line;


A difference between this distance measurement tool and the Labs tool is that we will allow points along the path to be dragged and deleted.

Markers are added in the map event listener activated by clicks, and for each of these new Markers, a double-click (for its deletion) and drag listener is added.

        google.maps.event.addListener(map, 'click', function(event) {
          var marker = new google.maps.Marker({
            map: map,
            position: event.latLng,
            draggable:true
          });
          markers.push(marker);
          drawPath();


          google.maps.event.addListener(marker, 'dblclick', function(event) {
            marker.setMap(null);
            drawPath();
          });
          
          google.maps.event.addListener(marker, 'drag', function(event) {
            drawPath();
          });
        });


Note that marker.setMap(null) removes the marker from view, though it remains in our markers[] array. Managing this array is done in the following function:

      function countMarkers() {
        count = 0;
        for (var i = markers.length - 1; i >= 0; i--) {
          if (markers[i].getMap() == null) {
            markers.splice(i, 1);
          } else {
            count++;
          }
        }
        return count;
      }


We wish to remove all markers whose map is set to null, and because removing an item shifts subsequent items to the left, we traverse the array backwards. Otherwise, we would run out of bounds after removing any single (or more) item from the middle of the array. splice removes one item (amount given in the second argument) at index i.


Next, knowing where all our active points are, we pass this information to update the Polyline display.

      function drawPath() {
        countMarkers();
        var coords = [];
        for (var i = 0; i < markers.length; i++) {
          coords.push(markers[i].getPosition());
        }
        line.setPath(coords);


        meters = google.maps.geometry.spherical.computeLength(coords);
        $("distKm").value = Math.round(meters/1000 * 100) / 100;
        $("distMi").value = Math.round(meters/1609 * 100) / 100;
      }

At the same time, the distance is measured with the geometry library, using a simple call to computeLength. The result is in meters, and conversions to kilometers and miles are done to update the textboxes. Finally, a straightforward function clears all the markers.

      function clearMarkers() {
        for (var i = 0; i < markers.length; i++) {
          markers[i].setMap(null)
        }
        drawPath();
      }

The HTML form looks like this:

          <form id="form">
            <input id="distKm" type="text"> km<br />
            <input id="distMi" type="text"> miles<br />
            
            <input id="button1" type="button" value="Clear markers" onclick="clearMarkers()">
          </form>


Full source code:

2 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. This looks very useful, but unfortunately is broken.
    In FF the map obscures the measurement boxes, and the 'Clear markers' does not work.
    In IE 10 the map doesn't display.

    In IE 10 compatability mode (for older browsers) it works.

    Any possibility you could fix it?

    ReplyDelete