Google Maps API v3将InfoWindow添加到每个标记

时间:2010-07-01 14:13:24

标签: javascript google-maps google-maps-api-3

注意:我正在使用Google Maps API的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部分,但不是postitive。有什么想法吗?

9 个答案:

答案 0 :(得分:79)

for in循环中有a very common closure problem

封闭在闭包中的变量共享相同的单一环境,因此当调用来自click的{​​{1}}回调时,循环将运行其路径和addListener变量将指向最后一个对象,这恰好是最后创建的info

在这种情况下,解决此问题的一种简单方法是使用InfoWindow扩充Marker对象:

InfoWindow

如果你不熟悉闭包的工作方式,这可能是一个非常棘手的话题。您可以查看以下Mozilla文章以获得简要介绍:

另请注意,v3 API允许在地图上显示多个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); }); 。如果您打算当时只有一个InfoWindow可见,则应该使用单个InfoWindow对象,然后在单击标记时打开它并更改其内容(Source

答案 1 :(得分:35)

您可以在事件中使用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.
});

答案 2 :(得分: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;
}

我还使用了标记中的地图,这样你就不需要传递谷歌地图对象,你可能想要使用标记所属的地图。

答案 3 :(得分: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。希望这有助于某人。

答案 4 :(得分: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);
            });
        }

答案 5 :(得分:1)

在我的情况下(使用Javascript insidde Razor)这在Foreach循环中完美地运行

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

答案 6 :(得分: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);
}

答案 7 :(得分: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);
    });
}

答案 8 :(得分:0)

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