百度地图获取行政区域以及自定义显示网格

目录

1 问题描述

2 独立显示区域

3 自定义网格

4 显示自定义网格

5 延展

6 参考文献


1 问题描述

(1) 通过百度地图或者高德地图只展示某一个行政区域,例如整个地图只展示郑州市金水区,其他区域不显示。

(2) 整个地图只显示自定义的区域,并显示区域的自定义名称。

百度地图的JSAPI有关于显示行政区域边界的专用方法,参考百度官方的例子

百度官方api提供的这个功能,就是直接根据行政区域的名称来检索,并显示边界信息的。最多到县级,再往下就没有了,更不要说社区、乡村这些了,甚至有些边远地区的行政边界也是没有的。并且官方的这个例子,也不支持仅仅只显示指定的区域,无法屏蔽到其他地图的能力。

关于行政边界的数据不是公开的,只有专业的地图测绘相关的公司有比较准确的数据。我们想用,要么找破解工具下载相对老的数据零散数据,要么掏钱找第三方地图服务的公司买。当然,我们也可以通过自己确定社区或者乡村的边界,在地图上打点,自定义覆盖物边界的方式自行圈出所需区域的边界

2 独立显示区域

所谓独立显示指定区域,指的是在地图上我只显示某一区域的地图,其他地图不想显示。例如:我只显示郑州市金水区的地图,其他地方都是空白。如何实现?在放代码之前,说一点我自己的认识和理解,不管怎样,地图都是一层一层的,根据级别不同,显示的地图颗粒度不同,百度地图关于覆盖物有比较清晰的API定义,那么实现思路其实就是,通过自定义添加多层覆盖物的方式来实现独立显示某一区域,例如:我们先给以全局覆盖物,把整个地图都盖住,然后再给一个覆盖物,显示具体的行政区域数据。

代码如下:

<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width" /><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title></title><script src="http://code.jquery.com/jquery-1.8.2.min.js"></script><script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=你的ak"></script><script type="text/javascript" src="http://api.map.baidu.com/library/AreaRestriction/1.2/src/AreaRestriction_min.js"></script><style type="text/css">html {height: 100%;}body {height: 100%;margin: 0px;padding: 0px;}#container {height: 100%;}</style>
</head><body>
<div id="container"></div><script type='text/javascript'>//提示:下面的代码用jquery,所以如果有不能运行的情况请引用后尝试//百度地图api container对应前端div名称 前端要引用2.0版本的百度地图api//需引用api.map.baidu.com/library/AreaRestriction/1.2/src/AreaRestriction_min.jsvar map = new BMap.Map("container", { enableMapClick: false }); // 创建地图实例,禁止点击地图底图//设置样式map.setMapStyle({styleJson: [{//不显示点信息"featureType": "poi","elementType": "all","stylers": {"color": "#ffffff","visibility": "off"}}]});map.disableDragging();//禁止拖动map.disableDoubleClickZoom();//禁止双击缩放var blist = [];var districtLoading = 0;function getBoundary() {addDistrict("郑州市金水区");}/*** 添加行政区划* @param {} districtName 行政区划名* @returns  无返回值*/function addDistrict(districtName) {//使用计数器来控制加载过程districtLoading++;var bdary = new BMap.Boundary();bdary.get(districtName, function (rs) {       //获取行政区域var count = rs.boundaries.length; //行政区域的点有多少个if (count === 0) {alert('未能获取当前输入行政区域');return;}for (var i = 0; i < count; i++) {blist.push({ points: rs.boundaries[i], name: districtName });};//加载完成区域点后计数器-1districtLoading--;if (districtLoading == 0) {//全加载完成后画端点drawBoundary();}});}/*** 各种鼠标事件绑定*/function click(evt) {alert(evt.target.name);}function mouseover(evt) {evt.target.label.setZIndex(99);evt.target.label.setPosition(evt.point);evt.target.label.show();}function mousemove(evt) {evt.target.label.setPosition(evt.point);}function mouseout(evt) {evt.target.label.hide();}function drawBoundary() {//包含所有区域的点数组var pointArray = [];/*画遮蔽层的相关方法*思路: 首先在中国地图最外画一圈,圈住理论上所有的中国领土,然后再将每个闭合区域合并进来,并全部连到西北角。*      这样就做出了一个经过多次西北角的闭合多边形*///定义中国东南西北端点,作为第一层var pNW = { lat: 59.0, lng: 73.0 }var pNE = { lat: 59.0, lng: 136.0 }var pSE = { lat: 3.0, lng: 136.0 }var pSW = { lat: 3.0, lng: 73.0 }//向数组中添加一次闭合多边形,并将西北角再加一次作为之后画闭合区域的起点var pArray = [];pArray.push(pNW);pArray.push(pSW);pArray.push(pSE);pArray.push(pNE);pArray.push(pNW);//循环添加各闭合区域for (var i = 0; i < blist.length; i++) {//添加显示用标签层var label = new BMap.Label(blist[i].name, { offset: new BMap.Size(20, -10) });label.hide();map.addOverlay(label);//添加多边形层并显示var ply = new BMap.Polygon(blist[i].points, { strokeWeight: 5, strokeColor: "#FF0000", fillOpacity: 0.01, fillColor: " #FFFFFF" }); //建立多边形覆盖物ply.name = blist[i].name;ply.label = label;ply.addEventListener("click", click);ply.addEventListener("mouseover", mouseover);ply.addEventListener("mouseout", mouseout);ply.addEventListener("mousemove", mousemove);map.addOverlay(ply);//添加名称标签层var centerlabel = new BMap.Label(blist[i].name, { offset: new BMap.Size(0, 0) });centerlabel.setPosition(ply.getBounds().getCenter());map.addOverlay(centerlabel);//将点增加到视野范围内var path = ply.getPath();pointArray = pointArray.concat(path);//将闭合区域加到遮蔽层上,每次添加完后要再加一次西北角作为下次添加的起点和最后一次的终点pArray = pArray.concat(path);pArray.push(pArray[0]);}//限定显示区域,需要引用api库var boundply = new BMap.Polygon(pointArray);BMapLib.AreaRestriction.setBounds(map, boundply.getBounds());map.setViewport(pointArray);    //调整视野//添加遮蔽层var plyall = new BMap.Polygon(pArray, { strokeOpacity: 0.0000001, strokeColor: "#000000", strokeWeight: 0.00001, fillColor: "#000000", fillOpacity: 0.7 }); //建立多边形覆盖物map.addOverlay(plyall);}setTimeout(function () {getBoundary();}, 100);
</script>
</body>

显示效果如下:

我们可以通过调整plyall遮罩层的颜色来改变底层的透明度,也可以完全不显示。

3 自定义网格

实际使用过程中,很多的社区、乡村的边界数据是没有的,我们无法直接通过bdary.get方式获取到,此时我们可以通过自定义划边界打点的功能来自定义边界区域,获取边界的所有点坐标,然后在以覆盖物的方式显示出来,就能满足需要。这个工具主要是来自参考文献2,我这里仅仅根据自己的需要做了微量调整,具体代码如下:

<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=gb2312" /><title>自动以选取行政区域的工具</title><script type="text/javascript" src="http://api.map.baidu.com/api?v=1.2"></script>
</head>
<body>
<div>
<div style="width:1200px;height:700px;border:1px solid gray;float: left;" id="container"></div>
<div style="float: right;width: calc(100% - 1220px);height: 1200px;padding-top: 350px;"><input id="startBtn" type="button" onclick="startTool();" value="开启取点工具" /><input type="button" onclick="clearInfos();" value="清除" />
</div>
</div>
<div id="info"></div>
<br/>
<h1>拷贝下面的数据信息到test2中去展示这个网格吧,相应的,你也可以把这个数据保存到数据库里,前端按需展示</h1>
<div id="code_infos"></div>
</body>
</html>
<script type="text/javascript">var map = new BMap.Map("container");// 创建Map实例map.centerAndZoom("郑州", 11);     // 初始化地图,设置中心点坐标和地图级别map.enableScrollWheelZoom();    //开启鼠标滚轮缩放var key = 1;    //开关var newpoint;   //一个经纬度var points = [];    //数组,放经纬度信息var polyline = new BMap.Polyline(); //折线覆盖物function clearInfos(){map.clearOverlays();document.getElementById('info').innerHTML = '';document.getElementById('code_infos').innerHTML = '';points=[];}function startTool(){   //开关函数if(key==1){document.getElementById("startBtn").style.background = "green";document.getElementById("startBtn").style.color = "white";document.getElementById("startBtn").value = "开启状态";key=0;}else{document.getElementById("startBtn").style.background = "red";document.getElementById("startBtn").value = "关闭状态";key=1;}}map.addEventListener("click",function(e){   //单击地图,形成折线覆盖物newpoint = new BMap.Point(e.point.lng,e.point.lat);if(key==0){//    if(points[points.length].lng==points[points.length-1].lng){alert(111);}points.push(newpoint);  //将新增的点放到数组中polyline.setPath(points);   //设置折线的点数组map.addOverlay(polyline);   //将折线添加到地图上document.getElementById("info").innerHTML += "new BMap.Point(" + e.point.lng + "," + e.point.lat + "),</br>";    //输出数组里的经纬度}});map.addEventListener("dblclick",function(e){   //双击地图,形成多边形覆盖物if(key==0){map.disableDoubleClickZoom();   //关闭双击放大var polygon = new BMap.Polygon(points);console.log(points);var c_points ='';for(var i=0;i<points.length;i++){if(i>0){c_points+=';'}c_points+=points[i].lng+', '+ points[i].lat;}var codeinfos ={points: c_points, name: '网格名称'}console.log(codeinfos);document.getElementById("code_infos").innerHTML = JSON.stringify(codeinfos);map.addOverlay(polygon);   //将折线添加到地图上}});
</script>

主要是添加了一个div用来把自定义划好网格区域的points数据放到一个对象种,并展示出来,使用的时候,直接拿这串数据去展示即可。关于工具有几点说明:

(1) 开启取点工具后,即可在地图上单击选点,从第二次点击开始,后续每次单击都会画一条线连接当前点和上一个点

(2) 双击鼠标会自动连接当前点和起始点,形成一个闭环的覆盖物显示到地图上,并将相关points信息在页面展示出来

4 显示自定义网格

在自定义工具中获取到的边界数据信息格式如下:

{points:"113.673169, 34.792905;113.673349, 34.791423;113.673313, 34.789289;113.673241, 34.787154;113.673493, 34.785969;113.673349, 34.785583;113.667312, 34.785583;113.664438, 34.785553;113.662318, 34.785731;113.658221, 34.792016;113.657143, 34.793706;113.657, 34.793943;113.66318, 34.79338;113.665372, 34.79335;113.666953, 34.793232;113.669792, 34.793083;113.673169, 34.792965;113.673169, 34.792965",name:"网格名称"};

我们优化改造下显示指定行政区域地图的代码,在通过bdary.get获取不到百度官方的行政区域数据的时候,使用自定义覆盖物的数据来展示,核心调整代码如下:

function getBoundary() {var points_code={points:"113.673169, 34.792905;113.673349, 34.791423;113.673313, 34.789289;113.673241, 34.787154;113.673493, 34.785969;113.673349, 34.785583;113.667312, 34.785583;113.664438, 34.785553;113.662318, 34.785731;113.658221, 34.792016;113.657143, 34.793706;113.657, 34.793943;113.66318, 34.79338;113.665372, 34.79335;113.666953, 34.793232;113.669792, 34.793083;113.673169, 34.792965;113.673169, 34.792965",name:"网格名称"};addDistrict("郑州大学",points_code);}/*** 添加行政区划* @param {} districtName 行政区划名* @returns  无返回值*/function addDistrict(districtName,points_code) {//使用计数器来控制加载过程districtLoading++;var bdary = new BMap.Boundary();bdary.get(districtName, function (rs) {       //获取行政区域var count = rs.boundaries.length; //行政区域的点有多少个if (count === 0) {alert("没有找到官方关于"+districtName+"的行政边界信息,使用自定义区域显示");blist.push(points_code);}else{for (var i = 0; i < count; i++) {blist.push({ points: rs.boundaries[i], name: districtName });};}//加载完成区域点后计数器-1districtLoading--;if (districtLoading == 0) {//全加载完成后画端点drawBoundary();}});}

显示效果如下

.

5 延展

有时候,客户可能因为安全原因或者网络缘故,要求使用离线地图,而且为了避免业务数据被百度或者高德抓取,要求不让使用百度或者高德的地图,这里推荐一个前端开源的js地图框架,OpenLayer,非常的强大,配合GeoServer以及postgis数据库,通过下载离线的瓦片数据,可以实现非常强大的地图效果。

6 参考文献

【1】百度地图api(javascript)只显示某一行政区域的地图,其他周边地区的都不显示

【2】【百度地图API】自行获取区域经纬度的工具

 

Published by

风君子

独自遨游何稽首 揭天掀地慰生平