Google Map V3--geocode与fitBounds方法的同步操作
google.maps.Geocoder类的geocode方法与google.maps.Map类的fitBounds都是异步方法, 在页面上添加google map的引用就可以使用这些类, 现在的一个问题是我想页面上所有map相关的数据加载完再进步下一步操作该如何实现?
场景
- 页面中有一个Select标签, 存放全国各城市的信息,
- 一个640px高度和宽度的正方型div, 用来加载地图.
- 一个输出按钮
在select标签中选择一个城市后, 用异步方式与服务器会话并取回这个城市所有的苹果专卖店的地址, div中显示被选中的城市并用Marker标出所有的苹果专卖店, 点击输入按钮将适合的zoom level和地图中心点坐标传回服务端生成报表再输出到客户端
理想操作
- 选择一个城市
- div中显示对应的城市并标出所有苹果专卖店
- 点击输出按输出一张报表并内嵌一个地图
上面按1, 2, 3的顺序是一个理想化操作, 但实际情况是对地址进行geocode的过程是异步的, 调用的fitBounds方法也是异步的。也就是说当你点击输出按钮时, 地图并没有完全设置好,这些苹果专卖店的Marker可能在地图上还没有表示出来, 而且一个城市的苹果专卖店都比较分散, 可能不会在地图中显示所有的Marker。想解决这个问题就要同步gecode和fitBounds方法. 但是这两上方法原生就是异步的, 没有同步方法
解决办法
添加2个int型变量, loadingItems和loadedItems。当添加Marker时将loadingItems的值自增1。调用geocode方法解析地址为LatLng对象,在回调函数中将loadedItems值自增1,并执行mapObj.fitBounds(results[0].geometry.viewport) 方法, fitBounds方法会引发bounds_changed事件. 在bounds_changed事件中, 如果loadingItems和loadedItems相等就证明所有Marker加载完毕, 并执行输出按钮的相应逻辑, 代码如下
var mapObj = new google.maps.Map(document.getElementById(targetContainer), mapOptions);
var bounds = new google.maps.LatLngBounds();
bounds.count = 0;
bounds.extendNew = function (latLng) {
this.extend(latLng);
this.count++;
};
function EventBind(target, eventName, func) {
var f = func;
google.maps.event.addListener(target, eventName, function (event) { func(event); });
}
EventBind(mapObj, "bounds_changed", function () {
if (loadingItems == loadedItems) {
if (allLoadedEvent != null) {
loadedItems = -1;
allLoadedEvent();
}
}
});
function AddMarkerWithBlurIcon(strAddress) {
var geocoder1 = new google.maps.Geocoder();
loadingItems++;
geocoder1.geocode({ "address": strAddress }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var markerImage = new google.maps.MarkerImage(
"http://maps.google.com/intl/en_us/mapfiles/ms/micons/blue-dot.png",
new google.maps.Size(20, 32),
new google.maps.Point(0, 0),
new google.maps.Point(0, 32)
);
loadedItems++;
mapObj.fitBounds(results[0].geometry.viewport);
bounds.extendNew(results[0].geometry.location);
var markerObj = new google.maps.Marker(
{
map: mapObj,
position: results[0].geometry.location,
icon: markerImage,
draggable: true
});
}
});
}
allLoadedEvent就是输出按钮的逻辑,allLoadedEvent在下面的方法中添加进来
function ExecuteWhenMapLoadedAll(action, runNow) {
allLoadedEvent = action;
if (runNow == true) mapObj.fitBounds(bounds);
}
在bounds_changed事件中当loadingItems == loadedItems条件成立时就会自动执行allLoadedEvent 。
另一个问题: 当页面有多个地图, 只有所有地图的数据全部加载完以后再执行相应的代码
将上面的代码封装为一个名为GoogleMapHelper的函数, 假设有2个地图,那么
var m1 = new GoogleMapHelper();
var m2 = new GoogleMapHelper();
m1.Initialize();
m2..Initialize();
m1.ExecuteWhenMapLoadedAll(
function (){
/*m1的逻辑代码*/
m2.ExecuteWhenMapLoadedAll(
function (){
/*最终需要执行的代码*/
__doPostBack(“<%= this.btnReport.ClientID %>", "");
}, true);
}, false);