最近因为需要,研究了一下地图API,有Google的、百度的、还有MapABC的,有MapBar的,虽然个人觉得Google地图比起其他的要强得不止一点两点 ,但最终还是选择了百度地图,主要原因是Google地图没有直接的公交查询接口,这是唯一让人遗憾的事情。而其他地图有些功能是不免费对外开放的,只有百度地图免费开放程度最大。但是百度地图有一个最让人头痛的地方,那就是非常不稳定...而且貌似对商业项目有一定的查询限制。非常纳闷的是当我知道这个情况的时候,项目已经做得差不多了,之前是打算用Google,但后来做到一半发现Google地图没有直接的公交查询接口。转而用MapABC,但是又发现它一些功能需要Money的。当选择用MapBar的时候就非常小心了,但最后结果很让人不满意...这其中可谓一波三折啊。最后选择用百度的,这次是不能再变了。项目经不起折腾啊...
好了,废话不多说了,下面是我用百度API做的一个搜索控件,直接上代码:
1 // 添加事件
2 function addEventHandler(tatget, eventName, handler) {
3 if (tatget.addEventListener) {
4 tatget.addEventListener(eventName, handler, false);
5 } else if (tatget.attachEvent) {
6 tatget.attachEvent("on" + eventName, handler);
7 } else {
8 tatget["on" + eventName] = handler;
9 }
10 }
11
12 // 移除事件
13 function removeEventHandler(tatget, eventName, handler) {
14 if (tatget.removeEventListener) {
15 tatget.removeEventListener(eventName, handler, false);
16 } else if (tatget.eventName) {
17 tatget.detachEvent("on" + eventName, handler);
18 } else {
19 tatget["on" + eventName] = null;
20 }
21 }
22
23 // 判断是否存在某className
24 function hasClass(target, name) {
25 return target.className.match(new RegExp('(\\s|^)' + name + '(\\s|$)'));
26 }
27
28 // 移除class
29 function removeClass(target, name) {
30 if (hasClass(target, name)) {
31 target.className = target.className.replace(new RegExp('(\\s|^)' + name + '(\\s|$)'), ' ');
32 }
33 }
34
35 // 添加class
36 function addClass(target, name) {
37 if (!hasClass(target, name)) {
38 target.className += " " + name;
39 }
40 }
41
42 // 获取location
43 function loc(target, dire) {
44 var i = 0;
45 while (target) {
46 i += target["offset" + dire];
47 if (target.offsetParent) {
48 if (target.offsetParent.style.position == "absolute") {
49 return i;
50 }
51 }
52 target = target.offsetParent;
53 }
54 return i;
55 }
56
57 String.prototype.trim = function() { return this.replace(/(^\s*)|(\s*$)/g, ""); }
58 String.prototype.format = function() { var txt = this; i = arguments[0].length; while (i--) { txt = txt.replace(new RegExp('\\{' + i + '\\}', 'gm'), arguments[0][i]); } return txt; }
59
60 // SearchBox控件
61 function SearchBox(options) {
62 this.callback = null;//回调函数,在点击搜索时调用,需要我们去覆盖的
63 this.pretender = document.createElement("ul");// 下拉列表的容器
64 this.searchBox = document.createElement("input");// 搜索框
65 this.searchBox.setAttribute("type", "text");
66 this.searchButton = document.createElement("input");// 搜索按钮
67 this.searchButton.setAttribute("type", "button");
68 this.map = null;// 地图对象
69
70 if(options)
71 {
72 this.defaultAnchor = options.anchor || BMAP_ANCHOR_BOTTOM_RIGHT;// 默认停靠在地图的右下方
73 this.defaultOffset = options.offset || new BMap.Size(10, 10);// 默认与地图边界的margin
74 }
75 else
76 {
77 this.defaultAnchor = BMAP_ANCHOR_BOTTOM_RIGHT;// 默认停靠在地图的右下方
78 this.defaultOffset = new BMap.Size(10, 10);// 默认与地图边界的margin
79 }
80 this.city = "";// 在哪个城市搜索?
81 }
82
83 // 继承自百度地图控件类
84 SearchBox.prototype = new BMap.Control();
85
86 // 初始化
87 SearchBox.prototype.initialize = function(map) {
88 this.map = map;
89 var casing = document.createElement("div");
90 casing.className = "searchbox_casing";
91
92 var txt = this.searchBox;
93 txt.className = "searchbox_box";
94
95 var drop = this.pretender;
96
97 var self = this;
98 addEventHandler(txt, "blur", function() {
99 window.setTimeout(function() { drop.style.display = "none"; }, 150);
100 });
101 addEventHandler(txt, "keydown", function(e) {
102 var key = txt.value.trim();
103 var code = e ? (e.charCode || e.keyCode) : 0;
104 if (key != "" && (code == 38 || code == 40)) {
105 var curr = null;
106 var childs = drop.childNodes;
107 for (var i = 0; i < childs.length; i++) {
108 if (hasClass(childs[i], "curr")) {
109 removeClass(childs[i], "curr");
110 switch (code) {
111 case 38:
112 curr = childs[i].previousSibling;
113 break;
114 case 40:
115 curr = childs[i].nextSibling;
116 break;
117 }
118 break;
119 }
120 }
121 if (!curr) {
122 switch (code) {
123 case 38:
124 curr = drop.lastChild;
125 break;
126 case 40:
127 curr = drop.firstChild;
128 break;
129 }
130 }
131 addClass(curr, "curr");
132 txt.value = curr.innerHTML;
133 }
134 else if (code == 13) {
135 self.search();
136 return false;
137 }
138 });
139
140 var timer = 0;
141 var town = this.city;
142 window.setInterval(function() {
143 if (timer > 0) {
144 timer -= 2;
145 } else if (timer < 0) {
146 timer = 0;
147 var key = txt.value.trim();
148 if (key != "") {
149 var callback = function(result) {
150 if (result) {
151 var count = result.getCurrentNumPois();
152 if (count > 0) {
153 drop.innerHTML = "";
154 for (var i = 0; i < count; i++) {
155 var item = result.getPoi(i);
156 var item_box = document.createElement("li");
157 item_box.innerHTML = item.title;
158
159 addEventHandler(item_box, "mouseover", (function(item_box) { return function() { addClass(item_box, "hover"); } })(item_box));
160 addEventHandler(item_box, "mouseout", (function(item_box) { return function() { removeClass(item_box, "hover"); } })(item_box));
161 addEventHandler(item_box, "click", (function(item_box) { return function() { txt.value = item_box.innerHTML; } })(item_box));
162 drop.appendChild(item_box);
163 }
164
165 var size = map.getSize();
166 var map_container = map.getContainer();
167 var offs = self.getOffset();
168
169 var left = loc(map_container, "Left");
170 var top = loc(map_container, "Top");
171 switch (self.getAnchor()) {
172 case BMAP_ANCHOR_TOP_LEFT:
173 top += offs.height + 30;
174 left += offs.width + 25;
175 break;
176 case BMAP_ANCHOR_TOP_RIGHT:
177 top += offs.height + 30;
178 left += size.width - offs.width - 432;
179 break;
180 case BMAP_ANCHOR_BOTTOM_LEFT:
181 top += size.height - offs.height;
182 left += offs.width + 25;
183 break;
184 case BMAP_ANCHOR_BOTTOM_RIGHT:
185 top += size.height - offs.height;
186 left += size.width - offs.width - 432;
187 break;
188 }
189 drop.style.left = left + "px";
190 drop.style.top = top + "px";
191 drop.style.display = "block";
192 }
193 }
194 };
195 var options = { pageCapacity: 10, onSearchComplete: callback };
196 new BMap.LocalSearch(town || map, options).search(key);
197 } else {
198 drop.style.display = "none";
199 }
200 }
201 }, 50);
202
203 addEventHandler(txt, "keyup", function(e) {
204 e = e || window.event;
205 var code = e ? (e.charCode || e.keyCode) : 0;
206 if ((code < 37 || code > 40) && code != 13) {
207 timer = 11;
208 }
209 });
210
211 casing.appendChild(txt);
212 this.pretender.className = "searchbox_pretender";
213
214 map.getContainer().parentNode.appendChild(this.pretender);
215
216 var btn = this.searchButton;
217 btn.className = "searchbox_btn";
218
219 addEventHandler(btn, "click", function() {
220 self.pretender.style.display = "none";
221 self.search();
222 });
223
224 casing.appendChild(btn);
225
226 map.getContainer().appendChild(casing);
227 return casing;
228 }
229
230 SearchBox.prototype.search = function() {
231 var key = this.searchBox.value;
232 if (key == "") {
233 alert("请输入您要搜索的地址!");
234 return;
235 }
236
237 this.pretender.style.display = "none";
238
239 var self = this;
240 var geocoder = new BMap.Geocoder();
241 geocoder.getPoint(key, function(point) {
242 self.callback(point);
243 }, this.city);
244 }
下面是页面调用的代码:
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2 <html xmlns="http://www.w3.org/1999/xhtml">
3 <head>
4 <title>百度地图自定义控件</title>
5 <!-- 导入样式 -->
6 <link href="js/searchbox/searchbox.css" rel="stylesheet" type="text/css" />
7 <!-- 导入百度地图API脚本 -->
8 <script type="text/javascript" src="http://api.map.baidu.com/api?v=1.1&services=true"></script>
9 <!-- 导入控件脚本 -->
10 <script type="text/javascript" src="js/searchbox/searchbox.js"></script>
11
12 <style type="text/css">
13 #map
14 {
15 width: 800px;
16 height: 500px;
17 }
18 </style>
19 </head>
20 <body onload="pageLoad();">
21 <div id="map" class="searchbox_casing">
22 </div>
23
24 <script type="text/javascript">
25 var map;
26 function pageLoad() {
27 var zoom = 14;
28 map = new BMap.Map("map");
29 map.enableScrollWheelZoom();
30 map.addControl(new BMap.NavigationControl());
31 map.centerAndZoom(new BMap.Point(113.287967,23.138278), zoom);
32
33 var searchbox = new SearchBox({anchor:BMAP_ANCHOR_TOP_RIGHT});// 创建搜索控件对象,并设置它停靠在地图的右上位置
34 searchbox.city = "北京市";// 在北京市查找数据
35 searchbox.callback = function(point){// 设置回调函数
36 // 如果找到地址了就在该坐标添加一个标记
37 if(point)
38 {
39 map.centerAndZoom(point, zoom);
40 marker = new BMap.Marker(point);
41 map.addOverlay(marker);
42 }
43 else
44 {
45 alert("没查到数据!");
46 }
47 }
48 map.addControl(searchbox); // 将搜索控件添加到地图上
49 }
50 </script>
51
52 </body>
53 </html>
顺便把CSS样式也贴上来,我用的是Firefox 4.0,本人样式比较菜鸟,在其他浏览器可能会有点走位...
1 .searchbox_casing { width :452px;overflow :hidden;height :30px;}
2 .searchbox_casing .searchbox_box { border:none; text-indent:30px; width:370px; height:31px; overflow:hidden; line-height:31px;background:url("images/txt_bg.gif") no-repeat 0 -64px;}
3 .searchbox_casing .searchbox_btn { border:none; cursor:pointer; width:80px; height:30px; font-size:14px; background:url("images/btnsearch_bg.gif") no-repeat; text-align:center; color:#fff; padding-top:0px;}
4 .searchbox_pretender { list-style:none; padding:0; font-size:12px; margin:0; width:348px; display:none; position:absolute; z-index:1000; border:solid 2px #ADADAC; background:#fff;}
5 .searchbox_pretender li { padding:2px 0 2px 5px; list-style:none; margin:0;}
6 .searchbox_pretender li.curr { background:#FDC451; }
7 .searchbox_pretender li.hover { background:#FDC451; cursor:pointer;}
另外贴上效果图: