Duncan's blog

March 21, 2015

Google Maps API – locked draggable markers

Filed under: Google Maps,Javascript — duncan @ 1:53 pm
Tags: , , ,

This is a nice simple post, inspired by a recent question on StackOverflow:

How to check if marker is out of specific constant bounds?

In summary, the user had defined a bounds, and wanted users to be able to drag a marker, but not outside of those bounds.

So firstly, you can simply use the LatLngBounds contains’ function to determine if a point is within those bounds.  And you can have an event listener for when the user drags the marker.  Usually you’d just want to check for the dragend event, when they stop dragging.

In this example I’ve drawn a semi-transparent rectangle using the bounds, so it’s obvious the area where you can drag your marker in.

I also keep track of the coordinates the marker had when they start dragging it.  If they go outside of the bounds, I reset it to that position.

Initial state of the map:

bounds map1

And after the user drags the marker outside of the bounds:

bounds map2

Here’s the code:

<!DOCTYPE html>
<html>
<head>
	<title>Locked draggable markers</title>
	<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
	<meta charset="utf-8">
	<style>
		#map {
			width: 640px; height: 480px;
		}
	</style>
	<script src="https://maps.googleapis.com/maps/api/js?v=3"></script>
	<script>
		function initialize() {
			var bounds = new google.maps.LatLngBounds(
				new google.maps.LatLng(51.5089872,-0.155157), 
				new google.maps.LatLng(51.599285,0.032984)
			);
			
			var map = new google.maps.Map(document.getElementById("map"), {
			  center: bounds.getCenter(),
			  zoom: 13,
			  mapTypeId: google.maps.MapTypeId.ROADMAP
			});
			
			map.fitBounds(bounds);
			
			var rectangle = new google.maps.Rectangle({
				bounds: bounds,
				map: map,
				fillOpacity: 0.2,
				fillColor: 'blue',
				strokeOpacity: 0
			});
					 
			var marker=new google.maps.Marker({
				map: map,
				position: bounds.getCenter(),
				draggable: true
			});
				
			var markerPosition;

			google.maps.event.addListener(marker, 'dragstart', function() {
				markerPosition = this.getPosition();
			});

			google.maps.event.addListener(marker, 'dragend', function() {
				if (bounds.contains(this.getPosition()) == false) {
					alert("You've dragged the marker outside of the bounds allowed. We've reset it");
					
					this.setPosition(markerPosition);
				}
			});
		}
		
		google.maps.event.addDomListener(window, 'load', initialize);
	</script>
</head>
<body>
	<div id="map"></div>
</body>
</html>

You’ll noticed I’m only declaring coordinates for the Bounds, and then getting the Bounds’ centre, and using that to plot the centre of the map and the initial coordinates for the marker.  And then making the map fit the bounds object.

One interesting note; The Google Maps API has started accepting coordinates in a lot of its classes in this shorthand format:

 {lat: x, lng: y}

… instead of having to create a new LatLng object every time:

 new google.maps.LatLng(x, y)

However, this doesn’t seem to work (yet) with the Bound class.

 

Secondly, as well as a bounds object, it might be useful to do the same thing on a polygon that you’ve drawn on the map.  This is slightly more complicated; the google.maps.Polygon class hasn’t got a contains event.  However the Geometry library does.  You need to load it in when you specify the Maps API URL:

<script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=geometry"></script>

Here I’ve just plotted a polygon roughly corresponding to the border of Utah:

Locked_draggable_markers_-_2015-03-21_13.34.50

I construct that initially as an array of LatLng points.

var boundary = [
    new google.maps.LatLng(41.987058, -114.007506),
    new google.maps.LatLng(41.987058, -111.063170),
    new google.maps.LatLng(40.999595, -111.063170),
    new google.maps.LatLng(40.999595, -109.041686),
    new google.maps.LatLng(37.005844, -109.063658),
    new google.maps.LatLng(37.005844, -114.051451)
];

I then loop over the array, adding each coordinate to a bounds object.

var bounds = new google.maps.LatLngBounds();

for(var i = 0; i < boundary.length; i++) {
    bounds.extend(boundary[i]);
}

Then I use the array of coordinates (not the bounds), to plot the path for a polygon object.

var polygon = new google.maps.Polygon({
    paths: boundary,
    map: map,
    fillOpacity: 0.2,
    fillColor: 'blue',
    strokeOpacity: 0
});

And finally just a slight change to the event listener, to check if the polygon contains the marker’s position.

google.maps.event.addListener(marker, 'dragend', function() {
    if (google.maps.geometry.poly.containsLocation(this.getPosition(), polygon) == false) {
        alert("You've dragged the marker outside of the bounds allowed. We've reset it");
            
        this.setPosition(markerPosition);
    }
});

Nice and simple!

Leave a Comment »

No comments yet.

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

Blog at WordPress.com.

%d bloggers like this: