2010-07-01 3 views
44

NOTA: sto usando v3 della API di Google MapsAPI di Google Maps v3 l'aggiunta di un InfoWindow per ogni marcatore

Sto cercando di aggiungere una finestra di informazioni per ogni marcatore ho messo sulla mappa. Attualmente sto facendo questo con il seguente codice:

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

Il problema è quando clicco su un marcatore solo visualizza la finestra di informazioni per l'ultimo marcatore aggiunto. Inoltre, per essere chiari, appare la finestra delle informazioni accanto all'ultimo indicatore e non il marcatore cliccato. Immagino che il mio problema è nella parte addListener ma non sono post-itativo. Qualche idea?

risposta

78

Si stanno avendo a very common closure problem nel for in ciclo:

variabili racchiuse in una quota di chiusura lo stesso ambiente unico, quindi per il momento il click richiamata dalla addListener si chiama, il ciclo ha compiuto il suo corso e la La variabile info verrà lasciata puntata sull'ultimo oggetto, che risulta essere l'ultimo InfoWindow creato.

In questo caso, un semplice modo per risolvere questo problema sarebbe quello di aumentare il vostro oggetto Marker con la 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); 
}); 

Questo può essere un bel argomento difficile, se non si ha familiarità con il modo di lavoro chiusure . Si può verificare il seguente articolo di Mozilla per una breve introduzione:

Anche tenere a mente, che l'API v3 consente a più InfoWindow s sulla mappa. Se hai intenzione di avere solo uno InfoWindow visibile al momento, dovresti invece utilizzare un singolo oggetto InfoWindow, quindi aprirlo e modificarne il contenuto ogni volta che si fa clic sul marker (Source).

+1

Puoi spiegare di più su dove devo inserire questo snippet di codice? È fatto invece di loop o prima del ciclo sono un po 'confuso. – uday

+1

È necessario inserire lo snippet di codice _inside_ il ciclo for;) – Tilt

0

Prova questo:

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

Haha avevo già provato. Ho appena provato di nuovo e purtroppo non funziona ancora. – blcArmadillo

+0

Il problema qui è la variabile 'i', che è ancora racchiusa in una chiusura. Quando viene richiamato il richiamo del 'click', la variabile' i' verrà lasciata puntata sull'ultimo elemento del ciclo, e quindi 'info [i] .open' aprirà comunque l'ultimo 'InfoWindow'. –

0

Ho avuto un problema molto simile, ma in ActionScript 3: Stack Over Flow: Dynamic Google Maps API Info Window HTML Content Issue

stavo cercando di estrarre informazioni univoche nella htmlcontent dei tooltip da un database e ha scoperto che Stavo ottenendo l'informazione dell'ultimo marcatore che ho aggiunto in ogni marcatore.

Supponendo che non si tratti di un problema specifico di ActionScript, la soluzione di JochenJung non funzionerà. Guarda la soluzione che ho postato nel mio problema e vedi se puoi applicarla qui. Questo sembra essere un problema serio con l'API della mappa.

1

Ciao a tutti. Non so se questa sia la soluzione ottimale, ma ho pensato di postarla qui per aiutare eventualmente le persone in futuro. Per favore commenta se vedi qualcosa che dovrebbe essere cambiato.

mio per i loop è ora:

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

E add_marker è definito come:

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

È possibile utilizzare info_window.close() per spegnere l'info_window in qualsiasi momento. Spero che questo aiuti qualcuno.

9

add_marker presenta ancora un problema di chiusura, in quanto utilizza la variabile dell'indicatore all'esterno dell'ambito google.maps.event.addListener.

Una migliore attuazione sarebbe:

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

ho usato anche la mappa dal marcatore, in questo modo non è necessario passare la mappa di google oggetto, probabilmente desidera utilizzare la mappa in cui il marcatore appartiene a comunque.

+0

Wow! Sono rimasto bloccato su questo per più di due ore! non sapevo che sarebbe stato usato il marcatore al di fuori del campo di applicazione! Grazie mille! –

1

per le API di plug-in Earth, crea il fumetto all'esterno del loop e passa il contatore alla funzione per ottenere contenuti unici per ogni segnaposto!

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

È possibile utilizzare this nell'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

Questa dovrebbe essere la risposta corretta. La risposta di @DanielVassallo soffre dello stesso problema che ha messo in relazione. –

+0

Questo ha funzionato anche per me .. 'questa' era la chiave. –

+3

Funziona alla grande ma dovevo fare 'this.info.open (marker_map, this); ' – askilondz

0

L'unico modo ho potuto finalmente ottenere questo al lavoro è stato con la creazione di un array in JavaScript. Gli elementi dell'array fanno riferimento alle varie finestre informative (viene creata una finestra informativa per ciascun indicatore sulla mappa). Ogni elemento dell'array contiene il testo univoco per il relativo indicatore di mappa appropriato. Ho definito l'evento JavaScript per ogni finestra delle informazioni basata sull'elemento dell'array. E quando l'evento si attiva, uso la parola chiave "this" per fare riferimento all'elemento dell'array in modo che faccia riferimento al valore appropriato da visualizzare.

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
+1

È preferibile includere un esempio anziché inoltrare a un collegamento. Se questo collegamento scompare, il tuo esempio ti sarà comunque d'aiuto e rispondi a una domanda molto vecchia (4 anni). –

+1

Il metodo mostrato in questo esempio ha funzionato per me. Crea "informazioni" nel tuo loop, ma poi crea una funzione separata che prende il "marker" e le "informazioni" per creare InfoWindow e l'ascoltatore per l'evento. @ La risposta di ostapische ha creato le finestre degli eventi corrette, ma erano tutte in luoghi che non erano associati a un particolare indicatore. –

+0

Questa è una buona risorsa. ES2015 lascia che l'scope scope si occupi di questo ora. – sheriffderek

0

Ho avuto un problema simile. Se tutto ciò che vuoi è che alcune informazioni vengano visualizzate quando passi con il mouse su un marker, invece di cliccarlo, ho scoperto che una buona alternativa all'utilizzo di una finestra informativa era di impostare un titolo sull'indicatore. In questo modo ogni volta che si passa il mouse sopra l'indicatore, il titolo viene visualizzato come un tag ALT. 'marker.setTitle (' Marker '+ id);' Si elimina la necessità di creare un listener per il marcatore troppo

1

Nel mio caso (utilizzando JavaScript insidde Razor) Questo ha funzionato perfettamente all'interno di un ciclo foreach

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