百度地图JS API 和原生JS 制作城市疫情可视化地图

561 阅读3分钟

7-8月的时候,南京突如其来的陷入了一场没头没脑的疫情,一家人分隔在城市的各个角落,每天都会紧张的查看今日新增,小小的数字显得十分沉重。

试着用了支付宝,微信,卫健委官网的疫情地图,发现这些地图最多精确到市。而每天的通报则会精确到街道,于是我就想用做一张区划更细、数据可视化的地图。

先上基础效果图:

IMG_9292.JPG

工具

  • 原生 JS
  • 百度地图 JavaScript API v2.0

做地图的时候我还不太会用react,干脆原生JS上阵。
百度地图 JavaScript API 现在已有 3.0,为了方便查找资料我用了2.0,3.0版本向下兼容,所以个人感觉使用3.0更好。
JavaScript API v3.0类参考

准备工作

使用百度地图 API 需先申请秘钥(ak)

lbs.baidu.com/apiconsole/…

输入应用名 -> 选择浏览器端 -> Refer临时可填 *

具体可参考开发指南

<script type="text/javascript" src="https://api.map.baidu.com/api?v=2.0&ak=你的秘钥&s=1"></script>

添加参数 s=1 使地图支持 HTTPS。

开始

// 百度地图
const map = new BMap.Map("container", {drawMargin: 100, drawer: BMAP_SVG_DRAWER_FIRST });

// 控制按钮和滚轮
map.addControl(new BMap.NavigationControl({type: BMAP_NAVIGATION_CONTROL_SMALL}));
map.enableScrollWheelZoom();

自定义中心点

地图打开时会请求当前坐标,以当前市的中心点为默认中心,但南京地跨长江,南北距离长于东西,默认中心显示时会有点歪。

可以通过坐标拾取工具寻找任意点转化的坐标:坐标拾取工具

坐标拾取工具也可以用于确定缩放尺度。

百度地图API一共分为19级,比例尺分别为:

[1:20米(简称20米,后同),50米,100米,200米,500米,1公里,2公里,5公里,10公里,20公里,25公里,50公里,100公里,200公里,500公里,1000公里,2000公里,5000公里,10000公里]

分别对应:

[19级,18级,17级,16级,15级,14级,13级,12级,11级,10级,9级,8级,7级,6级,5级,4级,3级,2级,1级]

缩放尺度为整数

// 中心点坐标
let centre_point = new BMap.Point(118.779425,31.939229);
// 设置中心点和缩放尺度
map.centerAndZoom(centre_point, 10);

定位并显示坐标

百度地图提供三种定位方式:

接口类名简介
浏览器定位Geolocation优先调用浏览器H5定位接口,如果失败会调用IP定位
IP定位LocalCity根据用户IP 返回城市级别的定位结果
定位SDK辅助定位Geolocation当您的APP中有内置的Web页面,同时在Web页面需要提供您的当前位置信息时,可调用集成在App中的百度地图定位SDK来获取更精准的位置信息

JavaScript API - 定位| 百度地图API SDK

如果只使用其中一种定位方式,有时候定位会出现偏差,精度也只到“市”,默认定位落在该市区划第一位的区里。

SDK 辅助定位的精度最高,province / city / district / street / streetNumber

// 定位所在地并显示坐标
const geolocation = new BMap.Geolocation();
// 自定义坐标 icon
const icon_marker = new BMap.Icon("img/marker.png", new BMap.Size(40, 42));
//创建地理编码器
const gc = new BMap.Geocoder();
// 开启SDK辅助定位
geolocation.enableSDKLocation();
geolocation.getCurrentPosition(function(r){
    if(this.getStatus() === BMAP_STATUS_SUCCESS){
        let mk = new BMap.Marker(r.point,{icon: icon_marker});
        map.addOverlay(mk);
        map.panTo(r.point);
        // alert('您的位置:' + r.point.lng + ',' + r.point.lat);

        let pt = r.point;
        map.panTo(pt);//移动地图中心点
        // console.log(map.pointToPixel(pt));

        gc.getLocation(pt, function(rs){
            let addComp = rs.addressComponents;
            let curr_district = addComp.district;
            let current_value = districts[curr_district] === undefined ? 0 : districts[curr_district];
            let high_risk_num = high[current_value] === undefined ? 0 : Object.keys(high[current_value]).length;
            let middle_risk_num = middle[current_value] === undefined ? 0 : Object.keys(middle[current_value]).length;

            // alert(addComp.province + addComp.city + addComp.district + addComp.street + addComp.streetNumber);
        });
    }
    else {
        alert('failed'+this.getStatus());
    }
});

添加多边形覆盖物实现数据可视化

BMap.Boundary(),完整的区划名(市+区)获取该区划的边界坐标点。

BMap.Polygon 接收一组坐标点,创建多边形

  • strokeWeight 边框粗细
  • strokeColor: 边框颜色
  • fillColor 填充颜色
  • fillOpacity 填充透明度

let district_fullname = city_name + district_name;
let boundary = new BMap.Boundary();
boundary.get(district_fullname, function(result){
    // 行政区域的点有多少个
    let count = result.boundaries.length;

    for(let i = 0; i < count; i++){
        let ply = new BMap.Polygon(result.boundaries[i], {strokeWeight: 2, strokeColor: boundary_color, fillColor: district_color, fillOpacity: district_opacity});
        map.addOverlay(ply);
    }
}

最终成品

github: github.com/norayao/cov…

demo: covid19-map.emist.top/