Update: a lot of the javascript in this article was based on old code I wrote a while ago… thinking about it after I initially published the article I decided to rewrite it slightly. So previously I had one array for destinations, and three global arrays for labels, polylines and markers. It’s much simpler in this case just to have one global array which contains destinations, labels, polylines and markers.
So my previous post in this series added event listeners to polylines, this time I want to make the lines draggable. In this case I want to have one marker I can move around the map, and the polylines connecting it to the other markers will update to stay elastically-attached to the one draggable marker. And the distances will update automatically. Again we’re using the Label code courtesy of Marc Ridey (which I’m not going to repeat here, see my earlier blogpost). And the rest of the code remains quite similar to previously, with some key differences.
var arrDestinations;
function initialize() {
var map, i, j, latLng, stuDistances, inBetween, labelMarker;
arrDestinations = [
{title: 'Place A', lat: 34.602694, lng: -106.066132},
{title: 'Place B', lat: 33.917153, lng: -106.869736},
{title: 'Place C', lat: 34.254946, lng: -105.599442}
];
var stuHome = {title: 'Where I am', lat: 34.148181, lng: -106.17897};
var homeLatlng = new google.maps.LatLng(stuHome.lat, stuHome.lng);
var myOptions = {
zoom: 9,
center: homeLatlng,
mapTypeId: google.maps.MapTypeId.SATELLITE
};
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
var homeMarker = new google.maps.Marker({
position: homeLatlng,
map: map,
title: stuHome.title,
draggable: true
});
$('#tableNeighbours').append(
'<tr>'
+ '<th>Destination</th>'
+ '<th colspan="2">' + stuHome.title + '</th>'
+ '</tr>'
);
for (i = 0; i < arrDestinations.length; i++) {
latLng = new google.maps.LatLng(arrDestinations[i].lat, arrDestinations[i].lng);
arrDestinations[i].marker = new google.maps.Marker({
position: latLng,
map: map,
title: arrDestinations[i].title,
icon: 'http://maps.google.co.uk/intl/en_ALL/mapfiles/ms/micons/green-dot.png'
});
// draw lines between each marker and home. these are curved lines, not as the crow flies, i.e. they take into account the curvature of the earth (only noticable on longer distances)
arrDestinations[i].polyline = new google.maps.Polyline({
path: [homeLatlng, latLng],
strokeColor: "#FF0000",
strokeOpacity: 0.5,
strokeWeight: 4,
geodesic: true,
map: map
});
// calculate the distance between home and this marker
stuDistances = calculateDistances(homeLatlng, latLng);
$('#tableNeighbours').append(
'<tr id="row' + i + '">'
+ '<td>' + arrDestinations[i].title + '</td>'
+ '<td class="km">' + stuDistances.km + ' km</td>'
+ '<td class="miles">' + stuDistances.miles + ' miles</td>'
+ '</tr>'
);
// get the point half-way between this marker and the home marker
inBetween = google.maps.geometry.spherical.interpolate(homeLatlng, latLng, 0.5);
// create an invisible marker
labelMarker = new google.maps.Marker({
position: inBetween,
map: map,
visible: false
});
arrDestinations[i].label = new Label();
arrDestinations[i].label.bindTo('position', labelMarker, 'position');
arrDestinations[i].label.set('text', stuDistances.miles + ' miles');
arrDestinations[i].label.setMap(map);
}
// lets make the home marker draggable, but none of the others, just for illustrating how we can make the polylines move dynamically
google.maps.event.addListener(homeMarker, 'dragend', function() {
var i, stuDistance, inBetween, marker, markerLatLng;
var homeLatLng = homeMarker.getPosition();
// do this for each of the markers
for (i = 0; i < arrDestinations.length; i++) {
markerLatLng = arrDestinations[i].marker.getPosition();
arrDestinations[i].polyline.setPath([homeLatLng, markerLatLng]);
stuDistance = calculateDistances(homeLatLng, markerLatLng);
arrDestinations[i].label.set('text', stuDistance.miles + ' miles');
// update the position of the marker which the label is bound to
inBetween = google.maps.geometry.spherical.interpolate(homeLatLng, markerLatLng, 0.5);
marker = new google.maps.Marker({
position: inBetween,
map: map,
visible: false
});
arrDestinations[i].label.set('position', inBetween);
// update values in table
$('#row' + i + ' td.km').text(stuDistance.km + ' kilometres');
$('#row' + i + ' td.miles').text(stuDistance.miles + ' miles');
}
});
}
function calculateDistances(start,end) {
var stuDistances = {};
stuDistances.metres = google.maps.geometry.spherical.computeDistanceBetween(start, end); // distance in metres rounded to 1dp
stuDistances.km = Math.round(stuDistances.metres / 1000 *10)/10; // distance in km rounded to 1dp
stuDistances.miles = Math.round(stuDistances.metres / 1000 * 0.6214 *10)/10; // distance in miles rounded to 1dp
return stuDistances;
}
google.maps.event.addDomListener(window, 'load', initialize);
This time when creating the ‘homeMarker’ I make it draggable using this option: draggable: true.
I also added a class to each of the kilometres and miles cells, so they’re easy to identify later when I want to dynamically update them.
And the markers are appended into an array so we can use them later when dragging the centre marker.
And this time we make the labels appear automatically by calling label.setMap(map); as we create each marker, and I never remove them.
We then have a new event listener for the ‘dragend‘ event on the homeMarker. I’ve tried using ‘drag‘ instead, but it seemed slightly processor-intensive to use (although it did automatically redraw lines and distances as I dragged – now I’m just redrawing them when the user releases the marker).
And this is what I see. Dragging the red marker redraws the polylines and updates the distances on the labels:

…and the table underneath displays the distances in miles and km, and automatically updates along with the labels:
| Destination | Where I am | |
|---|---|---|
| Place A | 51.6 km | 32.1 miles |
| Place B | 68.7 km | 42.7 miles |
| Place C | 54.7 km | 34 miles |

























