2010-07-01 9 views
44

NOTA: estoy usando v3 de la API de Google MapsAPI de Google Maps v3 adición de una ventana de información para cada marcador

Estoy intentando agregar una ventana de información para cada marcador puse en el mapa. Actualmente estoy haciendo esto con el siguiente código:

for (var i in tracks[racer_id].data.points) { 
    values = tracks[racer_id].data.points[i];     
    point = new google.maps.LatLng(values.lat, values.lng); 
    if (values.qst) { 
     var marker = new google.maps.Marker({map: map, position: point, clickable: true}); 
     tracks[racer_id].markers[i] = marker; 
     var info = new google.maps.InfoWindow({ 
      content: '<b>Speed:</b> ' + values.inst + ' knots' 
     }); 
     tracks[racer_id].info[i] = info; 
     google.maps.event.addListener(marker, 'click', function() { 
      info.open(map, marker); 
     }); 
    } 
    track_coordinates.push(point); 
    bd.extend(point); 
} 

El problema es cuando hago clic en un marcador que sólo muestra la ventana de información para el último marcador añadió. También para que quede claro, la ventana de información aparece junto al último marcador en el que el marcador no hizo clic. Me imagino que mi problema está en la porción addListener pero no soy postitivo. ¿Algunas ideas?

Respuesta

78

Usted está teniendo a very common closure problem en el for in bucle:

variables encerradas en una cuota de cierre del mismo entorno único, de manera que cuando el click devolución de llamada desde la addListener se llama, el bucle se han seguido su curso y la La variable info se dejará apuntando al último objeto, que resulta ser el último InfoWindow creado.

En este caso, una manera fácil de resolver este problema sería la de aumentar su objeto Marker con el InfoWindow:

var marker = new google.maps.Marker({map: map, position: point, clickable: true}); 

marker.info = new google.maps.InfoWindow({ 
    content: '<b>Speed:</b> ' + values.inst + ' knots' 
}); 

google.maps.event.addListener(marker, 'click', function() { 
    marker.info.open(map, marker); 
}); 

Esto puede ser un tema bastante complicado, si usted no está familiarizado con la forma en cierres de trabajo . Usted puede comprobar hacia fuera el siguiente artículo de Mozilla para una breve introducción:

También hay que tener en cuenta, que la versión 3 del API permite que múltiples InfoWindow s en el mapa. Si tiene la intención de tener solo un InfoWindow visible en ese momento, debería usar un solo objeto InfoWindow, y luego abrirlo y cambiar su contenido cada vez que se hace clic en el marcador (Source).

+1

¿Puede explicarme más sobre dónde debo conectar este fragmento de código? ¿Se hace en lugar de for loop o antes de for-loop? Estoy un poco confundido. – uday

+1

Debe insertar el fragmento de código _inside_ el ciclo for;) – Tilt

0

Prueba esto:

for (var i in tracks[racer_id].data.points) { 
    values = tracks[racer_id].data.points[i];     
    point = new google.maps.LatLng(values.lat, values.lng); 
    if (values.qst) { 
     var marker = new google.maps.Marker({map: map, position: point, clickable: true}); 
     tracks[racer_id].markers[i] = marker; 
     var info = new google.maps.InfoWindow({ 
      content: '<b>Speed:</b> ' + values.inst + ' knots' 
     }); 
     tracks[racer_id].info[i] = info; 
     google.maps.event.addListener(tracks[racer_id].markers[i], 'click', function() { 
      tracks[racer_id].info[i].open(map, tracks[racer_id].markers[i]); 
     }); 
    } 
    track_coordinates.push(point); 
    bd.extend(point); 
} 
+0

Jaja yo ya había intentado eso. Lo intenté de nuevo y, lamentablemente, todavía no funciona. – blcArmadillo

+0

El problema aquí es la variable 'i', que aún está encerrada en un cierre. Cuando se llama a la devolución de llamada 'click', la variable' i' quedará apuntando al último elemento del bucle, y por lo tanto 'info [i] .open' todavía abrirá la última' InfoWindow'. –

0

que tenía un problema muy similar pero en ActionScript 3: Stack Over Flow: Dynamic Google Maps API Info Window HTML Content Issue

yo estaba tratando de tirar de información única en el htmlContent de la información sobre herramientas de una base de datos y se encontró que Estaba obteniendo la información del último marcador que agregué en cada marcador.

Suponiendo que no es un problema específico de actionscript, la solución de JochenJung no funcionará. Mira la solución que publiqué en mi problema y mira si puedes aplicarla aquí. Esto parece ser un problema serio con Map API.

1

Hola a todos. No sé si esta es la solución óptima, pero pensé que la publicaría aquí para ayudar a la gente en el futuro. Comente si ve algo que deba cambiarse.

Mi bucles es ahora:

for (var i in tracks[racer_id].data.points) { 
    values = tracks[racer_id].data.points[i];     
    point = new google.maps.LatLng(values.lat, values.lng); 
    if (values.qst) { 
     tracks[racer_id].markers[i] = add_marker(racer_id, point, '<b>Speed:</b> ' + values.inst + ' knots<br /><b>Invalid:</b> <input type="button" value="Yes" /> <input type="button" value="No" />'); 
    } 
    track_coordinates.push(point); 
    bd.extend(point); 
} 

Y add_marker se define como:

var info_window = new google.maps.InfoWindow({content: ''}); 

function add_marker(racer_id, point, note) { 
    var marker = new google.maps.Marker({map: map, position: point, clickable: true}); 
    marker.note = note; 
    google.maps.event.addListener(marker, 'click', function() { 
     info_window.content = marker.note; 
     info_window.open(map, marker); 
    }); 
    return marker; 
} 

Puede utilizar info_window.close() para apagar el info_window en cualquier momento. Espero que esto ayude a alguien.

9

add_marker aún tiene un problema de cierre, porque utiliza la variable de marcador fuera del ámbito google.maps.event.addListener.

Una mejor aplicación sería:

function add_marker(racer_id, point, note) { 
    var marker = new google.maps.Marker({map: map, position: point, clickable: true}); 
    marker.note = note; 
    google.maps.event.addListener(marker, 'click', function() { 
     info_window.content = this.note; 
     info_window.open(this.getMap(), this); 
    }); 
    return marker; 
} 

También utilicé el mapa desde el marcador, de esta manera usted no tiene que pasar el objeto de mapa Google, es probable que desee utilizar el mapa donde el marcador pertenece a todos modos.

+0

¡Guau! ¡Estuve atascado en esto por más de dos horas! ¡no sabía que el marcador fuera del alcance se usaría! ¡Gracias una tonelada! –

1

para API Earth plugin, crea el globo fuera de tu bucle y pasa tu contador a la función para obtener contenidos exclusivos para cada marca de posición.

function createBalloon(placemark, i, event) { 
      var p = placemark; 
      var j = i; 
      google.earth.addEventListener(p, 'click', function (event) { 
        // prevent the default balloon from popping up 
        event.preventDefault(); 
        var balloon = ge.createHtmlStringBalloon(''); 
        balloon.setFeature(event.getTarget()); 

        balloon.setContentString('iframePath#' + j); 

        ge.setBalloon(balloon); 
      }); 
     } 
33

Puede utilizar this en el evento:

google.maps.event.addListener(marker, 'click', function() { 
    // this = marker 
    var marker_map = this.getMap(); 
    this.info.open(marker_map); 
    // this.info.open(marker_map, this); 
    // Note: If you call open() without passing a marker, the InfoWindow will use the position specified upon construction through the InfoWindowOptions object literal. 
}); 
+10

Esta debería ser la respuesta correcta. La respuesta de @DanielVassallo sufre del mismo problema que relató. –

+0

Esto funcionó para mí también ... 'esto' fue la clave. –

+3

Funciona muy bien pero tuve que hacer 'this.info.open (marker_map, this); ' – askilondz

0

La única manera de que finalmente pude conseguir que esto era el trabajo mediante la creación de una matriz en JavaScript. Los elementos de la matriz hacen referencia a las diversas ventanas de información (se crea una ventana de información para cada marcador en el mapa). Cada elemento de matriz contiene el texto único para su marcador de mapa apropiado. Definí el evento de JavaScript para cada ventana de información en función del elemento de la matriz. Y cuando se activa el evento, utilizo la palabra clave "this" para hacer referencia al elemento de la matriz para hacer referencia al valor apropiado para mostrar.

var map = new google.maps.Map(document.getElementById('map-div'), mapOptions); 
zipcircle = []; 
for (var zip in zipmap) { 
    var circleoptions = { 
     strokeOpacity: 0.8, 
     strokeWeight: 1, 
     fillOpacity: 0.35, 
     map: map, 
     center: zipmap[zip].center, 
     radius: 100 
    }; 
    zipcircle[zipmap[zip].zipkey] = new google.maps.Circle(circleoptions); 
    zipcircle[zipmap[zip].zipkey].infowindowtext = zipmap[zip].popuptext; 
    zipcircle[zipmap[zip].zipkey].infowindow = new google.maps.InfoWindow(); 
    google.maps.event.addListener(zipcircle[zipmap[zip].zipkey], 'click', function() { 
     this.infowindow.setContent(this.infowindowtext); 
     this.infowindow.open(map, this); 
    }); 
} 
4

Uso de eventos cierres ...

Ésta es la manera de hacerlo en v3: https://developers.google.com/maps/documentation/javascript/examples/event-closure

+1

Es mejor incluir un ejemplo de reenvío a un enlace. Si este enlace desaparece, su ejemplo seguirá siendo útil y responderá a una pregunta muy antigua (4 años). –

+1

El método que se muestra en ese ejemplo funcionó para mí. Cree "información" en su ciclo, pero luego cree una función separada que tome el "marcador" y la "información" para crear InfoWindow y el receptor del evento. @ La respuesta de ostapische creó las ventanas de eventos apropiadas, pero todas estaban en lugares que no estaban asociados con un marcador en particular. –

+0

Este es un buen recurso. ES2015 permite que el alcance del bloque probablemente se ocupe de esto ahora. – sheriffderek

0

yo tuvimos un problema similar. Si todo lo que desea es que se muestre alguna información al pasar el mouse sobre un marcador, en lugar de hacer clic en él, descubrí que una buena alternativa para usar una ventana de información era establecer un título en el marcador. De esta manera cada vez que pase el mouse sobre el marcador, el título se muestra como una etiqueta ALT. 'marker.setTitle (' Marker '+ id);' Se elimina la necesidad de crear un detector para el marcador demasiado

1

en mi caso (uso de JavaScript insidde Razor) Esto funcionó a la perfección dentro de un bucle foreach

google.maps.event.addListener(marker, 'click', function() { 
    marker.info.open(map, this); 
}); 
Cuestiones relacionadas