Sunday, June 17, 2018

Drawing Multiple Routes In One Map with Google Map

Lots of examples in Google Map tutorials and examples are about drawing directions, markers, searches - and all of them typically involve only drawing one set of markers into a "route". An example of this will be going from Boston, MA to Seattle, WA via Cleveland, OH then Chicago, IL. But I need to be make Google Map to draw multiple routes in a single map.

The purpose of this task is to compare the routes. Assuming, like the example above, I am going from Boston to Seattle - which route will be better? Or maybe closer to passing Detroit?

Or another use case: if my friend and I are both traveling out of NYC on 2 separate cars, I am going to Columbus, OH and my friend is going to Detroit, MI - and another friend needs to be dropped off in State College, PA - so which car should this friend join - my car or the other car?

So here is how you do it.
FIRST - you will need to get Google Map Javascript API Key - you can get it here. Once you get it and enable the needed APIs, you will need to use it in your script reference below.

SECOND - in your HTML markup - add script reference Google Map and substituting the YOUR_API_KEY with your real API key from above.
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
    #map {
        margin-top: 10px;
        height: 750px;
        width: 100%;
    }
</style>
</head>
<body>
 <div id="map"></div>
 <script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap" type="text/javascript"></script>
</body>
</html>
THIRD - initialize several global variables and create a javascript method called "initMap" - this is to initialize your map once the script from Google is loaded.
var routeMapArray = [];
var map;
var defaultZoom = 11;
var directionsService;
var directionDisplayRenderEngineArray = [];
var iconColor = '';

function initMap() {
  routeMapArray = [];
  directionsService = new google.maps.DirectionsService();

  // center initially on NYC
  loadMap(new google.maps.LatLng(40.7128, -74.0060));
}
FOURTH - Create a method called "loadMap" that takes 1 parameter and create a json payload for your routes.
var loadMap = function(center) {
  var mapOptions = {
    zoom: 11,
    mapTypeControl: false,
    streetViewControl: false,
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };

  if (center !== undefined && center !== null) {
    mapOptions.center = center;
  }

  // Some basic map setup (from the API docs)
  map = new google.maps.Map(document.getElementById('map'), mapOptions);

  // Start the request making
  var requestArray = [{
      "origin": "New York, NY",
      "destination": "Seattle, WA",
      "waypoints": [{
          "location": "Detroit, MI",
          "stopover": true
        },
        {
          "location": "Denver, CO",
          "stopover": true
        }
      ],
      "travelMode": "DRIVING"
    },
    {
      "origin": "Boston, MA",
      "destination": "San Diego, CA",
      "waypoints": [{
          "location": "Dayton, OH",
          "stopover": true
        },
        {
          "location": "Las Vegas, NV",
          "stopover": true
        }
      ],
      "travelMode": "DRIVING"
    }
  ];
  processRequests(requestArray);
};
FIFTH - We need to process the requests in order, one by one - using different renderer each time on the same map (this is the key).
var processRequests = function(requestArray) {
  var bounds = new google.maps.LatLngBounds();
  var infoWindow = new google.maps.InfoWindow();

  // Counter to track request submission and process one at a time;
  var i = 0;
  var position = "";

  // Used to submit the request 'i'
  var submitRequest = function() {
    if (requestArray.length === 0) return;
    directionsService.route(requestArray[i], processDirectionResults);
  };

  // Used as callback for the above request for current 'i'
  function processDirectionResults(result, status) {
    if (status === google.maps.DirectionsStatus.OK) {
      // Create a unique DirectionsRenderer 'i'
      directionDisplayRenderEngineArray[i] = new google.maps.DirectionsRenderer();
      directionDisplayRenderEngineArray[i].setMap(map);

      if (i == 0) {
        bounds = new google.maps.LatLngBounds();
      }
      iconColor = "#000000";

      directionDisplayRenderEngineArray[i].setOptions({
        preserveViewport: true,
        polylineOptions: {
          strokeWeight: 5,
          strokeOpacity: 0.8,
          strokeColor: iconColor
        },
        markerOptions: {}
      });

      // Use this new renderer with the result
      directionDisplayRenderEngineArray[i].setDirections(result);

      // adjust zooming
      if (i === 0) {
        bounds = directionDisplayRenderEngineArray[i].getDirections().routes[0].bounds;
      } else {
        bounds.union(directionDisplayRenderEngineArray[i].getDirections().routes[0].bounds);
      }

      map.fitBounds(bounds);
      if (map.zoom > defaultZoom) {
        map.setZoom(defaultZoom);
      }

      // and start the next request
      setTimeout(function() {
        nextRequest();
      }, 500);
    }
  }

  function nextRequest() {
    // increment counter
    i++;

    // next request if any
    if (i >= requestArray.length) {
      // No more to do
      return;
    }

    // submit next request
    submitRequest();
  }

  // begin processing
  submitRequest();
};
SIXTH - Done. Make. profit. Here is a working JSFiddle for it.

No comments: