Duncan's blog

March 1, 2013

Google Maps API – draggable polylines

Filed under: Google Maps,Javascript — duncan @ 6:26 pm
Tags: , , , ,

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:
new mexico

…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
Advertisements

5 Comments »

  1. Thanks for all this code samples, but is it possible to edit a marker and the polyline comes along?
    I mean i have an array of markers built in some with coords from database that already has for loop to go thru every single one of the records, now i have a marker that i can delete and move but i am no able to make the poly adjust when i do that, can you give me some hints?

    Thanks

    Comment by Nelson — September 11, 2013 @ 9:43 pm | Reply

  2. Can you show me your code so far? Put it on pastebin or something similar. Alternatively you might get some good answers if you ask this on StackOverflow

    Comment by duncan — September 11, 2013 @ 10:11 pm | Reply

  3. Here is my code so far for the marker and poly, everything is working and i want to add the update poly function inside my. Thanks

    http://pastebin.com/xnLFtdp1

    Comment by umanoitedecarnaval — September 12, 2013 @ 9:10 am | Reply

  4. Here’s a new blog post illustrating how I would do it. There may be better ways, but that’s what comes to mind without me looking for anyone else’s implementations. Let me know if that doesn’t really address your problem though:
    https://duncan99.wordpress.com/2013/09/12/draggable-polyline-markers/

    Comment by duncan — September 12, 2013 @ 6:40 pm | Reply

  5. […] response to a comment on a previous post I did with draggable polylines, I wrote this little example.  I’ve drawn a polyline along […]

    Pingback by Draggable polyline markers | Duncan's blog — September 12, 2013 @ 6:41 pm | Reply


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: