基本功能需求都已经实现(自定义标注、精确和模糊查询、个性化添加、右键菜单等),先贴出效果图:上图布局,最上面是测试通过的浏览器及其版本,左侧是动态加载的数据源和查询功能,右侧则是调用BMap API实现自己的应用知识拓展:关于js和css的浏览器兼容性问题,请参见我在百度空间的博客 Javascript 和 CSS 的浏览器兼容总结设计思路:接口是BMap API,内部功能采用模块化设计,搜索模块、自定义添加、右键菜单事件等,这样设计方便扩展和维护,后期将考虑加入谷歌的GMap下面,详细介绍内部功能是如何设计和实现的1、数据源格式数据源格式是比较规整的,具体格式如下:源码copy to clipboard打印?01.var data = [ 02. { id: 100, point: "116.397128|39.916527", addr: "紫金天子城", mainFlow: 3, subFlow: 169.9, press: 4, voltage: 13.3, flashFlow: 1, isEle: "有市电", time: "2011-7-13 16:30:00" }, 03. { id: 101, point: "116.422792|40.009471", addr: "十里村", mainFlow: 3, subFlow: 169.9, press: 4, voltage: 13.3, flashFlow: 1, isEle: "有市电", time: "2011-7-13 16:30:00" }, 04. { id: 202, point: "116.484289|39.97936", addr: "杨家大湾", mainFlow: 13, subFlow: 19.9, press: 14, voltage: 13.3, flashFlow: 1, isEle: "有市电", time: "2011-7-13 16:30:00" }, 05. { id: 303, point: "116.454494|39.964011", addr: "赵鹏", mainFlow: 3, subFlow: 69.9, press: 4, voltage: 13.3, flashFlow: 1, isEle: "有市电", time: "2011-7-13 16:30:00" }, 06. { id: 404, point: "116.394601|39.987925", addr: "王店", mainFlow: 3, subFlow: 169.9, press: 4, voltage: 13.3, flashFlow: 1, isEle: "有市电", time: "2011-7-13 16:30:00" }, 07. { id: 500, point: "116.469899|39.87684", addr: "刘村", mainFlow: 3, subFlow: 169.9, press: 4, voltage: 13.3, flashFlow: 1, isEle: "有市电", time: "2011-7-13 16:30:00" }, 08. { id: 501, point: "116.331292|39.949031", addr: "西子营", mainFlow: 3, subFlow: 169.9, press: 4, voltage: 13.3, flashFlow: 1, isEle: "有市电", time: "2011-7-13 16:30:00" }, 09. { id: 602, point: "116.374561|39.894302", addr: "马甲镇", mainFlow: 13, subFlow: 19.9, press: 14, voltage: 13.3, flashFlow: 1, isEle: "有市电", time: "2011-7-13 16:30:00" }, 10. { id: 703, point: "116.419527|39.945374", addr: "大牛集市", mainFlow: 3, subFlow: 69.9, press: 4, voltage: 13.3, flashFlow: 1, isEle: "有市电", time: "2011-7-13 16:30:00" }, 11. { id: 804, point: "116.394601|39.987925", addr: "小牛峡湾", mainFlow: 3, subFlow: 169.9, press: 4, voltage: 13.3, flashFlow: 1, isEle: "有市电", time: "2011-7-13 16:30:00" }, 12. { id: 905, point: "116.368099|39.942332", addr: "徐家水库", mainFlow: 3, subFlow: 169.9, press: 4, voltage: 13.3, flashFlow: 1, isEle: "有市电", time: "2011-7-13 16:30:00" } 13. ]; 目前数据源采用的text文本格式进行存储与加载,随着需求和应用的扩大,后期将会使用MySQL数据库进行保存与提取2、动态加载数据源(左侧table)源码copy to clipboard打印?01.function init_MiddleLeft() { 02. var top_div = document.getElementById("id_middle_left"); 03. 04. var table = document.createElement("table"); 05. table.setAttribute("border", 1); 06. table.setAttribute("width", 280); 07. for (var i = 0; i < data.length; i++) { 08. var tr = document.createElement("tr"); 09. 10. var td = document.createElement("td"); 11. var str = data[i].id; 12. var msg = document.createTextNode(str); 13. td.appendChild(msg); 14. tr.appendChild(td); 15. 16. td = document.createElement("td"); 17. str = data[i].addr; 18. msg = document.createTextNode(str); 19. td.appendChild(msg); 20. tr.appendChild(td); 21. 22. td = document.createElement("td"); 23. var img = document.createElement("img"); 24. img.src = "./info.gif"; 25. img.value = this.data[i]; 26. img.onclick = function(){return click(this)}; // img.onclick=Function("click(this.value)"); 27. 28. td.appendChild(img); 29. tr.appendChild(td); 30. 31. table.appendChild(tr); 32. } 33. 34. 35. top_div.appendChild(table); 36. } 左侧动态加载数据源效果图:3、精准与模糊查询(正则式实现)源码copy to clipboard打印?01.// search类原型 02.function searchClass(data) { 03. this.datas = data; 04.} 05. 06.// 设置数据源 07.searchClass.prototype.setData = function (data) { 08. this.datas = data; 09.} 10. 11.// 去掉字符串空格 12.searchClass.prototype.trim = function (str) { 13. if (null == str) { 14. str = ""; 15. } else { 16. str = str.toString(); 17. } 18. 19. return str.replace(/(^[\s\t\xa0\u3000]+)|([\u3000\xa0\s\t]+$)/g, ""); 20.} 21. 22.// search原型查询模块 23.// rule = {id: "id", key: "keyword", query: "single|more", show: "one|all"} 24.searchClass.prototype.search = function (rule) { 25. if (null == this.datas) { 26. alert("数据源不存在!"); 27. return false; 28. } 29. 30. if ("" == this.trim(rule) || "" == this.trim(rule.id) || "" == this.trim(rule.key) || "" == this.trim(rule.query)) { 31. alert("请指定要搜索内容!"); 32. return false; 33. } 34. 35. var reval = []; // 返回值,object数组类型 36. var datas = this.datas; // search类,成员变量 37. me = this; // 全局this,getData中me 38. 39. // 添加查询结果 40. var addData = function (data) { 41. reval.push(data); 42. } 43. 44. // 获取查询数据源串 45. var getData = function (data, id) { 46. var _id = me.trim(id); 47. var d = "data"; 48. if (0 == _id.length) { 49. return data; 50. } else { 51. d += '["' + _id + '"]'; 52. return eval(d); 53. } 54. } 55. 56. // 检索遍历 57. for (var i = 0; i < datas.length; i++) { 58. var data = datas[i]; 59. var d = getData(data, rule.id); 60. var dReg = new RegExp(this.trim(rule.key)); 61. 62. if ("one" == rule.show) { // 显示查询标记 63. if ("single" == rule.query && d == rule.key) { // 精准查询(single) 64. addData(data); 65. } else if ("more" == rule.query && dReg.test(d)) { // 模糊查询(正则式实现) 66. addData(data); 67. } 68. } else if ("all" == rule.show) { // 显示全部标记 69. addData(data); 70. } 71. } 72. 73. // 返回结果 74. return reval; 75.} 4、标记查询的结果源码copy to clipboard打印?01.// 标记查询结果 02.window.addMarker = function (data_a) { 03. map.clearOverlays(); // 首先清理已有标记 04. 05. // 遍历查询结果数据(data_a) 06. for (var i = 0; i < data_a.length; i++) { 07. // 获取坐标(经度、纬度),在地图map上显示 08. var px = data_a[i].point.split("|")[0]; 09. var py = data_a[i].point.split("|")[1]; 10. 11. var point = new BMap.Point(px, py); 12. var marker = new BMap.Marker(point); 13. map.addOverlay(marker); 14. //marker.enableDragging(true); 15. 16. // 生成标记信息(table) 17. var content = "<table>"; 18. content = content + "<tr><td> 设备编号:" + data_a[i].id + "</td></tr>"; 19. content = content + "<tr><td> 安装地点:" + data_a[i].addr + "</td></tr>"; 20. content = content + "<tr><td> 主表流量:" + data_a[i].mainFlow + "</td></tr>"; 21. content = content + "<tr><td> 副表流量:" + data_a[i].subFlow + "</td></tr>"; 22. content = content + "<tr><td> 管网压力:" + data_a[i].press + "</td></tr>"; 23. content = content + "<tr><td> 设备电压:" + data_a[i].voltage + "</td></tr>"; 24. content = content + "<tr><td> 瞬时流量:" + data_a[i].flashFlow + "</td></tr>"; 25. content = content + "<tr><td> 有无市电:" + data_a[i].isEle + "</td></tr>"; 26. content = content + "<tr><td> 记录时间:" + data_a[i].time + "</td></tr>"; 27. content += "</table>"; 28. 29. // 捕获标记点击事件,并且显示信息 30. // 函数闭包,总是执行 31. (function () { 32. var infoWindow = new BMap.InfoWindow(content); 33. marker.addEventListener("click", function () { 34. this.openInfoWindow(infoWindow); 35. }); 36. })() 37. } 38.} 标记效果图:5、右键菜单的实现源码copy to clipboard打印?01.// 添加右键菜单 02.var contextMenu = new BMap.ContextMenu(); 03.var txtMenuItem = [ 04. { 05. text: "放大", 06. callback: function () { map.zoomIn() } 07. }, 08. { 09. text: "缩小", 10. callback: function () { map.zoomOut() } 11. }, 12. { 13. text: '查看北京', 14. callback: function () { map.centerAndZoom("北京") } 15. }, 16. { 17. text: '放置到最大', 18. callback: function () { map.zoomTo(18) } 19. }, 20. { 21. text: '获取改点坐标', 22. callback: function(p){ 23. var px = p.lng; 24. var py = p.lat; 25. alert("该点坐标:\n经度:" + px + "; \n纬度:" + py); 26. } 27. }, 28. { 29. text: '添加该店标注', 30. callback: function (p) { 31. var marker = new BMap.Marker(p), px = map.pointToPixel(p); 32. map.addOverlay(marker); 33. marker.enableDragging(true); 34. } 35. } 36.]; 37. 38.// 遍历菜单items,添加进菜单 39.for (var i = 0; i < txtMenuItem.length; i++) { 40. contextMenu.addItem(new BMap.MenuItem(txtMenuItem[i].text, txtMenuItem[i].callback, 100)); 41. if (i == 1 || i == 3) { 42. contextMenu.addSeparator(); 43. } 44.} 45.map.addContextMenu(contextMenu); // 添加菜单到map 菜单效果图:6、模糊查询结果左侧,输入“1”,模糊匹配查询和显示查询结果右侧,输出3个标记结果校验:100、101、501三项,都含有查询关键字"1“,查询结果正确7、关注细节,改善体验在实现过程中,也考虑了一些细节处理,这里举两个示例a、输入框自动提示当用户没有输入时,输入框显示提示信息"input id",当用户鼠标点击后,提示信息自动清除(是不是很像AJAX的水印效果 哈哈)其实,其内部实现也不复杂,但不经意的设计,体现的却是很人性化具体实现(onmousedown和onmouseout)源码copy to clipboard打印?01.<input type="text" name="keyword" id="id_keyword" value="input id" onmousedown="clearKeyword('keyword')" 02. onmouseout="showKeyword('keyword')" /> 源码copy to clipboard打印?01.// 用户按下鼠标,提示信息清除 02.function clearKeyword(keyword) { 03. var input = document.getElementsByName(keyword); 04. input[0].value = ""; // 清除提示 05. 06.} 07. 08.// 鼠标移走,如果内容为空,则重新提示 09.function showKeyword(keyword) { 10. var input = document.getElementsByName(keyword); 11. var value = input[0].value; 12. if ("" == value) { // 判断是否为空 13. input[0].value = "input id"; 14. } 15.} b、左侧查询高亮显示点击查询小图标后,此栏背景色高亮显示,是用户一目了然实现代码如下:源码copy to clipboard打印?01.// 点击左侧查询小图标 02.function click(obj) { 03. // 先清理所有td元素,擦除上次高亮显示脚印 04. var td_a = document.getElementsByTagName("td"); 05. for (var i = 0; i < td_a.length; i++) { 06. td_a[i].setAttribute("bgcolor", "#ffffff"); 07. } 08. 09. // 高亮标记本次查询信息 10. obj.parentNode.setAttribute("bgcolor", "#ff0000"); 11. 12. var data_a = []; 13. var data = obj.value; 14. data_a.push(data); 15. addMarker(data_a); 16.}