paullb
paullb

Reputation: 4325

GoogleMaps Polyline Length in V3

There doesn't seem to be a length funciton for the Polyline in Google Maps anymore in V3.

Has anyone found a workaround for this functionality gap?

Upvotes: 1

Views: 20371

Answers (7)

geocodezip
geocodezip

Reputation: 161334

There is now a method in the Google Maps Javascript API v3 geometry library to compute the distance between two google.maps.LatLng objects in meters google.maps.geometry.spherical.computeDistanceBetween.

And a method in the Google Maps Javascript API v3 geometry library to compute the length of a polyline google.maps.geometry.poly.computeLength.

Concept from the Google Maps JavaScript API v3 groups post referenced in Hamish's answer, but using the Google Maps Javascript API v3 geometry library method computeDistanceBetween:

google.maps.Polyline.prototype.inKm = function(n) {
  var a = this.getPath(n),
    len = a.getLength(),
    dist = 0;
  for (var i = 0; i < len - 1; i++) {
    dist += google.maps.geometry.spherical.computeDistanceBetween(a.getAt(i), a.getAt(i + 1));
  }
  return dist / 1000;
}

The result is the length of the polyline in kilometers. The optional parameter is the path index of multi path polylines.

proof of concept fiddle

Using computeLength:

google.maps.geometry.spherical.computeLength(poly.getPath())/1000

proof of concept fiddle

code snippet:

var map;
var poly;
var gmarkers = [];

function initialize() {
  map = new google.maps.Map(
    document.getElementById("map_canvas"), {
      center: new google.maps.LatLng(37.4419, -122.1419),
      zoom: 11,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    });
  google.maps.event.addListener(map, 'click', addLatLng);
  var polyCoord = [
    new google.maps.LatLng(41.86, 8.73),
    new google.maps.LatLng(41.88, 8.75)
  ];
  var bounds = new google.maps.LatLngBounds();
  bounds.extend(polyCoord[0]);
  bounds.extend(polyCoord[1]);
  map.fitBounds(bounds);
  google.maps.event.addListenerOnce(map, 'bounds_changed', function() {
    map.setZoom(map.getZoom() - 2);
  });
  // Polyline
  poly = new google.maps.Polyline({
    path: polyCoord
  });
  poly.binder = new MVCArrayBinder(poly.getPath());
  var marker0 = new google.maps.Marker({
    position: event.latLng,
    title: '#0',
    map: map,
    icon: {
      path: 'M256,320c-70.688,0-128-57.312-128-128c0-70.687,57.313-128,128-128c70.688,0,128,57.313,128,128C384,262.688,326.688,320,256,320z',
      fillColor: 'white',
      fillOpacity: 1,
      scale: 0.025,
      strokeColor: 'black',
      strokeWeight: 1,
      strokeOpacity: 1,
      anchor: new google.maps.Point(200, 200)
    },
    draggable: true
  });
  marker0.bindTo('position', poly.binder, (0).toString());
  google.maps.event.addListener(marker0, 'dragend', updateLength);
  gmarkers.push(marker0);
  var marker1 = new google.maps.Marker({
    position: event.latLng,
    title: '#1',
    map: map,
    icon: {
      path: 'M256,320c-70.688,0-128-57.312-128-128c0-70.687,57.313-128,128-128c70.688,0,128,57.313,128,128C384,262.688,326.688,320,256,320z',
      fillColor: 'white',
      fillOpacity: 1,
      scale: 0.025,
      strokeColor: 'black',
      strokeWeight: 1,
      strokeOpacity: 1,
      anchor: new google.maps.Point(200, 200)
    },
    draggable: true
  });
  marker1.bindTo('position', poly.binder, (1).toString());
  google.maps.event.addListener(marker1, 'dragend', updateLength);
  gmarkers.push(marker1);
  poly.setMap(map);
  updateLength();
}

function updateLength() {
  document.getElementById('length').value = (google.maps.geometry.spherical.computeLength(poly.getPath()) / 1000).toFixed(2);
};
google.maps.event.addDomListener(window, "load", initialize);

/**
 * Handles click events on a map, and adds a new point to the Polyline.
 * @param {MouseEvent} mouseEvent
 */
function addLatLng(event) {
  var path = poly.getPath();
  path.push(event.latLng);
  var len = path.getLength();
  var marker = new google.maps.Marker({
    position: event.latLng,
    title: '#' + len,
    map: map,
    icon: {
      path: 'M256,320c-70.688,0-128-57.312-128-128c0-70.687,57.313-128,128-128c70.688,0,128,57.313,128,128C384,262.688,326.688,320,256,320z',
      fillColor: 'white',
      fillOpacity: 1,
      scale: 0.025,
      strokeColor: 'black',
      strokeWeight: 1,
      strokeOpacity: 1,
      anchor: new google.maps.Point(200, 200)
    },
    draggable: true
  });
  gmarkers.push(marker);
  marker.bindTo('position', poly.binder, (len - 1).toString());
  google.maps.event.addListener(marker, 'dragend', updateLength);
  document.getElementById('length').value = poly.inKm().toFixed(2);
}

/*
 * Use bindTo to allow dynamic drag of markers to refresh poly.
 */

function MVCArrayBinder(mvcArray) {
  this.array_ = mvcArray;
}
MVCArrayBinder.prototype = new google.maps.MVCObject();
MVCArrayBinder.prototype.get = function(key) {
  if (!isNaN(parseInt(key))) {
    return this.array_.getAt(parseInt(key));
  } else {
    this.array_.get(key);
  }
}
MVCArrayBinder.prototype.set = function(key, val) {
  if (!isNaN(parseInt(key))) {
    this.array_.setAt(parseInt(key), val);
  } else {
    this.array_.set(key, val);
  }
}
html,
body,
#map_canvas {
  height: 100%;
  width: 100%;
  margin: 0px;
  padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<label>polyline length (km):</label>
<input id="length" type="text" />
<div id="map_canvas" style="border: 2px solid #3872ac;"></div>

Upvotes: 5

TyGuy
TyGuy

Reputation: 21

I went looking for the same information and found that the api call you're looking for is in the geometry.spherical namespace.

Here's the code I'm using:

//Path is the mvc array of lat/lng that makes up the polyline
var path = $scope.courseLine.getPath();

$scope.totalDistance = google.maps.geometry.spherical.computeLength(path);
$scope.totalMiles = ($scope.totalDistance * 0.00062137).toFixed(2) + " mi";
                });

Upvotes: 2

Anderson
Anderson

Reputation: 2752

If you got the polyline from DirectionsService, check distance and duration in DirectionsLeg.

https://developers.google.com/maps/documentation/javascript/reference#DirectionsLeg

Upvotes: 1

D K
D K

Reputation: 271

<script type="text/javascript"
src="http://maps.google.com/maps/api/js?libraries=geometry&sensor=true"></script>
... var path = poly.getPath(); // or:
var path = polygon.getPath(); 
... = google.maps.geometry.spherical.computeLength(path.getArray())
... = google.maps.geometry.spherical.computeArea(path.getArray())

--> distance for polyline, area for polygon

and between two points: computeDistanceBetween()

Don't forget to specify the geometry library (libraries=geometry)

http://code.google.com/apis/maps/documentation/javascript/geometry.html

Upvotes: 19

Martin Zeitler
Martin Zeitler

Reputation: 76669

here's the prototypes for the required function - hope this helps any further:

google.maps.Polygon.prototype.Distance = function() {
   var dist = 0;
   for (var i=1; i < this.getPath().getLength(); i++) {
      dist += this.getPath().getAt(i).distanceFrom(this.getPath().getAt(i-1));
   }
   return dist;
}

google.maps.LatLng.prototype.distanceFrom = function(newLatLng) {
    //var R = 6371; // km (change this constant to get miles)
    var R = 6378100; // meters
    var lat1 = this.lat();
    var lon1 = this.lng();
    var lat2 = newLatLng.lat();
    var lon2 = newLatLng.lng();
    var dLat = (lat2-lat1) * Math.PI / 180;
    var dLon = (lon2-lon1) * Math.PI / 180;
    var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
      Math.cos(lat1 * Math.PI / 180 ) * Math.cos(lat2 * Math.PI / 180 ) *
      Math.sin(dLon/2) * Math.sin(dLon/2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    var d = R * c;
    return d;
}

source

Upvotes: 5

Galen
Galen

Reputation: 30170

Get the distance between the 2 LatLngs it connects using the haversine formula

Upvotes: 0

Hamish
Hamish

Reputation: 23316

It has to be done segment by segment.

See this Google Maps JavaScript API v3 groups post for a suggested solution.

Upvotes: 4

Related Questions