javascript - Google Maps: geocode addresses asynchronously, but get their responses in order - Stack Overflow

admin2025-04-26  0

I'm trying to plot lines between two or more addresses in Google Maps. The idea is that addresses are in an array (in the order of the route taken), then the array is looped over and geocoded via Google Maps, so I then have an array of co-ordinates:

function showRoute(routes) {
    var points = [];
    var geocoder = new GClientGeocoder();
    for (var i = 0; i < routes.length; i++) {
        geocoder.getLatLng(routes[i], function(point) {
            points.push(point);
            drawRoute(points, routes);
        });
    }
}

The drawRoute() function will only run through if the array passed to it is the same as the length of the original routes array.

Most of the time this works fine. However, it will break if there's a lag in getting a response from the geocoder for any value, as it'll result in them being out of order.

My first attempt around this problem was as follows:

function showRoute(routes) {
    var points = [];
    var geocoder = new GClientGeocoder();
    for (var i = 0; i < routes.length; i++) {
        geocoder.getLatLng(routes[i], function(point) {
            points[i] = point;
            drawRoute(points, routes);
        });
    }
}

But as the function runs asynchronously, it means that the value of i inside the geocode callback is always going to be the length of the routes array, so it'll just keep overwriting the same value.

Anyone got any ideas?

I'm trying to plot lines between two or more addresses in Google Maps. The idea is that addresses are in an array (in the order of the route taken), then the array is looped over and geocoded via Google Maps, so I then have an array of co-ordinates:

function showRoute(routes) {
    var points = [];
    var geocoder = new GClientGeocoder();
    for (var i = 0; i < routes.length; i++) {
        geocoder.getLatLng(routes[i], function(point) {
            points.push(point);
            drawRoute(points, routes);
        });
    }
}

The drawRoute() function will only run through if the array passed to it is the same as the length of the original routes array.

Most of the time this works fine. However, it will break if there's a lag in getting a response from the geocoder for any value, as it'll result in them being out of order.

My first attempt around this problem was as follows:

function showRoute(routes) {
    var points = [];
    var geocoder = new GClientGeocoder();
    for (var i = 0; i < routes.length; i++) {
        geocoder.getLatLng(routes[i], function(point) {
            points[i] = point;
            drawRoute(points, routes);
        });
    }
}

But as the function runs asynchronously, it means that the value of i inside the geocode callback is always going to be the length of the routes array, so it'll just keep overwriting the same value.

Anyone got any ideas?

Share Improve this question asked Nov 19, 2009 at 23:48 David MDavid M 352 silver badges6 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 4

Ok. So I had to do a search on SO and re-read how closures work before I answered this question (seems like I always have to do that when ever I think about closures).

The value of the index variable is set when the outer function returns (that is showRoute in this case). So I figured, all you need to do is wrap up your getLatLng in another function that takes the index as a parameter:

function processPoint (geocoder, routes, i, points)
{
    geocoder.getLatLng(routes[i], function(point) {
        points[i] = point;
        drawRoute (points, routes);
        });
}

So your loop in showRoute bees:

var geocoder = new GClientGeocoder();
for (var i = 0; i < wp.length; i++) 
     processPoint (geocoder, routes, i, points);

This way the getLatLng callback has access to the appropriate index value. I did a quick example which demonstrates this working. You can find the source for this here.

You want to do each geocode one at a time, and have the callback invoke the next geocode. This will guarantee the ordering.

E.g.:

var map = null;
var geocoder = null;
var next = 0;
var points = [];

var addresses = [
  "1521 1st Ave, Seattle, WA",
  "2222 2nd Ave, Seattle, WA",
  "14 Mercer St, Seattle, WA"
];

function initialize() {
  if (GBrowserIsCompatible()) {
    map = new GMap2(document.getElementById("map_canvas"));
    map.setCenter(new GLatLng(47.61630, -122.34546), 13);
    map.setUIToDefault();
    geocoder = new GClientGeocoder();
    geocodeAll();
  }
}

function geocodeAll() {
  if (next < addresses.length) {
    // Do the next one.
    geocoder.getLatLng(addresses[next], callBack);
  } else {
    doneCb();  // All done.
  }
  next += 1;
}

function callBack(point) {
  points.push(point);
  geocodeAll();
}

// Called when all done.
function doneCb() {
  // Add a polyline connecting the dots.
  var poly = new GPolyline(points);
  map.addOverlay(poly);

  // Add some markers over the points.
  for (var i = 0; i < points.length; ++i) {
    map.addOverlay(new GMarker(points[i]));
  }
}
转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1745643128a311719.html

最新回复(0)