使用Google地图API搜索功能
由于工作关系,最近这两天研究了下Google地图API,要实现地图位置搜索功能,显示搜索结果并能在地图上标记下来,刚开始还考虑使用51ditu,出于搜索关键字分词等方面考虑,最后还是决定使用Google地图,一直也都是那么的崇拜谷歌的大神,这次就来体验一翻~
在Google地图标记定位到一点
刚开始是实现在Google地图上定位一点的功能,API接口里GMap2类有一个setCenter(center:GLatLng, zoom?:Number, type?:GMapType)方法可以设置地图中心,GLatLng参数以经度和纬度表示的地理坐标点,zoom和type分别为缩放级别和地图类型的可选参数,GLatLng经纬度坐标点可以通过GClientGeocoder类的getLatLng方法获得,getLatLng方法传入地址关键字参数,在回调函数里传递找到的第一个经纬度坐标点,如果没有找到定位点则为null,这样我们就能根据GLatLng经纬度坐标点创建一个GMarker标记并在地图上显示出来。
搜索定位到多个点
根据关键字定位到会存在一个问题,假如搜索关键字在地图上有多个点的话,那么返回的第一个经纬度坐标点不一定就是你所要找的地址,这个时候就有必要返回多个搜索结果点,然后再能让用户选择。刚开始我还以为Google地图API里没有提供返回多个搜索结果的接口,让老萍各一强银说就跑到了Google AJAX Search API,不过那里确实有实现搜索返回多个结果的示例。今天仔细看了下Google地图API,发现它里面本身是提供搜索功能的,我想AJAX Map Search Solution只是自定义实现封装好了类。其实,在创建GMap2实例时可指定GMapOptions参数,里面的GGoogleBarOptions属性即为搜索控件的选项,然后再调用enableGoogleBar()方法就会为地图启用集成搜索控件,GGoogleBarOptions 类属性如下:
属性 | 类型 | 说明 |
---|---|---|
showOnLoad | Boolean | 当设置为 true 时,该属性显示 GoogleBar 中的搜索框(如果启用了控件并加载了地图)。默认情况下,控件中的搜索框是隐藏的,只有当点击该控件的放大镜时才会展开。
(自 2.95 开始) |
linkTarget | GGoogleBarLinkTarget | 该属性允许指定嵌入 GoogleBar 的搜索结果中的链接目标。默认值为 G_GOOGLEBAR_LINK_TARGET_BLANK,该默认值指定这些链接将在新窗口中打开。
(自 2.95 开始) |
resultList | GGoogleBarResultList or Element | 该属性可让您指定 GoogleBar 的搜索结果列表的样式,该样式可能为以下样式的一种:G_GOOGLEBAR_RESULT_LIST_INLINE(默认样式)将结果列表放入搜索框上的表中;G_GOOGLEBAR_RESULT_LIST_SUPPRESS 使用“下一个”/“上一个”按钮替换该列表;传递块级别的 DOM 的 Element 将列表放入您选择的容器(通常为 <div> 元素)中。
(自 2.95 开始) |
suppressInitialResultSelection | Boolean | 系统完成 GoogleBar 中的搜索后就会在其信息窗口中显示第一个结果(这是默认行为),该属性抑制这种行为。
(自 2.95 开始) |
suppressZoomToBounds | Boolean | 该属性还抑制完成 GoogleBar 中的搜索后自动平移和缩放以适合结果集的操作。(该属性抑制默认行为。)
(自 2.95 开始) |
onIdleCallback | Function | 该属性指定 GoogleBar 完成搜索且搜索结果关闭时要调用的回调函数。
(自 2.95 开始) |
onSearchCompleteCallback | Function | 该属性指定 GoogleBar 完成搜索且搜索结果完全显示时要调用的回调函数向该函数传递与搜索控件相关的 GlocalSearch 对象。在结果放到地图上或结果列表中之前调用该回调函数。
(自 2.95 开始) |
onGenerateMarkerHtmlCallback | Function | 此属性可让您指定打开搜索结果标记的信息窗口时要调用的回调函数。应该向该函数先后传递 GMarker、生成的 HTML 字符串和 GlocalSearchResult,并且该函数必须返回要显示在信息窗口中的已修改 HTML 字符串。
(自 2.95 开始) |
onMarkersSetCallback | Function | 该属性可让您指定 GGoogleBar 完成创建标记并将标记放到地图上时要调用的回调函数。必须向该函数传递一个表格对象数组 {result: GlocalSearch, marker: GMarker}。
(自 2.95 开始) |
点击搜索结果点信息窗口"错位"问题
问题是这样的,点击返回搜索结果列表时地图会定位到当前点,并且会用信息窗口标注这一点,但不知道Google是为了打开的信息窗口完全可见还是做了什么特殊判断,会使得当前标注这一点不能地图里居中,致使标注点偏移信息窗口显示不完全。由于搜索结果是直接指定resultList元素容器来接收存放的,所以我并不知道在点击事件里对Google地图做了什么样的操作,可能查看gmlocalsearch.js源码会了解一些详情。回到问题的原委来,我只需要获取点击的经纬度坐标点就能把地图位置居中,还好搜索有个onSearchCompleteCallback完成时的回调函数,并传递搜索结果参数过来,那么我就在每次搜索完成把结果保存在一个数组变量里,然后在点击搜索结果列表时获取点击元素的id索引号,于是就能获取当前点击的经纬度坐标了,再调用setCenter就能根据坐标点居中地图,由于有信息窗口,坐标点居中不一定能让信息窗口完全可见,而应该是中偏下一些,调用map.panBy(new GSize(-40,100))方法以动画方式平移指定的距离(左:40px,下:100px),需要注意Google地图API里很多方法都是以动画方式,它内部可能是通过setTimeout来延迟执行实现的,所以我这边有时也要用setTimeout来延迟执行,不然我设置的一些值会被Google的setTimeout延迟执行的给覆盖掉。
示例源代码:
<div id="googleSearch"></div><div id="googleResult" style="width:490px; margin:4px 0;"></div><div id="googleMap" style="width:490px; height:300px; border:solid 1px #ccc">loading...</div><link href="http://www.google.com/uds/css/gsearch.css" rel="stylesheet" type="text/css" /><link href="http://www.google.com/uds/solutions/localsearch/gmlocalsearch.css" rel="stylesheet" type="text/css" /><script src="http://ditu.google.cn/maps?file=api&v=2.x&key=ABQIAAAAzr2EBOXUKnm_jVnk0OJI7xSosDVG8KKPE1-m51RBrvYughuyMxQ-i1QfUnH94QxWIa6N4U6MouMmBA&hl=zh-CN" type="text/javascript"></script><script type="text/javascript"> var map = null; var geocoder = null; var mapReady = false; var mapResult = []; function initialize() { if (GBrowserIsCompatible()) { //搜索结果元素 var resultElem = document.getElementById("googleResult"); //地图容器元素 var mapElem = document.getElementById("googleMap"); // 指定实例化地图选项 var options = { //size : new GSize (338,353), googleBarOptions : { onSearchCompleteCallback : function(searcher) { //设置结果 mapResult = searcher.results; //统计结果数 //document.getElementById("sum").innerHTML = searcher.results.length; //搜索完成时候自动居中第一个结果 setTimeout(function() {autoCenter(0);},1000); }, resultList : resultElem , maxCursorPages : 5 , suppressZoomToBounds : true } }; map = new GMap2(mapElem, options); // 平移及缩放控件(左上角) map.addControl(new GLargeMapControl()); //比例尺控件(左下角) map.addControl(new GScaleControl()); //创建缩略图控件(右下角) var overviewMap = new GOverviewMapControl(); map.addControl(overviewMap); //最小化隐藏缩略图控件 setTimeout(function (){overviewMap.hide();},1000); geocoder = new GClientGeocoder(); //为地图启用集成搜索控件GoogleBar(此句顺序位置不可修改) map.enableGoogleBar(); //自动居中结果点 window.autoCenter = function (resultIndex){ var result = mapResult[resultIndex]; if( result ) { setTimeout(function() { //构建以经度和纬度表示的地理坐标点 var point = new GLatLng(result.lat,result.lng); //设置中心点 map.setCenter(point);//map.panTo(point); //以动画方式平移指定的距离(左:40px,下:100px) map.panBy(new GSize(-40,100)); }, 500 ); } } //点击搜索结果事件 resultElem.onclick = function (e){ e = window.event || e; var target = e.target || e.srcElement; var trElem = target; //获取冒泡事件的TR层节点 while(trElem && trElem.tagName!="TR") { if(trElem.tagName=="TABLE") break; trElem = trElem.parentNode; } if (trElem!=null) { //获取点击的结果索引 var resultIndex = trElem.id.substring(trElem.id.length-1); //自动居中 autoCenter(resultIndex); } } //初始化位置 var address = "广东省广州市天河区科韵路22号五华大厦"; if (geocoder) { geocoder.getLatLng( address, function(point) { if (point) { map.setCenter(point, 18); var marker = new GMarker(point); map.addOverlay(marker); marker.openInfoWindowHtml(address); setTimeout(function (){map.panBy(new GSize(-10,120));},2500); } } ); } //获取搜索控件 var searchBar = mapElem.lastChild; //清空样式 searchBar.style.cssText = ""; //改变搜索控件元素位置 document.getElementById("googleSearch").appendChild(searchBar); } } window.onload = function(){ initialize(); document.body.onunload = GUnload; mapReady = true; }</script>