2009-11-19 3 views
2

J'essaie de tracer des lignes entre deux adresses ou plus dans Google Maps. L'idée est que les adresses sont dans un tableau (dans l'ordre de la route empruntée), alors le tableau est en boucle sur et géocodées via Google Maps, donc j'ai alors un tableau de coordonnées:Google Maps: adresses de géocodage asynchrones, mais obtiennent leurs réponses dans l'ordre

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); 
     }); 
    } 
} 

Le La fonction drawRoute() ne sera exécutée que si le tableau qui lui est transmis est identique à la longueur du tableau d'itinéraires d'origine.

La plupart du temps cela fonctionne très bien. Cependant, il se cassera s'il y a un retard dans l'obtention d'une réponse du géocodeur pour n'importe quelle valeur, car il en résultera qu'ils sont hors service.

Ma première tentative autour de ce problème est la suivante:

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); 
     }); 
    } 
} 

Mais la fonction fonctionne de manière asynchrone, cela signifie que la valeur de i dans le rappel de géocodage va toujours être la longueur du tableau de routes , donc ça va juste continuer à écraser la même valeur.

Vous avez des idées?

Répondre

4

Ok. Donc je devais faire un search sur SO et relire comment les fermetures fonctionnent avant que j'ai répondu à cette question (semble que je dois toujours faire cela quand je pense à des fermetures).

La valeur de la variable d'index est définie lorsque la fonction externe est renvoyée (c'est-à-dire showRoute dans ce cas). Alors je me suis, tout ce que vous devez faire est de conclure votre getLatLng dans une autre fonction qui prend l'index en tant que paramètre:

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

Ainsi, votre boucle showRoute devient:

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

De cette façon, le rappel getLatLng a accès à la valeur d'index appropriée. J'ai fait un quick example qui démontre que cela fonctionne. Vous pouvez trouver la source pour ce here.

+0

Merci! C'est exactement ce que j'essayais de faire. –

+0

Bonnes choses :). Merci pour la bonne question. Cela m'a incité à examiner cela correctement. – RedBlueThing

2

Vous souhaitez effectuer chaque géocodage un à la fois et faire appel au rappel du géocodage suivant. Cela garantira la commande.

.: par exemple

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])); 
    } 
} 
+0

C'était aussi ma première réaction (en fait, j'ai utilisé cette approche dans le passé), mais je pense que vous pouvez éviter de faire les demandes de manière séquentielle. – RedBlueThing

+0

Merci pour l'idée; J'essayais d'éviter d'aller séquentiellement, car c'est plus lent. –

Questions connexes