谷歌地图API v3 - 多个地址解析请求后fitBounds

4
我想做的是使用AJAX和JSON加载一堆地址,找到每个地址的纬度和经度,在地图上放置标记,然后使用fitBounds()缩放以便所有标记都可见。听起来很简单。
我已经完成了大部分工作,但我的问题在于fitBounds()部分。
基本上,当循环遍历每个地址并查找纬度和经度时,似乎会在循环下面加载fitBounds()函数。
所以它正在调用fitBounds(),但还没有任何内容在marker_bounds数组中。我本以为它会在到达fitBounds()函数之前完成循环,但我想geocoder.geocode()函数可能会导致它继续加载其余的JavaScript,同时确定纬度和经度。
以下是我的代码:
var geocoder;
var map;
var marker_bounds = [];

var myOptions = {
    zoom: 12,
    mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);    

$.post('addresses.php', function(data) {

    var next_filter = '';           
    for(var x=0;x<data.addresses.length;x++) {

        geocoder.geocode( { 'address': data.addresses[x].address}, function(results, status) {

            if (status == google.maps.GeocoderStatus.OK) {

                marker = new google.maps.Marker({
                    map: map,
                    position: results[0].geometry.location
                });

                var latLng = new google.maps.LatLng(results[0].geometry.location.lat(), results[0].geometry.location.lng());
                marker_bounds.push(latLng);             
            }

        });             
    }

    var latlngbounds = new google.maps.LatLngBounds();
    for ( var i = 0; i < marker_bounds.length; i++ ) {
       latlngbounds.extend(marker_bounds[i]);
    }
    map.setCenter(latlngbounds.getCenter());
    map.fitBounds(latlngbounds); 

}, 'json'); 

在所有地理编码完成后,是否有可调用的函数?


我已经做了更多的调查,似乎geocode方法是一个异步调用,这就解释了为什么我的函数在geocoder完成之前就已经结束并返回了。有没有办法确定所有的geocode方法何时完成? - Ben Sinclair
3个回答

7

好的,我学到了以下内容。

  1. geocode方法是异步调用的,因此在该过程中进行地址查找时,包含geocode方法的页面将在geocoder完成查找之前完成。
  2. 需要在运行geocode方法后调用一个函数(addressBounds),并计算它已经地理编码了多少个地址(address_count)。
  3. 每次调用addressBounds函数时,都要检查是否已查找所有地址(if(total_addresses==address_count)),然后运行fitBounds()函数。

我的最终代码

var geocoder;
var map;
var markerBounds = [];  

var myOptions = {
    zoom: 4,
    mapTypeId: google.maps.MapTypeId.ROADMAP
}   
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);    

google.maps.event.addListenerOnce(map, 'idle', function(){

    $.post('addresses.php', function(data) {

        var total_addresses = data.addresses.length;            
        var address_count = 0;
        for(var x=0;x<total_addresses;x++) {    

            geocoder.geocode( { 'address': data.addresses[x].address }, function(results, status) {

                address_count++;        

                if (status == google.maps.GeocoderStatus.OK) {

                    marker = new google.maps.Marker({
                        map: map,
                        position: results[0].geometry.location
                    });

                    var infowindow = new google.maps.InfoWindow();
                    infowindow.setContent(address);
                    google.maps.event.addListener(marker, 'click', function() {
                        infowindow.open(map, marker);
                    });

                    var myLatLng = new google.maps.LatLng(results[0].geometry.location.lat(), results[0].geometry.location.lng());                      
                    addressesBounds(total_addresses, address_count, myLatLng);  

                }

            });

        }

    }, 'json');

});

function addressesBounds(total_addresses, address_count, myLatLng) {

    markerBounds.push(myLatLng);

    // make sure you only run this function when all addresses have been geocoded
    if (total_addresses == address_count) {
        var latlngbounds = new google.maps.LatLngBounds();
        for ( var i = 0; i < markerBounds.length; i++ ) {
           latlngbounds.extend(markerBounds[i]);
        }
        map.setCenter(latlngbounds.getCenter());
        map.fitBounds(latlngbounds);
    }
}

有没有可能同步完成所有事情? - Rodrigo Moreno
@RodrigoMoreno 我自上次构建代码以来就没有重新构建它,所以我不能回答这个问题。我相信他们在那时和现在之间可能已经进行了改进。 - Ben Sinclair

2
简单来说,您可以在全局范围内与其他变量一起定义您的边界对象,然后通过每个发现结果(在地理编码回调中)构造它。
基本上,您想要使用回调数据进行的所有操作都需要在回调或由回调触发的函数中完成(正如您所发现的)。但在这种情况下,您不需要一个单独的函数。浏览器应该储存所有的 'fitBounds' 操作并仅执行最后一个。
var latLng = new google.Maps.LatLng(
                          results[0].geometry.location.lat(),
                          results[0].geometry.location.lng());
marker_bounds.push(latLng);
latlngbounds.extend(latLng);
map.fitBounds(latlngbounds);

如果必要的话(因为您的浏览器足够快以处理每个地址的fitBounds),您可以在另一个变量中跟踪实际返回的结果数量,比如address_count,并在执行fitBounds之前测试是否已经获取了所有结果。也就是说,您的辅助函数可以被合并到地理编码器回调函数中。
var latLng = new google.Maps.LatLng(
                          results[0].geometry.location.lat(),
                          results[0].geometry.location.lng());
marker_bounds.push(latLng);
latlngbounds.extend(latLng);
address_count++;
if (address_count == data.addresses.length) map.fitBounds(latlngbounds);

0

我知道以下内容与严格相关,但我已经苦苦挣扎了很长时间,我认为值得分享。 在使用DirectionsRenderer渲染多个方向请求后,地图通常会聚焦于最后一个渲染命令的结果,尽管我在发出最后一个带有包含所有方向请求结果的边界框的渲染命令之后发出了map.fitBounds。这种行为是不确定的,有时视口会聚焦于整个地图,有时会聚焦于最后一个方向请求结果。解决方法是为渲染器设置preserveViewport:true,这样在显示方向请求结果后,它就不会改变地图的焦点,因此现在我可以通过fitbounds来改变焦点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接