效果图:

说明:

1.该功能是在这篇博客基础上完成的:ArcGIS JS API 实现路径轨迹回放  但是里面有点小问题:首先,小车并不是匀速运动的,而是每一段的运行时间固定,所以在该博客上进行了修改;另一方面,Leaflet中没有提供设置图标旋转角度的方法,因此需要先对Marker类进行扩展。

2.另外还参考了百度地图路书开源库,本来是想直接把js文件拿过来用,但是里面很多方法都和Bmap对象绑定,不能直接使用。

3.百度开源库中是先将经纬度坐标转为平面坐标再进行插值,插值之后再转为经纬度坐标,这样做的目的就只为了计算出真实距离,然后根据设置的速度进行真实模拟;Leaflet中没有提供地理坐标转平面坐标的方法,因此是直接用的经纬度进行插值,因此回放速度只是一个相对速度。

实现代码:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>路径轨迹回放</title><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="stylesheet" href="./lib/leaflet/leaflet.css" /><script src="./lib/leaflet/leaflet.js"></script></head><style>* { margin: 0; padding: 0; }html, body { height: 100%; }#mapid { width:100%; height:100%; }.input-card{z-index: 50;display: flex;flex-direction: column;min-width: 0;word-wrap: break-word;background-color: #fff;background-clip: border-box;border-radius: .25rem;width: 8rem;border-width: 0;border-radius: 0.4rem;box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);position: fixed;bottom: 1rem;right: 1rem;-ms-flex: 1 1 auto;flex: 1 1 auto;padding: 0.75rem 1.25rem;}
</style><body><div id="mapid" style="z-index: 10" ></div>
<div class="input-card"><button id="run"  onclick="start()">run</button><button id="stop" onclick="stop()">stop</button><button id="pause" onclick="pause()">pause</button>
</div><script>/*** 为Marker类添加方法*/(function() {// save these original methods before they are overwrittenvar proto_initIcon = L.Marker.prototype._initIcon;var proto_setPos = L.Marker.prototype._setPos;var oldIE = (L.DomUtil.TRANSFORM === 'msTransform');L.Marker.addInitHook(function () {var iconOptions = this.options.icon && this.options.icon.options;var iconAnchor = iconOptions && this.options.icon.options.iconAnchor;if (iconAnchor) {iconAnchor = (iconAnchor[0] + 'px ' + iconAnchor[1] + 'px');}this.options.rotationOrigin = this.options.rotationOrigin || iconAnchor || 'center center' ;this.options.rotationAngle = this.options.rotationAngle || 0;// Ensure marker keeps rotated during draggingthis.on('drag', function(e) { e.target._applyRotation(); });});L.Marker.include({_initIcon: function() {proto_initIcon.call(this);},_setPos: function (pos) {proto_setPos.call(this, pos);this._applyRotation();},_applyRotation: function () {if(this.options.rotationAngle) {this._icon.style[L.DomUtil.TRANSFORM+'Origin'] = this.options.rotationOrigin;if(oldIE) {// for IE 9, use the 2D rotationthis._icon.style[L.DomUtil.TRANSFORM] = 'rotate(' + this.options.rotationAngle + 'deg)';} else {// for modern browsers, prefer the 3D accelerated versionthis._icon.style[L.DomUtil.TRANSFORM] += ' rotateZ(' + this.options.rotationAngle + 'deg)';}}},setRotationAngle: function(angle) {this.options.rotationAngle = angle;this.update();return this;},setRotationOrigin: function(origin) {this.options.rotationOrigin = origin;this.update();return this;}});})();var map = L.map('mapid', {center: [38.8631169, 2.3708919],zoom: 5,crs: L.CRS.EPSG3857,layers: [L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'})]});var _opts = {icon: null,enableRotation:true //允许小车旋转};//移动到当前点的索引this.i = 0;var latlngs = [[45.51, 2.3708919],[37.77, 8.54235],[34.04, 9.52532],[36.04, 10.52532],[40.04, 14.52532],[47.04, 15.52532]];var _path = latlngs;var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map);var myIcon = L.icon({iconUrl: 'car.png',iconSize: [24, 24]});function start(){var me = this,len = me._path.length;//不是第一次点击开始,并且小车还没到达终点if (me.i && me.i < len - 1) {//没按pause再按start不做处理if (!me._fromPause) {return;}else if(!me._fromStop){//按了pause按钮,并且再按start,直接移动到下一点//并且此过程中,没有按stop按钮//防止先stop,再pause,然后连续不停的start的异常me._moveNext(++me.i);}}else {//第一次点击开始,或者点了stop之后点开始me._addMarker();me._moveNext(me.i);}//重置状态this._fromPause = false;this._fromStop = false;}function _addMarker(callback) {if (this._marker) {this.stop();this._marker.remove();}var marker =new L.Marker(_path[0],{icon: myIcon }).addTo(map)this._marker = marker;}/*** 移动到下一个点*/function _moveNext(index) {var me = this;if (index < this._path.length - 1) {this._move(me._path[index], me._path[index + 1], me._tween);}}/*** 移动小车* @param {Number} poi 当前的步长.* @param {Point} initPos 经纬度坐标初始点.* @param {Point} targetPos 经纬度坐标目标点.* @param {Function} effect 缓动效果,实现插值* @return 无返回值.*/function _move(initPos,targetPos,effect) {var me = this,//当前的帧数currentCount = 0,//步长timer = 10, //10毫秒为一步step = 0.1,//总步数count = Math.round(me._getDistance(initPos[0], initPos[1],targetPos[0],targetPos[1]) / step);//如果小于1直接移动到下一点if (count < 1) {this._moveNext(++me.i);return;}//两点之间匀速移动var angle;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(initPos[0], targetPos[0], currentCount, count),y = effect(initPos[1], targetPos[1], currentCount, count);var pos =L.latLng(x,y);//设置markerif(currentCount == 1){if(me._opts.enableRotation == true){//initPos=[lat,lng],leaflet中坐标对的格式为(纬度,经度),因此要计算角度的话,X对应经度,即initPos[1]angle = me._getAngle(initPos[1], initPos[0],targetPos[1],targetPos[0]);}}//正在移动me._marker.remove();//先删除me._marker.setRotationAngle(angle);me._marker._latlng = pos;//设置图标位置me._marker.addTo(map);}},timer);}/*** 缓动效果* 初始坐标,目标坐标,当前的步长,总的步长* @private*/function _tween(initPos, targetPos, currentCount, count) {var b = initPos, c = targetPos - initPos, t = currentCount,d = count;return c * t / d + b;}/*** 计算两点间的距离*/function _getDistance(pxA,pyA, pxB,pyB) {return Math.sqrt(Math.pow(pxA - pxB, 2) + Math.pow(pyA - pyB, 2));}/*** 计算角度* @param startx* @param starty* @param endx* @param endy* @returns {number}*/function _getAngle(startx, starty, endx, endy) {var tan = 0if (endx == startx) {tan = 90;} else {tan = Math.atan(Math.abs((endy - starty) / (endx - startx))) * 180 / Math.PI;console.log(tan);}if (endx >= startx && endy >= starty)//第一象限{return -tan;} else if (endx > startx && endy < starty)//第四象限{return tan;} else if (endx < startx && endy > starty)//第二象限{return tan - 180;} else {return 180 - tan;  //第三象限}}/*** 停止*/function stop() {this.i = 0;this._fromStop = true;clearInterval(this._intervalFlag);}/*** 暂停*/function pause() {clearInterval(this._intervalFlag);//标识是否是按过pause按钮this._fromPause = true;}</script>
</body>
</html>

文件下载地址:https://download.csdn.net/download/wml00000/10769999

基于Leaflet实现路径轨迹回放功能相关推荐

  1. android 基于高德地图的轨迹回放

    android 基于高德地图的轨迹回放 前段时间公司项目有一个需求,就是需要看到设备上传之后的轨迹路线,并且可以实现回放的整个过程,功能包括路线回放.地图位置插点.回放之后的轨迹标记颜色.回放加速等功 ...

  2. cesium 根据SampledPositionProperty与timeline实现轨迹回放功能(跟随视角、上帝视角) 详细代码与理解记录

    cesium 根据SampledPositionProperty与timeline实现轨迹回放功能(跟随视角.上帝视角) 详细代码与理解,文末附完整代码 最终类似效果展示 大致原理摘要 引用出处 这个 ...

  3. 高德地图轨迹回放功能

    一.介绍        在项目过程中,需要对自己设备产品输出的定位信息进行验证.通过路跑测试获取到了一组经纬度数据.这时需要验证这组数据是否是实际路跑测试的轨迹,就用到了高德地图的轨迹回放功能.下面将 ...

  4. js室内地图开发_如何使用JS来开发室内三维地图的轨迹回放功能

    在制作完成室内三维地图的功能后,最经常有的需求就是如何做人员的轨迹回放,一般流程都是从数据库中查询轨迹坐标后,经过后台查询接口返回给前端,接下来的事情都交给JS来完成. 如果想做好一个性能好的轨迹回放 ...

  5. uni-app map路线轨迹回放功能及turf.js实现缓冲区渲染(微信小程序)

    使用uni-app中 map组件实现路线轨迹回放功能. 1.通过接口获取返回的轨迹点. 2.地图的坐标系与轨迹点的坐标系要保持一致,否则轨迹有偏差.点经纬度转换,wgs84togcj02 =>j ...

  6. MotoSimEG-VRC软件:机器人工作路径轨迹跟踪功能使用方法

    目录 功能介绍 机器人系统创建 工作轨迹参数配置 显示工作轨迹功能的机器人控制指令 机器人仿真运行 工作轨迹模型清除与保存 本文已经首发在个人微信公众号:工业机器人仿真与编程(微信号:IndRobSi ...

  7. 高德地图单点、多点标记,轨迹绘制,自定义标记覆盖物,给标记添加点击事件,移除所有标记和轨迹,轨迹回放功能

    文档地址 https://lbs.amap.com/api/javascript-api/guide/abc/prepare 注册 到官网注册一下就可以了https://lbs.amap.com/并创 ...

  8. 基于Leaflet的轨迹模拟回放

    在gis场景中,轨迹回放是一个很常见的场景.比如在导航软件中,在行程结束后根据运动轨迹生成运动图,在keep软件中,会自动记录用户的锻炼轨迹,在结束后可以看到自己的运动轨迹等等.这些需求都是设备在运行 ...

  9. 百度路书实现车辆轨迹动态回放功能-javascrpt版

    基于百度路书js实现车辆轨迹回放功能:接到一个新需求,实现车辆历史轨迹回放功能,之前没有做过,根据网上各种文章走了一些坑,基本上都是半成品,最后还是看百度地图原生api完成开发,现在把最终结果分享给大 ...

最新文章

  1. OpenCV+python:分水岭算法
  2. QuartzCore框架-- iOS中的动画
  3. hihocoder 1638:多级并查集
  4. 文件的文本打开方式和二进制打开方式的区别
  5. oracle 02085,OracleDBLink创建和维护以及ORA-02085解决办法
  6. Java Hashtable equals()方法与示例
  7. C语言显示相位的程序,【图片】求助大佬用c语言帮忙编写下程序【c程序吧】_百度贴吧...
  8. 将jpg文件当作php文件来解析,解析漏洞
  9. HAProxy.md
  10. 图片怎么批量转换格式?
  11. 为什么说人间值得,因为有这么多美好让我们留恋。金秋十月初九于指南山村 。...
  12. Excel技能树系列05:TEXT函数,IF函数和INDEX+MATCH组合查找函数
  13. 火车采集器采集内容页分页教程
  14. 项目开发中之如何对接
  15. 钉钉与wcp集成通知【原创】
  16. php能做动画吗,使用 PHP 快速生成 Flash 动画
  17. 猴子?狒狒?傻傻分不清楚——制作tfrecord数据集并利用卷积神经网络训练实例
  18. Python数据分析与可视化——NumPy数组
  19. 小谈应该如何对抗网络小说
  20. 计算机超频的方法,原来电脑超频如此简单,小白也能轻松搞定

热门文章

  1. 大白话解析模拟退火算法、遗传算法入门
  2. matlab安装配置VLFeat库
  3. 利用github-pages建立个人博客
  4. 《大话数据结构》第9章 排序 9.2 排序的基本概念与分类
  5. for、while循环及其变体
  6. javascript系列-class10.DOM(下)
  7. 最近的状态很不好,需要调整
  8. 满纸荒唐言,一把辛酸泪--红楼一梦
  9. Storm之Bolt-接口
  10. Heartbeat+ipvsadm+ldirectord组建linux高可用集群