时间 : 15-02-08 栏目 : 技术笔记 作者 : eekuang 评论 : 0 点击 : 4,446 次
研一跟着导师做了一个关于城市沙井盖监控的项目,其中的沙井盖管理中心(网站形式)就采用了百度地图的WEB接口。其实项目早在14年9月份就已经结束了,奈何本人患有拖延症,一直没有静下心来写一写关于百度地图二次开发的经历。转眼间,研二上学期就结束了,还有十天,就是农历新年了。就现在吧,写写开发经验,技术大牛轻喷。
我做的是一个物联网项目——城市沙井盖监控。我们通过百度地图,将沙井盖节点可视化显示在百度地图上,然后通过点击井盖节点进行管理(授权、去授权、告警响应、查询)。由于WEB不能一直保持在线,故我们在进行节点管理的时候,实际上是通过数据库来进行数据中转。硬件端直接与上位机数据交互,上位机和WEB端实时读取数据库的数据信息,实现与硬件端的数据交互。整个系统的架构如下图所示(CANET可近似认为是井盖物理节点):
举个例子,现在某井盖节点被恶意打开,此时节点通过通信线路将数据发送到上位机软件,上位机软件接收到数据后立即将该节点的状态信息更新至MySQL数据库,WEB端通过实时读取数据库数据,更新地图上的显示。此时,数据库中该节点的状态数据更新为“非法打开”,地图上该节点的状态图标为对应的非法打开图样,如下图所示。
如今的主流的几种地图(谷歌地图、百度地图、高德地图等)都提供了API接口,考虑到谷歌这年对国内支持不太够,百度地图相对内容更为详尽,我选择了百度地图。百度地图为开发者提供了丰富的开发接口,为WEB端提供了JS API和Flash API(已停止更新),我选择的是JS API。特别注意,API版本在v1.5以上的,就必须申请密钥(ak)才能调用接口。密钥申请较为简单,此处就不再赘言。
作为一个技术小白,你的第一感觉应该是:这就是百度地图接口?那我怎么拿来用呢?
由于地图使用的是JS代码,故首先你得对javascript有大概认识(至少要能读懂)。新手建议先试试百度地图提供的地图生成器,通过手动生成一些地图代码,来了解地图的代码结构。生成器网址:http://api.map.baidu.com/lbsapi/createmap/index.html。看完示例代码,实际上可以看出来,百度地图是通过在网页上嵌入一个固定大小DIV容器,在容器内显示从百度地图官网中调用来的地图数据。
当然,仅仅看完示例代码,你也只能创建一个静态的地图,不能自定义地在地图上添加各种你想要的功能。下面我就说说我用到的功能的一些实现办法。当然,由于我也仅仅只是用到了百度地图的部分功能,所以本文章阐述的东西还是非常有限的。
function iniMarkers() { var xmlhttp; var user=document.getElementById("user").innerText; //获取当前登陆管理员id if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp=new XMLHttpRequest(); } else {// code for IE6, IE5 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { if(xmlhttp.responseText!="") { wellArr=xmlhttp.responseText.split(";");//结点数据通过";"分割 addMarker();//将数据添加到地图图层 updateInfo();//定时刷新地图数据显示 } else { window.alert("该用户暂未安排节点监控管理。"); } } } xmlhttp.open("GET","mcmProcess.php?flag=fetchWelllist&user="+user,true);//获取结点数据 xmlhttp.send(); }
function addMarker(){ point= new BMap.Point(wellArr[0].split("|")[2],wellArr[0].split("|")[3]); map.centerAndZoom(point,17);//设定地图的中心点和坐标并将地图显示在地图容器中 for(var i=0;i<window.wellArr.length-1;i++){ canet[i] = window.wellArr[i].split("|")[0]; canid[i] = window.wellArr[i].split("|")[1]; lng[i] = window.wellArr[i].split("|")[2]; lat[i] = window.wellArr[i].split("|")[3]; state[i] = window.wellArr[i].split("|")[4]; descr[i] = window.wellArr[i].split("|")[5]; var point = new BMap.Point(lng[i],lat[i]); var sateImg; switch(state[i]) { case '1': stateImg="img/authored.png"; break; case '2': stateImg="img/authoropened.png"; break; case '3': stateImg="img/warn.png"; break; case '19': stateImg="img/warnacked.png"; break; case '255': stateImg="img/lost.png"; break; default: stateImg="img/normal.png"; break; } var iconImg = new BMap.Icon(stateImg,new BMap.Size(20,20)); var marker = new BMap.Marker(point,{icon:iconImg}); var iw = createInfoWindow(i); var label = new BMap.Label(canid[i],{"offset":new BMap.Size(17,0)});//右,下, marker.setLabel(label); map.addOverlay(marker); markers[i]=marker; label.setStyle({ borderColor:"#808080", color:"#333", cursor:"pointer" }); (function(){ var index = i; var _iw = createInfoWindow(i); var _marker = marker; _marker.addEventListener("click",function(){ this.openInfoWindow(_iw); document.getElementById("canet").value=canet[index]; document.getElementById("canid").value=canid[index]; }); _iw.addEventListener("open",function(){ _marker.getLabel().hide(); }) _iw.addEventListener("close",function(){ _marker.getLabel().show(); }) label.addEventListener("click",function(){ }) label.show(); })() } }
当然,显示出来还是第一步,之后还要定时获取数据库更新的数据,更新地图显示。我将更新这一过程封装在updateinfo()函数中,具体实现代码如下:
function updateInfo() { if(timeCount!=0) { if(timeCount==5) { document.getElementById("report").value= document.getElementById("report").value+"\n无法与数据库取得连接,通信异常!"; return; } ++timeCount; setTimeout("updateInfo()",2000); return; } if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp=new XMLHttpRequest(); } else {// code for IE6, IE5 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { if(xmlhttp.responseText!="") { reportProcess(xmlhttp.responseText); } setTimeout("updateInfo()",2000); timeCount=0; } } user=document.getElementById('user').innerText; xmlhttp.open("GET","mcmProcess.php?flag=fetchReport&user="+user,true); xmlhttp.send(); ++timeCount; }
在updateinfo()函数中,我使用了Window的一个method,setTimeout()。该函数可以定时执行某一函数,我们用它定时执行updateinfo()函数。updateinfo函数通过AJAX技术,定时查询更新的数据,然后将更新数据显示出来。上述函数中嵌套了reportProcess子函数,就是用于更新显示。具体实现代码如下:
function reportProcess(responseStr)
{
var reportStr=document.getElementById("report").value;
reportArr=responseStr.split(";");
var iconImg;
var stateStr;
for(var i=0;i!=reportArr.length;++i)
{
switch(reportArr[i].split("|")[3])
{
case "255":
iconImg=new BMap.Icon("img/lost.png",new BMap.Size(20,20));
if(reportArr[i].split("|")[2]=="0")
{//canet失联了
reportStr=reportStr+reportArr[i].split("|")[0]+" CANET:"+
reportArr[i].split("|")[1]+"失联!\n";
for(var j=0;j!=window.canet.length;++j)
{
if(window.canet[j]==reportArr[i].split("|")[1])
{
markers[j].setIcon(iconImg);
}
}
}
else
{//节点失联了
for(var j=0;j!=window.canet.length;++j)
{
if(window.canet[j]==reportArr[i].split("|")[1]&&
window.canid[j]==reportArr[i].split("|")[2])
{
markers[j].setIcon(iconImg);
reportStr=reportStr+reportArr[i].split("|")[0]+" CANET:"
+reportArr[i].split("|")[1]+"节点:"+reportArr[i].split("|")[2]+"失联!\n";
}
}
}
break;
case "0"://正常关闭
var iconImg=new BMap.Icon("img/normal.png",new BMap.Size(20,20));
if(reportArr[i].split("|")[2]=="0")
{//canet建立连接了
reportStr=reportStr+reportArr[i].split("|")[0]+" CANET:"
+reportArr[i].split("|")[1]+"状态正常!\n";
for(var j=0;j!=window.canet.length;++j)
{
if(window.canet[j]==reportArr[i].split("|")[1])
{
markers[j].setIcon(iconImg);
}
}
}
else
{//节点查询到了
for(var j=0;j!=window.canet.length;++j)
{
if(window.canet[j]==reportArr[i].split("|")[1]&&
window.canid[j]==reportArr[i].split("|")[2])
{
markers[j].setIcon(iconImg);
reportStr=reportStr+reportArr[i].split("|")[0]+" CANET:"
+reportArr[i].split("|")[1]+"节点:"+reportArr[i].split("|")[2]+"正常!\n";
}
}
}
break;
case "1"://授权关闭
case "2"://授权打开
case "3"://非法打开
case "9"://确认完成授权
case "11"://取消授权成功
if(reportArr[i].split("|")[3]=="1")
{
iconImg=new BMap.Icon("img/authored.png",new BMap.Size(20,20));
stateStr="处于授权关闭!\n";
}else if(reportArr[i].split("|")[3]=="2")
{
iconImg=new BMap.Icon("img/authoropened.png",new BMap.Size(20,20));
stateStr="处于授权打开!\n";
}else if(reportArr[i].split("|")[3]=="3")
{
iconImg=new BMap.Icon("img/warn.png",new BMap.Size(20,20));
stateStr="处于非法打开!\n";
}else if(reportArr[i].split("|")[3]=="9")
{
iconImg=new BMap.Icon("img/authored.png",new BMap.Size(20,20));
stateStr="授权成功!\n";
}else if(reportArr[i].split("|")[3]=="11")
{
iconImg=new BMap.Icon("img/normal.png",new BMap.Size(20,20));
stateStr="取消授权成功!\n";
}
for(var j=0;j!=window.canet.length;++j)
{
if(window.canet[j]==reportArr[i].split("|")[1]&&
window.canid[j]==reportArr[i].split("|")[2])
{
markers[j].setIcon(iconImg);
reportStr=reportStr+reportArr[i].split("|")[0]+" CANET:"
+reportArr[i].split("|")[1]+"节点:"+reportArr[i].split("|")[2]+stateStr;
}
}
break;
case "10"://授权失败
case "12"://取消授权失败
case "13"://已处于授权状态
case "14"://已处于非授权状态
case "19"://非法打开,已响应
if(reportArr[i].split("|")[3]=="10")
{
stateStr="授权失败!\n";
}else if(reportArr[i].split("|")[3]=="12")
{
stateStr="取消授权失败!\n";
}else if(reportArr[i].split("|")[3]=="13")
{
stateStr="已处于授权状态!\n";
}else if(reportArr[i].split("|")[3]=="14")
{
stateStr="已处于非授权状!\n";
}else if(reportArr[i].split("|")[3]=="19")
{
iconImg=new BMap.Icon("img/warnacked.png",new BMap.Size(20,20));
stateStr="非法打开,已响应报警!\n";
}
for(var j=0;j!=window.canet.length;++j)
{
if(window.canet[j]==reportArr[i].split("|")[1]&&
window.canid[j]==reportArr[i].split("|")[2])
{
markers[j].setIcon(iconImg);
reportStr=reportStr+reportArr[i].split("|")[0]+" CANET:"
+reportArr[i].split("|")[1]+"节点:"+reportArr[i].split("|")[2]+stateStr;
}
}
break;
}
}
document.getElementById("report" ).value=reportStr;
}
我这里使用的代码方法比较笨,就是用遍历的办法逐个更新节点。但其实,对于本项目性能上是能够满足的。为什么这么说呢?首先,在本项目中,虽然监控的总的井盖节点数据众多,但实际上每个区域的井盖节点是不多的。在实际情况中,各个系统用户应该只是管理他所在辖区内的井盖节点,这些节点是有限数目的。因而,这样的代码从性能上是能够保证顺畅运行的。但,这并不代表这些代码是高效率的。算是本人的惰性吧,在完成功能实现后,没有花太多心思用在提高代码执行效率上,没有重构代码。所以,本文仅希望能给初学者稍稍启发,读者就别吐槽俺的糟糕代码了。
从开发难度上来说,百度地图的二次开发难度还是不大的。个人认为,在官网上已经提供了足够详细的开发文档,所以开发人员只要熟读开发指南,就足以能够进行快速的二次开发。地图的开放接口为广大商家大大节约了自己制作和维护地图的成本,给各大地图提供商点个赞!
除非注明,文章均为( eekuang )原创,转载请保留链接: http://www.14en.com/?p=122