-2

I'd like to return all the countries from a google.maps.DirectionsResult object after routing from A to B. The response does not include information about this directly, but in the instructions it sometimes says Entering Germany as an example. Now my function goes over the steps array and accumulates the kms until it reaches an 'Entering...' instruction, then saves the entry and goes on with the new country.

This works for some countries in Europe but not all of them. For example: Istanbul to Zagreb does not contain any information about crossing the border which means this way won't work.

Has anybody run into this before? Or do you know a solution for this?

Flov
  • 1,527
  • 16
  • 25
  • 2
    This has been asked many times already but I don't think there was ever a viable answer. Only tricks and workarounds. – MrUpsidown Dec 01 '22 at 14:09
  • You *could* probably get satisfying results using the DistanceMatrix service **at a cost** by sending every steps coordinates to the service as the coords will be geocoded and the response will include the countries names. But you would need to 1) break the request into multiple chunks that will fit the service limitations (ie. do multiple requests) and 2) extract all countries from the response and reduce this to a list of unique countries names. Not very efficient but feasible. – MrUpsidown Dec 01 '22 at 15:15
  • Another option would be to open a feature request in Google's Directions API [issue tracker](https://issuetracker.google.com/issues?q=status:open%20componentid:188841) but you shouldn't expect anything to happen in the near future. – MrUpsidown Dec 01 '22 at 15:17
  • Related question (similar functionality for US states): [Google maps api v3 calculate mileage by state](https://stackoverflow.com/questions/34028829/google-maps-api-v3-calculate-mileage-by-state) (as I recall, it is kind of a hack, and processing extensive) – geocodezip Dec 01 '22 at 15:45

1 Answers1

-1

Here is a very basic / non-optimized implementation of what I mentioned in my comment (using DistanceMatrix Service).

A cleaner implementation would be to use promises with the DistanceMatrix Service since you need to split all steps locations into chunks of max 25 locations then reduce the list to unique countries. What I did is really just a proof of concept.

Also (as you can see from the output of the below script) it looks like sometimes, the string after the last comma in the DistanceMatrix reponse isn't the country name but something else (for example the 6530 in the below output), or it can contain a postal code and the country name (that's what I found out running just a few tests, you might find more exceptions).

Other than that, the output seems correct. Again, beware of the costs of such an implementation (DistanceMatrix + Directions API + basic map usage).

var directionDisplay;
var directionsService;
var map;
var countries = [];

function initialize() {
  directionsService = new google.maps.DirectionsService();
  directionsDisplay = new google.maps.DirectionsRenderer();
  var center = new google.maps.LatLng(0, 0);
  var myOptions = {
    zoom: 7,
    mapTypeId: google.maps.MapTypeId.ROADMAP,
    center: center
  }

  map = new google.maps.Map(document.getElementById("map-canvas"), myOptions);
  directionsDisplay.setMap(map);

  var start = "Istanbul";
  var end = "Zagreb";
  var method = 'DRIVING';
  var request = {
    origin: start,
    destination: end,
    travelMode: google.maps.DirectionsTravelMode[method]
  };

  directionsService.route(request, function(response, status) {
    if (status == google.maps.DirectionsStatus.OK) {
      directionsDisplay.setDirections(response);

      let steps = response.routes[0].legs[0].steps;
      let origins = [];
      let destinations = [];

      steps.forEach((element) => {
        origins.push(element.start_location);
        destinations.push(element.end_location);
      });

      let originsChunks = chunkArrayInGroups(origins, 25);
      let responses = [];

      originsChunks.forEach((element) => {
        responses.push(getDistanceMatrix(element, [end]))
      });
    }
  });
}

function getDistanceMatrix(origins, destinations) {

  const dmService = new google.maps.DistanceMatrixService();

  const request = {
    origins: origins,
    destinations: destinations,
    travelMode: google.maps.TravelMode.DRIVING,
    unitSystem: google.maps.UnitSystem.METRIC,
    avoidHighways: false,
    avoidTolls: false,
  };

  // Get distance matrix response
  dmService.getDistanceMatrix(request).then((dmResponse) => {

    dmResponse.originAddresses.forEach((element) => {

      countries.push(element.split(', ').pop());
    });

    let uniqueCountries = [...new Set(countries)];
    document.getElementById('countries').innerHTML = '<h2>This route crosses ' + uniqueCountries.join(', ') + '</h2>';
  });
}

function chunkArrayInGroups(arr, size) {
  var myArray = [];
  for (var i = 0; i < arr.length; i += size) {
    myArray.push(arr.slice(i, i + size));
  }
  return myArray;
}
#map-canvas {
  height: 125px;
}
<div id="map-canvas"></div>
<div id="countries">

</div>

<script async src="//maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&language=en&callback=initialize"></script>
MrUpsidown
  • 21,592
  • 15
  • 77
  • 131