概述

历史轨迹回放是GIS很常见的一个功能,本文结合turf.js实现轨迹的展示与播放动画。

效果

实现功能

  • 轨迹的展示;
  • 轨迹的方向的箭头展示;
  • 随着轨迹播放的小车,并调整方向与轨迹方向一致;
  • 已播放路径的展示;
  • 多条轨迹线的同时播放展示;

实现

const icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAWCAMAAAC13D+jAAADAFBMVEWs1eL/0T7+zTv+lwD81FfXqSZNNA/84nXSixXJt5kjS2z/uCn8rBVxz+yn09/mtymmvMavxrX9sxn/zTLnxmrJ9v/+uzNarMOHqsb1vGb9ynuDwdK7ycn7t0r85WpMpLuHrLn/4kDFmiRUaYL9xDT/0THlgAH01XH9rSz/1ULHqWP723N3ucv+2D/7wWeyoVTbs1S02uWP1OzIp1OidDBNjKe46vyYtKjit2n/zSzmmzncvWlzTAf/3UFrtMgwg6+4rJb+ogGtkVr/swiSxtr/5j76xG7VsVOQrKxXXFnx0Wimwuola5T84Fztx5fglxw5PDPftVBXu9r9v0f/rgmWn5a3l1adbhP/0Tmftcbltljqu4WDdl3w6eGs5fmepJj2qSupiD2wvLN7pbXTtF//98f4pC321m+rwsT63Wv9+vZXam/Cq4zFsIz/2zVxe3X+xC1rwtqgdhvomjDtwXr/qwL/0mS/pGH31GPtvHn/0y3m07vByZXUqVf/0y+smGv/80X900r/1D293OY1JgrnqVnx49LM5Ov5uFT/0Cr0oi/69vP9/PpkWCxrmbr/1znz1XjTrk7YtVt1udPdul+64u6bn5D/5i4aJSj/z3i4hSfm/v/322ry///vnir/0CzbjSTVrWSw2d328ej933r2v2j/1C//0C/kvjC/kkGukkCBmJeu2OK+spbZ6vDT/f+hutbCfgrz3HXxrTPFlkvtkATzhwDnp03RzLvvs0d3kZ6SsKj/yh6MsrmRqbD/2Y7zqSL/5n3/ryb/1CvlwmOOu8D5wlpoodNqvtz/+VCoiE1ZveCgilVovfO/j0SZj3KEm7VRscpWXmjOq1JNZFzv0njxxST3zSj/wCT/zSLekzDPy8T/yWv+4E56gXSjo5KrsJW4qI6jz9/swpDxu275zJf33LiWwszqy6Hx06zz0nD/pwr/7UsKDhADHDHrw00+FQD9yDcROFiXbSrtz2ysjizmsWuzkiW7lzRghaZkkKRgZ1dwm7322Wdgi4X///+RNRZLAAABAHRSTlP///8AU/cHJQAAAAlwSFlzAAAOwwAADsMBx2+oZAAAAB1pVFh0U29mdHdhcmUAAAAAAEFkb2JlIEltYWdlUmVhZHkGrQKXAAADD2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS41LWMwMTQgNzkuMTUxNDgxLCAyMDEzLzAzLzEzLTEyOjA5OjE1ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo2NUZGMDA3MTYwREExMUVDOURGOEIxQTMwNjhFRTA1OCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2NUZGMDA3MDYwREExMUVDOURGOEIxQTMwNjhFRTA1OCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgV2luZG93cyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSIxREI5NjEzNURBODA0MkYzMzk5NDA4NzZFN0YzQkM2RCIgc3RSZWY6ZG9jdW1lbnRJRD0iMURCOTYxMzVEQTgwNDJGMzM5OTQwODc2RTdGM0JDNkQiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6ffRDqAAADEklEQVQ4jWP4jx/clstCF2L4/z/rxZMSKT09PckylqV6ICB5Z2bwsaVA4CZ5J4r//ZOZM0sqS0AgunoxWEvb1lLn0ln15eXlNqe0gGS5lkWijdZCIKi1eFI7q4Vt68aNN4SEhHh4XjtKRb8Eaune+nrlOZ5ZvxQUFGZkH00GAQHPtwICkZGRGySUL3l63vP4M4PflgkIPnKLpbY++89Q+dpfouYai/vEie4ik4DEJPdJKSnWl42NjbVYe3fJNMeZma3nCnf9+PEjE5Omqm6jWhZDcciWDMX+L1fVweCV9hLtgweXpKunp6dP6NdfP3cqHwOfqLJNAyMj00cVlY8qeY5+DPNe18uoRqgergKDZVWdVZadnctA7MPTE71nr+FjYBD9yebaxMioqanJVMCy8xtDF3PoGuEIRiwgwvXrhtmGDHx8ZhIBEboQsWWbcrYzpG3dx4ddC6Pr98i57e3NDFNdAvhtIUKqc3KsgFoUFglHaGpi06JkGufyaF3z1EcB/IpwLcVALRKLhJtUVLDoUVTaFScur/PIkCGAFablb84CiJZ+MTEsWlyVfom2M9jZXbwI17I8MxekZS/QYbrYHfaTV8fQkGGNHdxhQC23QN5fY4nD+0p9RnZ20jouCO/PZ+e0AgUyzhD7YW8kLS8uftEeFsjCe5YAtcxzPP9cNaJuWR0SmF9VNX9+Z+f0VfZGk4FaTvuwKTZFRAhbMv31lYtqZZgXErY3r9/rixcS0E5P1wYCW/2zhXbi4uK8XDYNTI2NLOxy7L6KwATzrdT/eM31iqjAwECvI+4GIDBRZMKkKVOmWPP3/tE5EXQ6iPdT0UldX7m7cnerbjZu62ZYzPz6jBOP0mpzc/OAfMHdICD4u0UwCQgyLijnZ1/5Z2r/bsUbzSbVjwU3hFJlHwOzWDVzqbOQyer4+GlsMQ+mAcH9tTFsD9c6AAFnrtPnD2wcReEF3Nzchw5p8Ox/Gg3OyLGVO2VlNTQ00sTEEjRAIIE7+MCBBDBQ2azvLsZU1tHhBgJLH7dB8j4C9GCydsgtRi8uAEXmog5wB7NZAAAAAElFTkSuQmCC'
const arrow = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAnElEQVQ4T63TsQ0CMQyF4f/NgMQQ0CBR0FIx190cFIiWhhFoKdgEiRUeSoF0gO8cjkub+Evs2OLPpc9422dgBRwlNZn/BtjeApdOUJsh0QuuwKYWiYAFcAKWHaSR1EbpfAHlkO0ICdMJgV+QXmAAmUu6v9IZA8wkPVKgtg7TF7H25t4UbN+A9ahGmqqVD8AO2GdzUF45+I3ZJJb9JxbwRhEhB66xAAAAAElFTkSuQmCC'class AnimationRoute {constructor(map, json, play = true) {this._map = mapthis._json = jsonthis._play = playthis.init()}init() {const that = thisthat._index = 0that._count = 1500that._step = turf.length(that._json) / that._countthat._flag = 0that._playId = 'play-' + Date.now()// 添加路径图层that._map.addSource(that._playId, {type: 'geojson',data: that._json})that._map.addLayer({id: that._playId,type: 'line',source: that._playId,'layout': {'line-cap': 'round','line-join': 'round'},'paint': {'line-color': '#aaaaaa','line-width': 10}})// 添加已播放路径that._map.addSource(that._playId + '-played', {type: 'geojson',data: that._json})that._map.addLayer({id: that._playId + '-played',type: 'line',source: that._playId + '-played','layout': {'line-cap': 'round','line-join': 'round'},'paint': {'line-color': '#09801a','line-width': 10}})// 添加路径上的箭头that._map.loadImage(arrow, function(error, image) {if (error) throw errorthat._map.addImage(that._playId + '-arrow', image)that._map.addLayer({'id': that._playId + '-arrow','source': that._playId,'type': 'symbol','layout': {'symbol-placement': 'line','symbol-spacing': 50,'icon-image': that._playId + '-arrow','icon-size': 0.6,'icon-allow-overlap': true}})})// 添加动态图标that._map.loadImage(icon, function(error, image) {if (error) throw errorthat._map.addImage(that._playId + '-icon', image)that._map.addSource(that._playId + '-point', {'type': 'geojson','data': that._getDataByCoords()})that._map.addLayer({'id': that._playId + '-point','source': that._playId + '-point','type': 'symbol','layout': {'icon-image': that._playId + '-icon','icon-size': 0.75,'icon-allow-overlap': true,'icon-rotation-alignment': 'map','icon-pitch-alignment': 'map','icon-rotate': 50}})that._animatePath()})}_animatePath() {if(this._index > this._count) {window.cancelAnimationFrame(this._flag)} else {const coords = turf.along(this._json, this._step * this._index).geometry.coordinates// 已播放的线const start = turf.along(this._json, 0).geometry.coordinatesthis._map.getSource(this._playId + '-played').setData(turf.lineSlice(start, coords, this._json))// 车的图标位置this._map.getSource(this._playId + '-point').setData(this._getDataByCoords(coords))// 计算旋转角度const nextIndex = this._index === this._count ? this._count - 1 : this._index + 1const coordsNext = turf.along(this._json, this._step * nextIndex).geometry.coordinateslet angle = turf.bearing(turf.point(coords),turf.point(coordsNext)) - 90if(this._index === this._count) angle += 180this._map.setLayoutProperty(this._playId + '-point', 'icon-rotate', angle)this._index++if(this._play) this._flag = requestAnimationFrame(() => {this._animatePath()})}}_getDataByCoords(coords) {if(!coords || coords.length !== 2) return nullreturn turf.point(coords, {'label': this._formatDistance(this._step * this._index)})}_formatDistance(dis) {if(dis < 1) {dis = dis * 1000return dis.toFixed(0) + '米'} else {return dis.toFixed(2) + '千米'}}destory() {window.cancelAnimationFrame(this._flag)if(this._map.getSource(this._playId + '-point')) {this._map.removeLayer(this._playId + '-point')// this._map.removeLayer(this._playId + '-label')this._map.removeSource(this._playId + '-point')}if(this._map.getSource(this._playId)) {this._map.removeLayer(this._playId)this._map.removeSource(this._playId)}}
}

测试调用代码:

const route1 = {'type':'Feature','properties':{},'geometry':{'type':'LineString','coordinates':[[106.669,22.5785],[106.6374,22.5974],[106.6206,22.608],[106.6037,22.5553],[106.5784,22.4858],[106.5595,22.4373],[106.5637,22.3804],[106.5827,22.3298],[106.6543,22.313],[106.6859,22.2561],[106.7006,22.195],[106.688,22.1613],[106.6943,22.0897],[106.6964,22.018],[106.6838,21.9717],[106.7386,21.9864],[106.7554,22.0138],[106.8334,21.9759],[106.9008,21.9738],[106.9261,21.9422],[106.9767,21.9316],[107.0209,21.9485],[107.0609,21.919],[107.0125,21.8705],[107.0104,21.8305],[107.0609,21.8031],[107.1031,21.7862],[107.1473,21.7483],[107.2063,21.7125],[107.2611,21.6935],[107.2927,21.7251]]}}
new AnimationRoute(map, route1)

说明:如果为多个轨迹同时展示,多次调用new AnimationRoute即可。

mapboxGL轨迹展示与播放相关推荐

  1. 轨迹系列13——多轨迹展示在实际项目中的落地和优化

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 在之前的"多车辆实时迹展示方案"(http ...

  2. 轨迹系列8——记某真实项目中轨迹展示查询效率优化方案一(初步设计)

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.    背景 准确说,该项目的迹展示涉及到两个方面,一个是轨迹查询展 ...

  3. 【Qt 开源音视频框架模块QtAV】03:QTAV主要接口展示以及播放器源码分享

    介绍 QtAV 是一个基于 Qt 和 FFmpeg 的跨平台.高性能多媒体播放框架,能够帮助你轻而易举地编写出一个播放器. [Qt 开源音视频框架模块QtAV]01:介绍.编译以及简单使用 因为网上使 ...

  4. 高德地图车头方向,marker方向控制,车辆移动,轨迹展示,轨迹回放

    经常有人问怎么控制车辆车头方向随着行进方向改变, 怎么展示车辆运行轨迹 在高德地图中展示车辆轨迹有三种方法,一种方法是AMapUI的PathSimplifier创建巡航器来展示轨迹: 高德地图轨迹展示 ...

  5. vue 高德地图搜索功能_VUE中使用高德地图做轨迹添加功能,帮助轨迹展示

    准备工作 使用前准备 : 高德地图key 使用插件: vue-amap 1.npm安装vue-amap npm install vue-amap --save import AMap from 'vu ...

  6. 基于Cesium的卫星及空间碎片的轨迹展示

    核心:cesium.czml.satellite.js.tle 下面简单介绍一下操作步骤,并展示部分代码(附上结果截图) 步骤一:初始化cesium const viewer = new Viewer ...

  7. 高德地图轨迹展示样式修改

    自定义轨迹的icon,应该用import 先引入图片,再使用,否则加载不出来 import carUrl from '../../assets/img/car.png' var map = new A ...

  8. 结合SSE实现实时位置展示与轨迹展示

    概述 实时位置与实时轨迹的展示是webgis中非常常见的一个功能,本文结合SSE来实现实现此功能. SSE简介 SSE是Sever-Sent Event的首字母缩写,它是基于HTTP协议的,在服务器和 ...

  9. 基于WebGl的火车运行轨迹展示

    作者:Volare 前言 随着目前可视化的发展,人们越来越愿意在三维的场景下浏览,因为这样不仅看的更加的清楚,也是更加的直观,在本片博客中,小编以从武汉疫情爆发前驶出的火车来为大家展示出火车轨迹. ( ...

最新文章

  1. (volatile int)(x)与*(volatile int *)(x)
  2. Solaris 9安装VNC
  3. 直接学python行不行_是否可以直接学python或者java而不学c++?
  4. 九、多表模型创建,一对一,一对多,基于对像的多表模型等
  5. 前端 CSS Framework --- NEC (网易)
  6. 【飞控理论】【惯性导航基础】二维平面的旋转如何用代数表示?三维平面的旋转如何用代数表示?什么是四元数?四元数、欧拉角、方向余弦之间有什么关系?
  7. H5类似易企秀/编辑器/页面制作/开发/生成工具/软件/源码/授权
  8. 大数据杀熟,是真的吗?
  9. HDU1850 Being a Good Boy in Spring Festival
  10. Junit4与junt3并存时产生的问题
  11. 魅族手机便签里的备忘录内容如何导出到华为手机上?
  12. 技嘉主板bios设置方法
  13. hp/博科光纤交换机配置小记
  14. ArcGIS转CAD坐标
  15. arcgis语言如何中文改英文_ArcGIS的概述及中英文切换——附GIS名词解释大全(一)...
  16. 金网奖首度跨界心理学,打造最强案例
  17. xpath之根据节点获取兄弟节点
  18. 基于阿里云LinkWAN实现设备上云(1) LinkWAN平台简析
  19. git 报错fatal: cannot create directory at ‘../../..‘: Permission denied
  20. 【转】流媒体技术笔记(视频编码相关)

热门文章

  1. Armbian魔百盒折腾记4(内网穿透frp、异地组网等)慢更中
  2. 最新电商之推荐系统要诀~
  3. 2021年电工(初级)考试及电工(初级)试题及解析
  4. python互相关函数_计算互相关函数?
  5. 【JavaScript学习记录】快速下载网页所有图片
  6. connection and session
  7. Nature:肺部微生物组调节大脑自身免疫
  8. Python-FCL 学习
  9. SBT30100VDC-ASEMI低压降肖特基二极管SBT30100VDC
  10. dubbo多协议配置