利用百度地图前端实现矢量县区地图下载(json)

4,813 阅读3分钟

我们在做可视化开发的时候常常需要下载某些地方的适量地图数据,利用echarts等去渲染相关数据,当然我们完全可以利用GIS技术去实现,但是GIS相对我们比较简单的需求成本有点过大,因为你需要制图、配准、发布,再到前段开发,这样有点得不偿失。

所以我们有时候仅仅需要一个县区的边界,比如我们需要展现“凤翔县”的行政边界我们现在可以这样做

Step 1

打开链接:百度地图API > 覆盖物示例 > 添加行政区划 lbsyun.baidu.com/jsdemo.htm#… 看到如下界面:

注意上图的右边显示了一个北京市的边界。 再看左边的代码里有这么一段话:

function getBoundary(){       
    var bdary = new BMap.Boundary();
    bdary.get("北京市海淀区", function(rs){ //获取行政区域
        map.clearOverlays();        //清除地图覆盖物       
        var count = rs.boundaries.length; //行政区域的点有多少个
        if (count === 0) {
            alert('未能获取当前输入行政区域');
            return ;
        }
    ……

通过一个GET请求去获取北京市海淀区的边界,我们打印出来看看,可以这样做:

function getBoundary(){       
    var bdary = new BMap.Boundary();
    bdary.get("北京市海淀区", function(rs){ //获取行政区域
        //--------------------
        console.log(rs)
        //--------------------
        map.clearOverlays();        //清除地图覆盖物       
        var count = rs.boundaries.length; //行政区域的点有多少个
        if (count === 0) {
            alert('未能获取当前输入行政区域');
            return ;
        }
    ……

在控制台看到的结果:

你会发现一个问题:控制台会输出一个数组,内部存储一个字符串,但是太长了没法复制,这里我们可以选择两个办法:

  1. 把这个结果存储到本地Local Storage里面,然后去那个里面复制。
  2. 请看Step 2

Step 2

改造上面的代码中getBoundary()函数如下:

function getBoundary(){       
    var bdary = new BMap.Boundary();
    bdary.get("凤翔县", function(rs){       //获取行政区域
        map.clearOverlays();        //清除地图覆盖物       
        var count = rs.boundaries.length; //行政区域的点有多少个
            console.log(rs.boundaries);
        var content = rs.boundaries
        var fileName = '凤翔县.txt'
        var aLink = document.createElement('a');
        var blob = new Blob([content]);
        var evt = document.createEvent("HTMLEvents");
            evt.initEvent("click", false, false);
            aLink.download = fileName;
            aLink.href = URL.createObjectURL(blob);
            aLink.dispatchEvent(evt);
            aLink.click();
            if (count === 0) {
                alert('未能获取当前输入行政区域');
                return ;
            }
        var pointArray = [];
            for (var i = 0; i < count; i++) {
                var ply = new BMap.Polygon(rs.boundaries[i], {strokeWeight: 2, strokeColor: "#ff0000"}); //建立多边形覆盖物
                map.addOverlay(ply);  //添加覆盖物
                pointArray = pointArray.concat(ply.getPath());
            }    
        map.setViewport(pointArray);    //调整视野  
        addlabel();               
    });   
}

点击运行按钮等待2s会自动下载一个凤翔县.txt文件,打开后里面的内容如下

107.653733, 34.657435;107.648513, 34.661217;107.625176, 34.705117;107.609942, 34.707262;107.594553, 34.736579;107.584968, 34.730437;107.579062, 34.745847;107.573426, 34.745894;……

我们可以使用js的字符串切割方法对其进行以';'切割,之后再转换成二维数组,然后利用convas、svg技术描点绘制出来,其中类似107.653733就是x坐标利用js的经纬度转墨卡托算法(当然你也可以直接渲染,但保证地图上的点也是经纬度)在将其转换成墨卡托平面直角坐标系坐标,就可以了,当然会得出一个很大的值,我们可以除与共同系数来改变整体渲染结果的大小,我么还可以利用此去绑定鼠标事件。

经纬度转墨卡托算法

没接触过GIS的同学可能不知道这是什么意思,大致是这样的:

大家都知道,地球是个球体,那么经纬度明显表达的是一个度数,直接用其绘制出来的图形不是个平面的会有一定的变形,所以科学家墨卡托假想一个与地轴方向一致的圆柱切或割于地球,按等角条件,将经纬网投影到圆柱面上,将圆柱面展为平面后,即得投影。墨卡托投影在切圆柱投影与割圆柱投影中,最早也是最常用的是切圆柱投影。 算法公式在下面:

function _getMercator(poi) {//[114.32894, 30.585748]
    var mercator = {};
    var earthRad = 6378137.0;//赤道周长
        mercator.x = poi.lng * Math.PI / 180 * earthRad;
    var a = poi.lat * Math.PI / 180;
        mercator.y = earthRad / 2 * Math.log((1.0 + Math.sin(a)) / (1.0 - Math.sin(a)));
    return mercator; //[12727039.383734727, 3579066.6894065146]
}

原文地址