Javascript Ruler for Google Maps v3 to measure distance on map

Javascript example for measuring distances on a Google Maps with a ruler.

Dicembre 19, 2009

[October 2019] A few years ago, I’ve made this ruler to measure distances on a Google Map, I’ve noticed it’s still a searched page so I’ve made some updates to keep it working.

The file Ruler.js contains a two functions: one is used to calculate the distance between two points on the map with their position expressed in decimal degrees, and one function that physically add the ruler to the canvas of the map. Ther ruler is composed with two standard Google markers, and a poly object is used to track the line. Two labels which show the distance are placed near the markes. The labels are placed on the map with the Labels.js class from Marc Ridley (you can reach is old blog here).

A working demo to find distance google maps is available, and you can play with it, to download the javascript files used click on these links: ruler.js, labels.js.

Instructions to use ruler.js

  1. First you have to register an API Key to use Google Maps objects in your site. When you have done this you can include Google scripts to enable maps on your site.
  2. In your HTML file place a div and add an attribute id with value map_canvas. Here Google will place your map. Style it with an height to see it.
  3. On load of the page call a function to create the map. The function is simple and just declare the object of the map, the position and the initial zoom (you can find the code in the ruler.js file).
  4. Call addruler(); function to add the ruler to the map.

Here is the intial code for ruler.js with the addruler method, the file now is a bit changed and has more features:

function addruler() {

	ruler1 = new google.maps.Marker({
		position: map.getCenter() ,
		map: map,
		draggable: true
	});

	ruler2 = new google.maps.Marker({
		position: map.getCenter() ,
		map: map,
		draggable: true
	});

	var ruler1label = new Label({ map: map });
	var ruler2label = new Label({ map: map });
	ruler1label.bindTo('position', ruler1, 'position');
	ruler2label.bindTo('position', ruler2, 'position');

	rulerpoly = new google.maps.Polyline({
		path: [ruler1.position, ruler2.position] ,
		strokeColor: "#FFFF00",
		strokeOpacity: .7,
		strokeWeight: 8
	});
	rulerpoly.setMap(map);

	ruler1label.set('text',"0m");
	ruler2label.set('text',"0m");

	google.maps.event.addListener(ruler1, 'drag', function() {
		rulerpoly.setPath([ruler1.getPosition(), ruler2.getPosition()]);
		ruler1label.set('text',distance( ruler1.getPosition().lat(), ruler1.getPosition().lng(), ruler2.getPosition().lat(), ruler2.getPosition().lng()));
		ruler2label.set('text',distance( ruler1.getPosition().lat(), ruler1.getPosition().lng(), ruler2.getPosition().lat(), ruler2.getPosition().lng()));
	});

	google.maps.event.addListener(ruler2, 'drag', function() {
		rulerpoly.setPath([ruler1.getPosition(), ruler2.getPosition()]);
		ruler1label.set('text',distance( ruler1.getPosition().lat(), ruler1.getPosition().lng(), ruler2.getPosition().lat(), ruler2.getPosition().lng()));
		ruler2label.set('text',distance( ruler1.getPosition().lat(), ruler1.getPosition().lng(), ruler2.getPosition().lat(), ruler2.getPosition().lng()));
	});

}

And this is the function to calculate distance in meters (km). To change the units modify the constant using the um variable:

function distance(lat1,lon1,lat2,lon2) {
	var um = "km"; // km | ft (choose the constant)
	var R = 6371;
	if (um=="ft") {
		R = 20924640; // ft
	}
	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;
	if(um=="km") {
		if (d>1) return Math.round(d)+"km";
		else if (d<=1) return Math.round(d*1000)+"m";
	}
	if(um=="ft"){
		if ((d/5280)>=1) return Math.round((d/5280))+"mi";
		else if ((d/5280)<1) return Math.round(d)+"ft";
	}
	return d;
}

Author

PHP expert. Wordpress plugin and theme developer. Father, Maker, Arduino and ESP8266 enthusiast.

Comments on “Javascript Ruler for Google Maps v3 to measure distance on map”

19 thoughts

  1. bob ha detto:

    “var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));” can be simplified to “var c = 2 * Math.asin(Math.sqrt(a));”

  2. Kaese ha detto:

    True – what Bob says

  3. ABM Adnan ha detto:

    Thanks a lot man! You saved my life.

    Just one little thing, there is a very little bug in labels.js (I know you didn’t write it)
    On line 44:
    maps.google.event.removeListener(this.listeners_[i]);

    this should be:
    google.maps.event.removeListener(this.listeners_[i]);

    Regards
    Adnan

  4. anil singh ha detto:

    thanks. will visit again

    on a learning curve.

  5. admin ha detto:

    Right. I’ve fixed it. Thank you.

  6. piero ha detto:

    Excellent. Good job: my congratulation.
    It would useful also to have a couple of additional features:
    1)replace the couple of labels with a single label placed in the middle of the ruler line, alway on top (I tried using zIndex with no success? any idea ?)
    2)the rule line binded to the objects you’re measuring the distance. Suppose we would like to continously track the distance changes among a couple of moving markers (i.e. vehicles).

    PG Ornolio

  7. phicarre ha detto:

    Hello,
    If I attribute an icon to the rulers then the behaviour changes !
    How to change the standard icons ?

    Thank you.

  8. pani100 ha detto:

    Really good and handy code.
    If i wanted to change the distance to miles would this be correct?
    function distance(lat1,lon1,lat2,lon2) {
    var R = 3959; // km (change this constant to get miles. 3959 for m, 6371 for km also change 1000 to 1760)
    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;
    if (d>1) return Math.round(d)+”miles”;
    else if (d<=1) return Math.round(d*1760)+"yards";
    return d;

    Regards
    Pani

  9. How do you remove a ruler?

  10. Francisco ha detto:

    how do you remove a ruler,,, can you helps us

  11. Marius ha detto:

    Very nice, i also though want to know how to remove the ruler ?

  12. Marius ha detto:

    I changed the script a bit, and now you can remove the ruler. Simply pass a ‘true’ or ‘false’ to the addruler call

    var ruler1;
    var ruler2;
    var ruler1label;
    var ruler2label;
    var rulerpoly;

    function addruler(remove) {

    if (remove) {
    google.maps.event.clearListeners(ruler1, ‘drag’);
    ruler1.setMap(null);
    google.maps.event.clearListeners(ruler2, ‘drag’);
    ruler2.setMap(null);
    ruler1label.setMap(null);
    ruler2label.setMap(null);
    rulerpoly.setMap(null);
    }
    else {
    ruler1 = new google.maps.Marker({
    position: map.getCenter(),
    map: map,
    title: ‘Starting Point’,
    draggable: true
    });

    ruler2 = new google.maps.Marker({
    position: map.getCenter(),
    map: map,
    title: ‘End Point’,
    draggable: true
    });
    ruler1label = new Label({ map: map });
    ruler2label = new Label({ map: map });
    ruler1label.bindTo(‘position’, ruler1, ‘position’);
    ruler2label.bindTo(‘position’, ruler2, ‘position’);

    rulerpoly = new google.maps.Polyline({
    path: [ruler1.position, ruler2.position],
    strokeColor: “#FFFF00″,
    strokeOpacity: .7,
    strokeWeight: 7
    });

    rulerpoly.setMap(map);

    ruler1label.set(‘text’, distance(ruler1.getPosition().lat(), ruler1.getPosition().lng(), ruler2.getPosition().lat(), ruler2.getPosition().lng()));
    ruler2label.set(‘text’, distance(ruler1.getPosition().lat(), ruler1.getPosition().lng(), ruler2.getPosition().lat(), ruler2.getPosition().lng()));

    google.maps.event.addListener(ruler1, ‘drag’, function() {
    rulerpoly.setPath([ruler1.getPosition(), ruler2.getPosition()]);
    ruler1label.set(‘text’, distance(ruler1.getPosition().lat(), ruler1.getPosition().lng(), ruler2.getPosition().lat(), ruler2.getPosition().lng()));
    ruler2label.set(‘text’, distance(ruler1.getPosition().lat(), ruler1.getPosition().lng(), ruler2.getPosition().lat(), ruler2.getPosition().lng()));
    });

    google.maps.event.addListener(ruler2, ‘drag’, function() {
    rulerpoly.setPath([ruler1.getPosition(), ruler2.getPosition()]);
    ruler1label.set(‘text’, distance(ruler1.getPosition().lat(), ruler1.getPosition().lng(), ruler2.getPosition().lat(), ruler2.getPosition().lng()));
    ruler2label.set(‘text’, distance(ruler1.getPosition().lat(), ruler1.getPosition().lng(), ruler2.getPosition().lat(), ruler2.getPosition().lng()));
    });
    }

    }

    function distance(lat1,lon1,lat2,lon2) {
    var R = 6371; // km (change this constant to get miles)
    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;
    if (d>1) return Math.round(d)+”km”;
    else if (d<=1) return Math.round(d*1000)+"m";
    return d;
    }

  13. Marius ha detto:

    Sorry, I lied. It works when i test it locally, but does not work when i put it on the live server :(

  14. Marius ha detto:

    I am a dumb ass – It still had the old version in cache, so make sure you clear the cache so it gets the new js file, then it works :)

  15. Francisco ha detto:

    thanks a lot

  16. Rohit ha detto:

    Nice article

  17. Jason Maggard ha detto:

    Thank you very much for the code. We have a situation here where we need to do site surveys, and to help our salespeople I have set up a Google map they can add markers to. However, I took your code one step further, and thought I’d share.

    This version of the code stores the rulers in an array and outputs a line for each one where our salesmen can put in the other information we need. At the end of each line, there is a “Delete Ruler” button. It deletes the line and the ruler from the page.


    // Quasi global array of all of the lines we've added.
    var lines = new Array();

    function addruler() {
    var ruler1 = new google.maps.Marker({
    position: map.getCenter() ,
    map: map,
    draggable: true
    });
    var ruler2 = new google.maps.Marker({
    position: map.getCenter() ,
    map: map,
    draggable: true
    });
    var ruler1label = new Label({ map: map });
    var ruler2label = new Label({ map: map });
    ruler1label.bindTo('position', ruler1, 'position');
    ruler2label.bindTo('position', ruler2, 'position');
    var rulerpoly = new google.maps.Polyline({
    path: [ruler1.position, ruler2.position] ,
    strokeColor: "#0098b5",
    strokeOpacity: .7,
    strokeWeight: 7
    });
    rulerpoly.setMap(map);
    ruler1label.set('text',distance( ruler1.getPosition().lat(), ruler1.getPosition().lng(), ruler2.getPosition().lat(), ruler2.getPosition().lng()));
    ruler2label.set('text',distance( ruler1.getPosition().lat(), ruler1.getPosition().lng(), ruler2.getPosition().lat(), ruler2.getPosition().lng()));
    google.maps.event.addListener(ruler1, 'drag', function() {
    rulerpoly.setPath([ruler1.getPosition(), ruler2.getPosition()]);
    ruler1label.set('text',distance( ruler1.getPosition().lat(), ruler1.getPosition().lng(), ruler2.getPosition().lat(), ruler2.getPosition().lng()));
    ruler2label.set('text',distance( ruler1.getPosition().lat(), ruler1.getPosition().lng(), ruler2.getPosition().lat(), ruler2.getPosition().lng()));
    });
    google.maps.event.addListener(ruler2, 'drag', function() {
    rulerpoly.setPath([ruler1.getPosition(), ruler2.getPosition()]);
    ruler1label.set('text',distance( ruler1.getPosition().lat(), ruler1.getPosition().lng(), ruler2.getPosition().lat(), ruler2.getPosition().lng()));
    ruler2label.set('text',distance( ruler1.getPosition().lat(), ruler1.getPosition().lng(), ruler2.getPosition().lat(), ruler2.getPosition().lng()));
    });
    // Add our new ruler to an array for later reference
    lines.push([ruler1, ruler2, ruler1label, ruler2label, rulerpoly]);
    addLine(lines.length - 1);
    }

    function addLine (num) {
    // This function adds a line to our page.
    var div = document.getElementById('latlon');
    var oldHTML = document.getElementById('latlon').innerHTML;
    div.innerHTML = oldHTML + "YesNo Delete Ruler";
    // Set up the event handler for the remove ruler button
    document.getElementById('delruler' + num).onclick = function() {removeLine(num); return false;}
    }

    function removeLine (num) {
    // Removes the line from our HTML page
    var div = document.getElementById('ruler' + num);
    div.parentNode.removeChild(div);
    removeRuler(lines[num]);
    }

    function removeRuler (r) {
    // Now we remove the ruler.
    // I've unpacked the variables for readability.
    var ruler1=r[0]; var ruler2=r[1]; var ruler1label=r[2]; var ruler2label=r[3]; var rulerpoly=r[4];
    google.maps.event.clearListeners(ruler1, 'drag');
    ruler1.setMap(null);
    google.maps.event.clearListeners(ruler2, 'drag');
    ruler2.setMap(null);
    ruler1label.setMap(null);
    ruler2label.setMap(null);
    rulerpoly.setMap(null);
    }

    function distance(lat1,lon1,lat2,lon2) {
    var R = 3959; // Here's the right settings for miles and feet
    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;
    if (d>1) return Math.round(d)+"mi";
    else if (d<=1) return Math.round(d*5280)+"ft";
    return d;
    }

    Again, thanks for publishing this. You saved me a day or two.

  18. Jason Maggard ha detto:

    Ooops, this ate my HTML…


    div.innerHTML = oldHTML + "YesNo Delete Ruler";

    Long story short, there was a bunch of HTML in here. Longer story shorter, you don’t need it.

    The trick that makes this work however, is that the button id is

    id='delruler" + num + "'

    So that the event handler attaches the button to the right ruler.


    document.getElementById('delruler' + num).onclick = function() {removeLine(num); return false;}

    Notice that in the getElementById, we name each div delruler1, delruler2, etc…

  19. Bernhard Konrad ha detto:

    Nice code, thanks for sharing! As noted in the comments above, it would be nice to have the option to delete a ruler. My solution to this was that a double-click on one of the markers deletes the ruler. Simply add


    google.maps.event.addListener(ruler1, 'dblclick', function() {
    ruler1.setMap(null);
    ruler2.setMap(null);
    ruler1label.setMap(null);
    ruler2label.setMap(null);
    rulerpoly.setMap(null);
    });

    google.maps.event.addListener(ruler2, 'dblclick', function() {
    ruler1.setMap(null);
    ruler2.setMap(null);
    ruler1label.setMap(null);
    ruler2label.setMap(null);
    rulerpoly.setMap(null);
    });

    to the end of the addruler function.

Comments are closed

Recommended

New Facebook Invite all friends hack

So, you want to invote all your friends but the old hack doesn’t work anymore? With the last facebook friends…

Settembre 14, 2011

How to write a text description into html input type password

Sometime designers put form labels and instrucions into html inputs. One of the common uses is for login boxes when…

Marzo 10, 2010

Decimal Degrees conversion and distance of two points on google map

Those two functions are usefull when you’re making Google Maps applications: When you show the coordinates of a point, it’s…

Dicembre 26, 2009

Clustering many markers with Google Maps v3

I’ve found this blog where Matthias Burtscher converted the Marker Cluster (like the Phoogle2) for Google Maps API v.3. Since…

Dicembre 13, 2009

Full Screen GControl for Google Maps

Use with phoogle modified class: (see an example here) To use it in the phoogle modified class just turn it…

Novembre 13, 2009