Creating a Polyline Using Geolocation and the Google Maps

Aurelio De Rosa
Share

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 LatLngBounds represents a rectangle in geographical coordinates, including one that crosses the 180 degrees longitudinal meridian. Its constructor accepts up to two parameters that, if given, must be LatLng 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.