使用百度地图 JS API 播放轨迹

发表于2019-09-09,长度4253, 505个单词, 12分钟读完
Flag Counter

尽管百度在BAT巨头中的名声越来越差,但不可否认百度地图依然是国内使用最广泛、最方便的地图工具。相比高德、腾讯的地图,领先的不是一两点。 我之前吐槽过一次高德的周边,简直不敢回首:高德打车,这辈子不再用

今天简单说一下百度地图API的使用。最近用它实现了一个播放轨迹的功能,就是有一系列轨迹点和对应的时间点组成的时序集合,可以根据不同时间间隔、不同距离间隔进行轨迹相邻点间的移动。

效果如图:

资源准备

百度地图上的标记都是图片,当然它自动了默认的标记图。如果想使用其他图片作为标记(比如图中的电动车),需要自己去下载,并且要指定图片的大小。

我推荐使用https://www.iconfont.cn这个网站,图标多,而且尺寸可以自己选。

实现代码

先引入依赖包和图片:

import moment from 'moment'
import bike from '/assets/bike.png'

我们需要地图对象、轨迹集合、电车标记:

var markerArr = data.list; // 轨迹集合
var map; // 地图对象
var bikeMarker; // 电车标记

然后初始化地图:

if (markerArr.length == 0) return;
map = new BMap.Map("map", { enableMapClick: true }); // 地图显示在ID为map的元素上
var point = new BMap.Point(markerArr[0]['longitude'], markerArr[0]['latitude']); // 中心点为第一个轨迹点
map.centerAndZoom(point, 15);
map.enableScrollWheelZoom(true);
map.addControl(new BMap.MapTypeControl()); // 地图类型
map.addControl(new BMap.NavigationControl()); // 导航控件
map.addControl(new BMap.OverviewMapControl()); // 小地图
map.addControl(new BMap.ScaleControl()); // 缩放控件

接下来是重点。先把轨迹点间的距离和速度算出来,放在一个新集合里:

var pairs = [];
for (var i = 0; ; i++) {
    var cond = false;
    var obj = markerArr[i];
    var point = new BMap.Point(obj['longitude'], obj['latitude']);
    var icon;
    if (i == 0) {
        icon = new BMap.Icon(`${sp}`, new BMap.Size(32, 32), {
        anchor: new BMap.Size(16, 32),
        });
    } else if (i + 1 == markerArr.length) {
        icon = new BMap.Icon(`${dp}`, new BMap.Size(48, 48), {
        anchor: new BMap.Size(24, 48),
        });

        cond = true;
    } else {
        icon = new BMap.Icon(`${cp}`, new BMap.Size(16, 16), {
        anchor: new BMap.Size(8, 8),
        });
    }
    var marker = new BMap.Marker(point, { icon });
    marker.setLabel(new BMap.Label(obj['time'].split('T')[1].split('.')[0], {
        offset: new BMap.Size(25, 5)
    }));
    map.addOverlay(marker);
    if (cond) {
        // 标记完最后一个点就结束
        break;
    }

    const nxtObj = markerArr[i + 1];
    var ruler = this.zoom[map.getZoom() - 1];// 取出比例尺
    const nxtP = new BMap.Point(nxtObj['longitude'], nxtObj['latitude']);
    var timeDiff = moment(nxtObj['time']) - moment(obj['time']);
    timeDiff = parseInt(timeDiff / base);
    var dist = map.getDistance(point, nxtP);
    if (dist * 5 > ruler) {
        // 距离太短的不分段
        const stp = parseInt(dist * 25 / ruler);
        var st = 0;
        var startP = point;
        if (obj['longitude'] == nxtObj['longitude']) {
        const latDiff = (nxtObj['latitude'] - obj['latitude']) / stp;
        while (st < stp) {
            var newLat = startP['lat'] + latDiff;
            var endP = new BMap.Point(nxtObj['longitude'], newLat);
            addLineFreg([startP, endP], timeDiff, stp);

            startP = endP;
            st++;
        }
        } else if (obj['latitude'] == nxtObj['latitude']) {
        const lngDiff = (nxtObj['longitude'] - obj['longitude']) / stp;
        while (st < stp) {
            var newLng = startP['lng'] + lngDiff;
            var endP = new BMap.Point(newLng, nxtObj['latitude']);
            addLineFreg([startP, endP], timeDiff, stp);
            startP = endP;
            st++;
        }
        } else {
        // 不可能出现经纬度都一样 不然距离为0
        var lngDiff = (nxtObj['longitude'] - obj['longitude']) / stp;
        var latDiff = (nxtObj['latitude'] - obj['latitude']) / stp;
        while (st < stp) {
            var newLng = startP['lng'] + lngDiff;
            var newLat = startP['lat'] + latDiff;
            var endP = new BMap.Point(newLng, newLat);
            addLineFreg([startP, endP], timeDiff, stp);
            startP = endP;
            st++;
        }
        }

    } else {
        addLineFreg([point, nxtP], timeDiff, 5);
    }
}

然后根据速度展示集合点:

showLineFreg();

const showLineFreg = async () => {
    for (let i = 0; i < pairs.length; i++) {
    var o = pairs[i]
    await show(o);
    }
}

const show = (pair) => new Promise((resolve, reject) => {
    const to = pair.mock * diss;
    setTimeout(() => {
    if (bikeMarker) {
        map.removeOverlay(bikeMarker);
    }
    
    bikeMarker = new BMap.Marker(pair.points[1], { icon: bicon });
    map.addOverlay(bikeMarker);
    map.addOverlay(new BMap.Polyline(pair.points, {
        strokeColor: "black",
        strokeWeight: 2,
        strokeOpacity: 0.7
    }));
    map.panTo(pair.points[0]);
    resolve();
    }, to);
});

注意使用的异步标记,不然不能一点点移动。

这样就大功告成了!

Written on September 9, 2019
分类: dev, 标签: javascript
如果你喜欢,请赞赏! davelet