百度地图官方提供的BMapGL,不能直接实现边走边画的功能,自带api也没有此功能。所以从网上找了许多案例,然后结合了自己的一些理解整合出了下面的基本功能。
需求: 从后台获得坐标点阵,画出轨迹图,小车动画跟随画线,边走边画。附加速度调整功能和暂停开始功能。
分析: 原生js不能实现边走边画,所以我们要自己来画线,画线具体操作见下方
首先要引入
<!-- 百度地图 -->
<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=自己的"></script>
<!-- 路书 -->
<script type="text/javascript" src="http://api.map.baidu.com/library/LuShu/1.2/src/LuShu_min.js"></script>
然后是页面部分,这里是通过弹窗来新增一个路书地图,需要引入elementUI
<!-- 弹窗 -->
<el-dialog
title="轨迹回放"
:visible.sync="dialogVisible"
width="1200px"
:before-close="cancel">
<div class="win-cont">
<!-- 时间 -->
<!-- 这个部分是通过时间段从后台获取坐标点集合的查询框 -->
<el-form class="form-cont">
<el-form-item label="时间选择">
<el-date-picker
v-model="startEndTime"
type="datetimerange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitPlay" size="medium">查询</el-button>
</el-form-item>
</el-form>
<!-- 播放按钮 -->
<div class="play-cont" @click="playMap">
<svg-icon v-if="!play" icon-class="play" class-name="card-panel-play" />
<svg-icon v-else icon-class="close_1" class-name="card-panel-play" />
</div>
<!-- 速度控制 -->
<!-- 这里用的是elementui选择器,用法可看官网 -->
<div class="speed-select">
<el-select v-model="speed" placeholder="速度变更">
<el-option
v-for="item in options"
:key="item.speed"
:label="item.label"
:value="item.speed"
@change="speedChange"
size="mini">
</el-option>
</el-select>
</div>
<div :id="id" class="map1" style="height:520px; width: 100%"></div>
</div>
</el-dialog>
下面是功能部分
创建(路书)地图
createPolyMap (data, row) {
console.log(data, row, this.id)
let bmap = new BMap.Map(this.id) // 创建Map实例
bmap.centerAndZoom(new BMap.Point(row.lat, row.lng), 19) // 初始化地图,设置中心点坐标和地图级别19
bmap.enableScrollWheelZoom(true) //设置地图可通过鼠标滚轮缩放
bmap.setMapType(BMAP_HYBRID_MAP); //设置地图类型为混合型
this.bmap = bmap
// 清除轨迹缓存
this.bmap.clearOverlays()
//创建轨迹
this.createPolyLine(data, bmap)
}
创建轨迹和画线逻辑
createPolyLine (data, bmap) {
let points = []
if (!data.length) return
data.forEach(e => {
points.push(new BMap.Point(e.lat, e.lng))
})
let icon = 'http://developer.baidu.com/map/jsdemo/img/car.png'
let marker=new BMap.Marker(points[0],{
//引入小车图标,前面一个size参数是图标大小,后面一个size是中心点位置,一般一半就行
icon : new BMap.Icon(icon, new BMap.Size(44,44),{anchor : new BMap.Size(22, 22)})
})
//展示时小车样式
let label = new BMap.Label('',{offset:new BMap.Size(0,-30)});
label.setStyle({border:"2px red rgb(204, 204, 204)",color: "rgb(2, 0, 0)",borderRadius:"10px",padding:"5px",background:"rgb(222, 255, 255)",});
marker.setLabel(label);
bmap.addOverlay(marker);
//设置路书动画
BMapLib.LuShu.prototype._move=function(initPos,targetPos,effect) {
let pointsArr=[initPos,targetPos]; //点数组
let me = this,
//当前的帧数
currentCount = 0,
//步长,米/秒
timer = 5,
step = this._opts.speed / (1000 / timer),
//初始坐标
init_pos = this._projection.lngLatToPoint(initPos),
//获取结束点的(x,y)坐标
target_pos = this._projection.lngLatToPoint(targetPos),
//总的步长
count = Math.round(me._getDistance(init_pos, target_pos) / step);
//显示折线 syj201607191107
// 画线操作
this._map.addOverlay(new BMap.Polyline(pointsArr, {
strokeColor : "red",
strokeWeight : 3,
strokeOpacity : 0.5
}));
//如果小于1直接移动到下一点
if (count < 1) {
me._moveNext(++me.i);
return;
}
me._intervalFlag = setInterval(function() {
//两点之间当前帧数大于总帧数的时候,则说明已经完成移动
if (currentCount >= count) {
clearInterval(me._intervalFlag);
//移动的点已经超过总的长度
if(me.i > me._path.length){
return;
}
//运行下一个点
me._moveNext(++me.i);
}else {
currentCount++;
let x = effect(init_pos.x, target_pos.x, currentCount, count),
y = effect(init_pos.y, target_pos.y, currentCount, count),
pos = me._projection.pointToLngLat(new BMap.Pixel(x, y));
//设置marker
if(currentCount == 1){
let proPos = null;
if(me.i - 1 >= 0){
proPos = me._path[me.i - 1];
}
if(me._opts.enableRotation == true){
me.setRotation(proPos,initPos,targetPos);
}
if(me._opts.autoView){
if(!me._map.getBounds().containsPoint(pos)){
me._map.setCenter(pos);
}
}
}
//正在移动
me._marker.setPosition(pos);
//设置自定义overlay的位置
me._setInfoWin(pos);
}
},timer);
};
console.log(bmap, points)
this.setMapZoom(bmap, points)
},
根据坐标集points设置百度地图
setMapZoom (map, points) {
let view = map.getViewport(points),
mapZoom = view.zoom,
centerPoint = view.center
map.centerAndZoom(centerPoint,mapZoom)
if (this.dialogVisible) {
this.mapPlay(map, points)
}
},
轨迹动画的设置及播放动画
mapPlay(map,points){
//创建路书
let icon = img_forklift
//因为是单一弹窗播放,所以用var来全局控制
var trackAni = new BMapLib.LuShu(map,points,{
defaultContent:'叉车',//路书展示内容
autoView:true,//是否开启自动视野调整
//图标设置
icon : new BMap.Icon(icon, new BMap.Size(44,44),{anchor : new BMap.Size(22, 22)}),
speed: this.speed,//速度
enableRotation:true,//是否设置marker随着道路的走向进行旋转
landmarkPois:[
//停顿点 html 展示内容 pauseTime 停留时间 1s
// {lng:116.363364,lat:39.920393,html:'测试点',pauseTime:1}
]
});
this.points=points
this.map=map
this.trackAni = trackAni
trackAni.start();
},
暂停和播放功能
playMap () {
let { play, trackAni } = this
if (!play) {
trackAni.start()
this.play = true
} else {
trackAni.pause()
this.play = false
}
},
速度控制
speedChange(){
this.trackAni._opts.speed = this.speed
}
核心功能和代码如上所示,下面是效果截图
大功告成!