3

I have a Google Map with around 200 markers on it. Using the Google Distance Matrix Service I can find the driving distance from an address to all the markers on the map. Due to the API limits I can only submit 25 destinations per call so I have to break up the operation into 8 separate calls to the Distance Matrix Service.

My problem is that since the calls are asynchronous they can arrive back in any order and therefore I'm a little stumped on how to best match the returned results with the original array of markers. Ideally I would like to pass along an offset to the call back function so it knows exactly which 25 elements in the original marker array correspond to the 25 results sent back from the API call but I don't know how to accomplish this so any help is greatly appreciated.

var limit = 25;
var numMarkers = markers.length; // markers is an array of markers defined elsewhere
var numCallbacks = Math.ceil(numMarkers/limit);
var callbackCount = 0;

for(var i = 0; i < numMarkers; i += limit) {
    var destinations = [];

    // Get destination position in batches of 25 (API limit)
    for(var j = i; j < i + limit && j < numMarkers; j++) {
        destinations[j - i] = markers[j].getPosition();
    }

    // Calculate distances
    distMatrix.getDistanceMatrix(
    {
        origins: origin, // array containing single lat/lng
        destinations: destinations,
        travelMode: google.maps.TravelMode.DRIVING,
        unitSystem: google.maps.UnitSystem.IMPERIAL,
        avoidHighways: false,
        avoidTolls: false

    }, function(response, status) {

        if (status == google.maps.DistanceMatrixStatus.OK) {
            var distances = response.rows[0].elements;

            // This is where it would be nice to know the offset in the markers array 
            // that these 25 results correspond to so I can then just iterate through 
            // the distances array and add the data to the correct marker.
        }

        if(++callbackCount == numCallbacks) {
            // All callbacks complete do something else...
        }
    });
}

So if there was a way to seed the callback function of each of the API calls with the value of "i" from the for loop at the time it was called then it would be easy to match everything up but I'm not that great with javascript so I don't know how to do this or if its even possible.

Thanks for any help you guys can provide!

Beesknees
  • 769
  • 1
  • 6
  • 8

1 Answers1

3

I assume you've tried to use i and j inside your callback, but always found that they equal the last value; this is because JavaScript has only function scope (not block), so i and j are only declared once; therefore each iteration references the same variable.

For more information on this, see Doesn't JavaScript support closures with local variables?.


The solution is the same as in the example (and with all occurrences of this problem); you need to introduce a new scope level. You can do this quite nicely for your problem as such;

function buildResponseFor(i) {
    return function (response, status) {
        if (status == google.maps.DistanceMatrixStatus.OK) {
            var distances = response.rows[0].elements;

            // Use i here.
        }
    }
}

Then update your getDistanceMatrix call to:

distMatrix.getDistanceMatrix({
    origins: origin, // array containing single lat/lng
    destinations: destinations,
    travelMode: google.maps.TravelMode.DRIVING,
    unitSystem: google.maps.UnitSystem.IMPERIAL,
    avoidHighways: false,
    avoidTolls: false

}, buildResponseFor(i));

... note you can pass i, or j, or i and j etc. to your buildResponseFor function, and they'll be available in your callback function as the names you give them inside the function declaration for buildResponseFor.

Community
  • 1
  • 1
Matt
  • 74,352
  • 26
  • 153
  • 180
  • Awesome! Thanks so much Matt. I did indeed try using i and j but was seeing the final value in the loop like you said. I'm fairly new to javascript so thanks for that little nugget of knowledge I'm sure it will come in handy again. – Beesknees Mar 17 '13 at 17:16