Creating a Polyline Using Geolocation and the Google Maps
In Getting Directions Using the Google Maps API, I explained how to create a service that lets a user find a route from one address to another. In this article, you’ll learn how to use the Geolocation API together with the Google Maps API to display a polyline on a map that join several points.
This article assumes you’re familiar with the material in Working with Geolocation and the Google Maps API and Getting Directions Using the Google Maps API. If you haven’t read them yet, I suggest doing so now.
Do Even More with the Google Maps API
In the last two articles you’ve seen a lot of classes, methods, and properties, however, they were just a small piece of the Google Maps API puzzle. In this section you’ll see another piece of the API that we’ll use in the final demo.
The first class I’ll introduce is google.maps.Polyline
. It draws a line that connects several points, using the options (a google.maps.PolylineOptions
object) passed to the constructor. The methods of this class are just getters and setters, so I won’t go into too much detail, but keep in mind that the most important setters are setPath()
, that defines the points to join, and setMap()
, which sets the map where the line will be drawn.
The google.maps.PolylineOptions
class is full of properties that you can use to tune the polyline to fit your needs. The two most important are those underlying the setters described before – map
and path
. The stroke properties are also noteworthy, as they will be used in the demo. As the name implies, strokeColor
sets the stroke color, and defaults to #000000
(black). strokeOpacity
is a number between 0.0 and 1.0 that sets the stroke opacity. strokeWeight
is a number that sets the stroke width in pixels. I suggest reading the PolylineOptions official documentation to learn about other useful properties.
The demo also takes advantage of the google.maps.LatLngBounds
class. Citing the official documentation, a
. Its constructor accepts up to two parameters that, if given, must be LatLngBounds
represents a rectangle in geographical coordinates, including one that crosses the 180 degrees longitudinal meridianLatLng
instances. The first will be used as the south-west point of the rectangle, while the second acts as the north-east point. The only method that you’ll see in the demo is extend()
, which accepts a LatLng
point, and widens the current rectangle’s bounds to include it. Another method of the LatLngBounds
class is contains()
, which tests if a LatLng
coordinate is within the bounds or not. This class also has other useful methods which work with multiple rectangles. In fact, you can merge (union()
) or intersect (intersects()
) rectangles, but remember that you can only run the action on two LatLngBounds
instances at a time.
Building the Demo
To see the presented classes in action, let’s build a demo that saves the movements of the user, and draws a polyline that join them on a map. Because we must track the user’s movements, the demo uses the geolocation watchPosition()
method instead of getCurrentPosition()
. The positions will be stored in a variable called path
that is initialized to an empty array.
// Save the positions' history
var path = [];
When the watchPosition()
method runs the success callback function, the user’s latitude and longitude are used to build a google.maps.LatLng
object. That object will then be inserted in the path
array. And, for every new point added, the map will be refreshed to show the user’s movements.
// Save the current position
path.push(new google.maps.LatLng(position.coords.latitude, position.coords.longitude));
We also need to adjust the map view so that it contains all the points of the polyline. This is done with a LatLngBounds
object, stored in a variable called latLngBounds
. We need to loop over all the saved points and pass them, one at a time, to the extend()
method. Please note that, at the moment, we’re only preparing the data for use with the fitBounds()
method, so currently the map won’t fit the bounds. In addition, we’ll also mark every point using a Marker
object, so you can easily locate each position. The code that implements this is listed below.
// Create the LatLngBounds object that will be used to fit the view to the points range and
// place the markers to the polyline's points
var latLngBounds = new google.maps.LatLngBounds();
for(var i = 0; i < path.length; i++) {
latLngBounds.extend(path[i]);
// Place the marker
new google.maps.Marker({
map: map,
position: path[i],
title: "Point " + (i + 1)
});
}
Once you have the points to show, we need to build the polyline using the Polyline
and PolylineOptions
classes discussed earlier. This is very easy because you simply need to create a new Polyline
object with the desired options. In the code below, the stroke of the line has been changed to a one pixel wide, blue line, with 70% opacity.
// Creates the polyline object
var polyline = new google.maps.Polyline({
map: map,
path: path,
strokeColor: '#0000FF',
strokeOpacity: 0.7,
strokeWeight: 1
});
The only remaining step, is to ensure that the map’s view contains all of the points of the polyline. This is done by passing the latLngBounds
variable to the fitBounds()
method of the map, as shown below.
// Fit the bounds of the generated points
map.fitBounds(latLngBounds);
Adding Preset Points
Using the code above, we have a completely working demo. However, if you test the code in a desktop environment, the watchPosition()
method will only run once, so you won’t see any line drawn. To avoid this problem, you can copy the following piece of code and paste it before the block that loops over the path
array and builds the LatLngBounds
object. This code will simply create and insert into the path
array a small set of randomly generated points using the user’s current position.
// Create the polyline's points
for(var i = 0; i < 5; i++) {
// Create a random point using the user current position and a random generated number.
// The number will be once positive and once negative using based on the parity of i
// and to reduce the range the number is divided by 10
path.push(
new google.maps.LatLng(
position.coords.latitude + (Math.random() / 10 * ((i % 2) ? 1 : -1)),
position.coords.longitude + (Math.random() / 10 * ((i % 2) ? 1 : -1))
)
);
}
Demo Page
Using the code shown in the previous sections, the final working demo page is listed below.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Create a polyline using Geolocation and Google Maps API</title>
<script src="http://maps.google.com/maps/api/js?sensor=true"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script>
$(document).ready(function() {
// If the browser supports the Geolocation API
if (typeof navigator.geolocation == "undefined") {
$("#error").text("Your browser doesn't support the Geolocation API");
return;
}
// Save the positions' history
var path = [];
navigator.geolocation.watchPosition(function(position) {
// Save the current position
path.push(new google.maps.LatLng(position.coords.latitude, position.coords.longitude));
// Create the map
var myOptions = {
zoom : 16,
center : path[0],
mapTypeId : google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(document.getElementById("map"), myOptions);
/*
Uncomment this block if you want to set a path
// Create the polyline's points
for(var i = 0; i < 5; i++) {
// Create a random point using the user current position and a random generated number.
// The number will be once positive and once negative using based on the parity of i
// and to reduce the range the number is divided by 10
path.push(
new google.maps.LatLng(
position.coords.latitude + (Math.random() / 10 * ((i % 2) ? 1 : -1)),
position.coords.longitude + (Math.random() / 10 * ((i % 2) ? 1 : -1))
)
);
}
*/
// Create the array that will be used to fit the view to the points range and
// place the markers to the polyline's points
var latLngBounds = new google.maps.LatLngBounds();
for(var i = 0; i < path.length; i++) {
latLngBounds.extend(path[i]);
// Place the marker
new google.maps.Marker({
map: map,
position: path[i],
title: "Point " + (i + 1)
});
}
// Creates the polyline object
var polyline = new google.maps.Polyline({
map: map,
path: path,
strokeColor: '#0000FF',
strokeOpacity: 0.7,
strokeWeight: 1
});
// Fit the bounds of the generated points
map.fitBounds(latLngBounds);
},
function(positionError){
$("#error").append("Error: " + positionError.message + "<br />");
},
{
enableHighAccuracy: true,
timeout: 10 * 1000 // 10 seconds
});
});
</script>
<style type="text/css">
#map {
width: 500px;
height: 400px;
margin-top: 10px;
}
</style>
</head>
<body>
<h1>Create a polyline</h1>
<div id="map"></div>
<p id="error"></p>
</body>
</html>
Conclusion
This article explained the classes, properties, and methods used to draw a polyline that joins several points on a map. As you’ve seen throughout this series of articles, these APIs can be used to build a lot of great services which enhance your users’ experience. Of course, you can do much more than what has been shown here. By exploring the other classes in the Google Maps API, the possibilities are virtually endless.