2010-07-01 133 views
44

注:我使用谷歌地图API谷歌地图API V3添加信息窗口中每个标记

我想要的信息窗口添加到每个标记我把地图上的V3。目前,我用下面的代码这样做:

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

问题是,当我点击它只是显示在过去标记添加的信息窗口的标志。也只是要清除信息窗口出现在最后一个标记旁边,而不是点击标记。我会想象我的问题是在addListener部分,但不是联系。有任何想法吗?

回答

78

您在for in循环有a very common closure problem

变量从addListenerclick回调被调用时封闭在一个封闭共享同一个环境,所以,循环将已经走完了其历程和info变量将被指向最后一个对象,这恰好是最后创建的InfoWindow

在这种情况下,一个简单的方法来解决这个问题将是与InfoWindow增强您Marker对象:

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

这可以是一个相当棘手的话题,如果你不熟悉闭包是如何工作的。您可以检查出以下Mozilla的文章作一简要介绍:

还要记住的是,V3 API允许多个InfoWindow S中的地图上。如果您打算在当时只显示一个InfoWindow,则应改为使用一个InfoWindow对象,然后打开它并在单击标记时更改其内容(Source)。

+1

你能解释更多关于我需要插入这段代码的地方吗?完成它而不是for循环还是for循环之前我有点困惑。 – uday 2013-01-16 03:06:32

+1

您需要插入代码片段_inside_ for循环;) – Tilt 2013-11-06 18:52:17

0

试试这个:

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

哈哈,我已经试过了。只是再次尝试,不幸的是它仍然无法正常工作。 – blcArmadillo 2010-07-01 14:28:55

+0

这里的问题是'i'变量,它仍然封闭在闭包中。当'click'回调被调用时,'i'变量将被指向循环的最后一项,因此'info [i] .open'仍然会打开最后一个'InfoWindow'。 – 2010-07-01 15:25:24

0

我有一个非常类似的问题,但在ActionScript 3: Stack Over Flow: Dynamic Google Maps API Info Window HTML Content Issue

我想拉独特的信息到提示的htmlcontent从数据库后发现,我得到了每个标记中添加的最后一个标记的信息。

假设它不是一个动作特定的问题,那么JochenJung的解决方案将无法工作。看看我在问题中发布的解决方案,看看你是否可以在这里应用它。这似乎是Map API的一个严重问题。

1

嘿大家。我不知道这是否是最佳解决方案,但我想我会在这里发布它,希望在未来帮助人们。如果您发现任何应该更改的内容,请发表评论。

我的for循环,现在是:

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

而且add_marker被定义为:

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

您可以使用info_window.close()随时关闭info_window。希望这可以帮助某人。

9

add_marker仍然存在关闭问题,因为它使用google.maps.event.addListener作用域之外的标记变量。

一个更好的实现是:

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

我还用从标记的地图,这样你就不需要通过谷歌地图对象,你可能想在标志使用地图无论如何。

+0

哇!我坚持了两个多小时!不知道范围之外的标记将被使用!万分感谢! – 2016-11-07 02:57:24

1

对于地球插件API,在您的循环外创建气球并将您的计数器传递给函数以获取每个地标的唯一内容!

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

您可以在事件中使用this

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

这应该是正确的答案。 @DanielVassallo答案患有与他有关的同样的问题。 – 2014-09-17 13:44:52

+0

这也适用于我..'这'是关键。 – 2015-06-08 17:46:37

+3

很好用,但我必须做'this.info.open(marker_map,this); ' – askilondz 2015-09-10 00:55:56

0

我终于得到这个工作的唯一方法是通过创建在JavaScript中的数组。数组元素引用各种信息窗口(为地图上的每个标记创建一个信息窗口)。每个数组元素都包含适当地图标记的唯一文本。我根据数组元素为每个信息窗口定义了JavaScript事件。当事件触发时,我使用“this”关键字引用数组元素来引用适当的值来显示。

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

使用事件倒闭......

这是如何做到这一点的V3:https://developers.google.com/maps/documentation/javascript/examples/event-closure

+1

最好包含一个示例,而不是转发到链接。如果这个链接消失了,你的例子仍然会有帮助,并且你正在回答一个非常古老的问题(4岁)。 – 2014-10-28 07:02:40

+1

该示例中显示的方法适用于我。 在循环中创建“info”,但创建一个单独的函数,它使用“marker”和“info”创建InfoWindow和事件的侦听器。 @ ostapische的答案确实创建了适当的事件窗口,但它们都在与特定标记无关的地方。 – 2015-10-27 16:53:03

+0

这是一个很好的资源。 ES2015现在让块定界可能会照顾到这一点。 – sheriffderek 2017-02-27 21:41:52

0

我也有类似的问题。 如果您只需要将鼠标悬停在标记上时显示某些信息,而不是点击它,那么我发现使用信息窗口的另一种方法是在标记上设置标题。这样,只要将鼠标悬停在标记上,标题就会显示为一个ALT标记。 'marker.setTitle('Marker'+ id);' 它消除了需要创建一个侦听器标记过

1

在我的情况(使用JavaScript insidde剃刀)这工作完全在Foreach循环内

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