以下内容设计的主要功能点:
目录
路书边运动边画轨迹(使用BMap.DrivingRoute对路径进行修正)
接下来依次实现上述功能
路书的基本使用
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>百度地图API路书实现历史轨迹回放</title>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=你的密钥"></script>
<!-- 你在百度地图开放平台申请的ak -->
<!-- 路书功能 -->
<script src="http://api.map.baidu.com/library/LuShu/1.2/src/LuShu_min.js"></script>
</head>
<body>
<!-- 地图容器 -->
<div id="allmap" style="position: absolute; width: 100%; top: 50px; bottom: 0px"></div>
<script type="text/javascript">
<!--新建地图及添加控件-->
var map = new BMap.Map("allmap", { minZoom: 9, maxZoom: 19 });
var point = new BMap.Point(116.128554, 24.294562);
map.centerAndZoom(point, 9); //设置中心点和缩放比例
var top_left_navigation = new BMap.NavigationControl();
map.addControl(top_left_navigation);// 添加平移缩放控件
map.addControl(new BMap.ScaleControl({ anchor: BMAP_ANCHOR_TOP_LEFT })); // 添加比例尺控件
map.addControl(new BMap.OverviewMapControl()); //添加缩略地图控件
map.enableScrollWheelZoom();//启用滚轮放大缩小
//中心点坐标
var carCenterPoint = new BMap.Point(113.408984, 23.174023);
map.centerAndZoom(carCenterPoint , 17);
//显示车辆轨迹线
//车辆轨迹坐标
var latLngArray = [
"113.408984,23.174023",
"113.406639,23.174023",
"113.403944,23.173566",
"113.400827,23.17394",
"113.397468,23.174496",
"113.391494,23.174513",
"113.389032,23.174588",
"113.388736,23.173217",
"113.388511,23.171888",
"113.388592,23.170501",
"113.38861,23.170219",
"113.38861,23.168342",
"113.388574,23.165218"
];
//添加路书图标
var icons = new BMap.Icon('C:\\Users\\out of the common\\Downloads\\car.png', new BMap.Size(32,32),{anchor: new BMap.Size(16, 16)});
//路书默认信息窗口内容
var trackContent = "某车辆轨迹回放";
//添加路书
var lushu = new BMapLib.LuShu(map,pois,{
defaultContent: trackContent,
icons: [icons],
autoView: false,//是否开启自动视野调整,如果开启那么路书在运动过程中会根据视野自动调整
speed: 100, //路书速度
enableRotation: true,//是否设置marker随着道路的走向进行旋转
});
</script>
</body>
</html>
路书的开始、暂停、继续
增加控件
<div id="controls">
<!-- 开始按钮 -->
<button onclick="start()">开始</button>
<!-- 暂停按钮 -->
<button onclick="pause()">暂停</button>
<!-- 继续按钮 -->
<button onclick="resume()">继续</button>
<!-- 暂停按钮 -->
<button onclick="stop()">暂停</button>
<!-- 播放进度条 -->
<input type="range" id="progress" min="0" max="100" value="0" step="1">
</div>
增加js代码
// 定义开始、暂停、继续、停止函数
function start() {
lushu.start();
}
function pause() {
lushu.pause();
}
function resume() {
lushu.start();
}
function stop() {
lushu.stop();
}
完整代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>百度地图API路书实现历史轨迹回放</title>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=你的密钥"></script>
<!-- 你在百度地图开放平台申请的ak -->
<!-- 路书功能 -->
<script src="http://api.map.baidu.com/library/LuShu/1.2/src/LuShu_min.js"></script>
</head>
<body>
<!-- 在此处添加控制按钮和滑动条 -->
<div id="controls">
<!-- 开始按钮 -->
<button onclick="start()">开始</button>
<!-- 暂停按钮 -->
<button onclick="pause()">暂停</button>
<!-- 继续按钮 -->
<button onclick="resume()">继续</button>
<!-- 暂停按钮 -->
<button onclick="stop()">暂停</button>
</div>
<div id="allmap" style="position: absolute; width: 100%; top: 50px; bottom: 0px"></div>
<script type="text/javascript">
var map = new BMap.Map("allmap", { minZoom: 9, maxZoom: 19 });
var point = new BMap.Point(116.128554, 24.294562);
var top_left_navigation = new BMap.NavigationControl();
map.addControl(top_left_navigation);// 添加平移缩放控件
map.addControl(new BMap.ScaleControl({ anchor: BMAP_ANCHOR_TOP_LEFT })); // 添加比例尺控件
map.addControl(new BMap.OverviewMapControl()); //添加缩略地图控件
map.enableScrollWheelZoom();//启用滚轮放大缩小
map.centerAndZoom(point, 9);
//中心点坐标
var carCenterPoint = new BMap.Point(113.408984, 23.174023);
map.centerAndZoom(carCenterPoint , 17);
var pois = [];
//车辆轨迹坐标
var latLngArray = [
"113.408984,23.174023",
"113.406639,23.174023",
"113.403944,23.173566",
"113.400827,23.17394",
"113.397468,23.174496",
"113.391494,23.174513",
"113.389032,23.174588",
"113.388736,23.173217",
"113.388511,23.171888",
"113.388592,23.170501",
"113.38861,23.170219",
"113.38861,23.168342",
"113.388574,23.165218"
];
//对坐标进行处理,获取BMap.Point对象
for(var i = 0; i < latLngArray.length ; i++) {
var latLng = latLngArray[i];
var pointArray = latLng.split(",");
pois.push(new BMap.Point(pointArray[0], pointArray[1]));
}
//轨迹显示样式
var sy = new BMap.Symbol(BMap_Symbol_SHAPE_BACKWARD_OPEN_ARROW, {
scale: 0.6,//图标缩放大小
strokeColor: '#fff',//设置矢量图标的线填充颜色
strokeWeight: '2',//设置线宽
});
var icons = new BMap.IconSequence(sy, '10', '30');
//创建polyline对象
var polyline = new BMap.Polyline(pois, {
enableEditing: false,//是否启用线编辑,默认为false
enableClicking: true,//是否响应点击事件,默认为true
icons: [icons],
strokeWeight: '8',//折线的宽度,以像素为单位
strokeOpacity: 0.8,//折线的透明度,取值范围0 - 1
strokeColor: "#18a45b" //折线颜色
});
map.addOverlay(polyline);
//添加路书图标
var ls_icons = new BMap.Icon('C:\\Users\\out of the common\\Downloads\\car.png', new BMap.Size(32,32),{anchor: new BMap.Size(16, 16)});
//路书默认信息窗口内容
var trackContent = "某车辆轨迹回放";
//添加路书
var lushu = new BMapLib.LuShu(map,pois,{
defaultContent: trackContent,
icons: [ls_icons],
autoView: false,//是否开启自动视野调整,如果开启那么路书在运动过程中会根据视野自动调整
speed: 100,
enableRotation: true,//是否设置marker随着道路的走向进行旋转
});
// 定义开始、暂停、继续、停止函数
function start() {
lushu.start();
}
function pause() {
lushu.pause();
}
function resume() {
lushu.start();
}
function stop() {
lushu.stop();
}
</script>
</body>
</html>
滑动条控制路书速度
添加控件
这里滑动条用的是Bootstrap Slider<!-- 引入 Bootstrap Slider 相关文件 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/11.0.2/css/bootstrap-slider.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/11.0.2/bootstrap-slider.min.js"></script>
<!-- 播放速度 -->
<span>播放速度</span>
<input type="range" id="speed">
添加代码
//滑动条
var slider = new Slider('#speed', {
min: 1, //最小值
max: 500, //最大值
step: 50, //步长
value: 100, //默认值
});
slider.on("change", function (obj) { //滑动条改变事件
var value = obj.newValue;
if (lushu != null) {
lushu._opts.speed = parseInt(value);
}
});
滑动条控制路书进度
添加控件
<!-- 播放进度条 -->
<span>播放进度</span>
<input type="range" id="process">
添加代码
- 滑动条控制进度
设置滑动条的最大值为路书数据的长度-1,当拖动时修改路书实例的属性,这个 i 对应的就是路书当前运动的数据索引。$('#process').slider({ orientation: "horizontal", //排列方式 value: 0, min: 0, max: pois.length - 1, //pois为路书数据 slide: function (event, ui) { //拖动 if (lushu.i < ui.value) { //快进 如果滑动条的进度大于路书当前的进度,则把滑动条设置为路书当前的进度 $('#process').slider('value', lushu.i); } else { //后退 lushu.i = ui.value; } if (ui.value == pois.length - 1) { pause(); } } });
- 滑动条的值随着路书的运动增加
其实就是重写路书的源码,BMapLib.LuShu.prototype._move指的就是路书运动时执行的函数,增加的代码就一行:$('#process').slider('value', this.i);
BMapLib.LuShu.prototype._move = function (initPos, targetPos, effect) {
$('#process').slider('setValue', this.i);
var me = this,
//当前的帧数
currentCount = 0,
//步长,米/秒
timer = 10,
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);
//如果小于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++;
var 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) {
var 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);
};
路书运动过程信息窗口内容改变
重写源码
其实关键代码也只有me._overlay.setHtml("现在运动到第"+me.i+"个数据了");
BMapLib.LuShu.prototype._setInfoWin = function (pos) {
//设置上方overlay的position
var me = this;
if (!me._overlay) {
return;
}
me._overlay.setPosition(pos, me._marker.getIcon().size);
var index = me._troughPointIndex(pos);
if (index != -1) {
clearInterval(me._intervalFlag);
me._overlay.setHtml(me._opts.landmarkPois[index].html);
me._overlay.setPosition(pos, me._marker.getIcon().size);
me._pauseForView(index);
} else {
me._overlay.setHtml("现在运动到第"+me.i+"个数据了");
}
};
路书边运动边画轨迹(使用BMap.DrivingRoute对路径进行修正)
修改BMapLib.LuShu.prototype._move
直接加代码,我这里使用了bmap.drivingroute(百度地图路线规划),因为有时候我们的点坐标不准容易飘点,画出来的线路不在道路上。
initPos和targetPos就是路书每次运动的开始点和结束点
onsearchcomplete是获取driving.search结果之后的回调函数,具体的可以去官网详细看看
onmarkersset是获取图标,我这里的操作是删除了始发站和终点站的图标
var pointsArr = [initPos,targetPos];
var driving = new bmap.drivingroute(map, {
onsearchcomplete: function (results) {
if (driving.getstatus() == bmap_status_success) {
let path = results.getplan(0).getroute(0).getpath();
let polyline = new bmap.polyline(path, { strokecolor: "#18a45b", strokeweight: 8 });
map.addoverlay(polyline);
_this.group.push(polyline);
}
},
onmarkersset: function (routes) {
map.removeoverlay(routes[0].marker); //删除起点
map.removeoverlay(routes[1].marker);//删除终点
}
});
driving.search(pointsArr[0], pointsArr[1]);
要是不想用线路规划直接添加折线也可以的,完整的代码如下
BMapLib.LuShu.prototype._move = function (initPos, targetPos, effect) {
$('#process').slider('setValue', this.i);
var pointsArr = [initPos,targetPos];
var me = this,
//当前的帧数
currentCount = 0,
//步长,米/秒
timer = 10,
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);
// //添加折线
var driving = new bmap.drivingroute(map, {
onsearchcomplete: function (results) {
if (driving.getstatus() == bmap_status_success) {
let path = results.getplan(0).getroute(0).getpath();
let polyline = new bmap.polyline(path, { strokecolor: "#18a45b", strokeweight: 8 });
map.addoverlay(polyline);
_this.group.push(polyline);
}
},
onmarkersset: function (routes) {
map.removeoverlay(routes[0].marker); //删除起点
map.removeoverlay(routes[1].marker);//删除终点
}
});
driving.search(pointsarr[0], pointsarr[1]);
//如果小于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++;
var 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) {
var 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);
};