修罗

百度地图路书轨迹播放(js)
1,业务介绍:后端返回由gps提供的一组小车经纬度数据[{"x":113.739448,&qu...
扫描右侧二维码阅读全文
18
2023/03

百度地图路书轨迹播放(js)

1,业务介绍:

后端返回由gps提供的一组小车经纬度数据[{"x":113.739448,"y":23.024184,"sp":1,"ag":0,"tm":1678936916}...],将这组数据显示到百度地图中,并且能够回放小车轨迹,也能通过拖拽进度条的方式查看某个时间小车的位置。返回的数据有点飘需要通过百度地图接口纠偏。

GIF1.gif

2,在vue2环境中执行

index.html页面引入百度地图cdn,ak需要在百度地图api申请

<script src="//api.map.baidu.com/api?v=3.0&ak=******"></script>

3, 引入百度地图lushu库

在单页面vue中引入即可
lushu.js

import "./lushu.js";

4,代码执行流程

  • mounted

image-20230318162806265.png

  • __initMap

this.__initTrack()注释,只初始化了地图,没处理轨迹数据;本案例数据都是模拟的(写死的),正式使用时需要从百度拿到纠偏后的数据,将数据赋值给this.trackBaiRes,之后再执行this.__initTrack()

image-20230318162907107.png

5,代码:

<template>
  <div class="view-trajectory">
    <!-- 地图 -->
    <div id="allmap"></div>
    <!-- 进度条容器 -->
    <div class="range-container">
        <!-- 进度条鼠标悬浮面板 -->
        <div class="tooltip" ref="tooltipRef"></div>
        <!-- 进度条 -->
        <input type="range" class="range" value="1"  ref="rangeRef"/>
        <div class="control-panel">
          <div class="control-button" @click="speedChange">加速</div>
          <div class="control-button" @click="playChange">{{isPlay?'暂停':'播放'}}</div>
          <div class="control-button" @click="reset">重置</div>
        </div>
    </div>
  </div>

</template>

<script>
import car from "./car.png";
import "./lushu.js";
export default {
  data(){
      return {
        // 请求百度返回纠偏后的数据
        trackBaiRes: {"status":0,"message":"成功","total":39,"distance":4108.0859917828,"toll_distance":0,"low_speed_distance":0,"points":[{"loc_time":1679014441,"latitude":23.030706525334,"longitude":113.7450487838,"speed":8.4968909955548,"direction":289},{"loc_time":1679014721,"latitude":23.032945497212,"longitude":113.74533852002,"speed":14.222299521862,"direction":318.41737329693},{"loc_time":1679014737,"latitude":23.033326638549,"longitude":113.74497102672,"speed":9.614471401481,"direction":327.02413618549},{"loc_time":1679014737,"latitude":23.033914979258,"longitude":113.74455587803,"speed":9.614471401481,"direction":317.99855141367},{"loc_time":1679014795,"latitude":23.034436212997,"longitude":113.74395731432,"speed":14.572723147873,"direction":10.760557699982},{"loc_time":1679014795,"latitude":23.034775425544,"longitude":113.74402736581,"speed":14.572723147873,"direction":13.361222491928},{"loc_time":1679014809,"latitude":23.035036952553,"longitude":113.74411728753,"speed":6.6629134155498,"direction":32.677752622545},{"loc_time":1679014876,"latitude":23.037025042662,"longitude":113.74533203158,"speed":22.608593150423,"direction":33.22208363622},{"loc_time":1679014876,"latitude":23.037733082839,"longitude":113.74589286953,"speed":22.608593150423,"direction":24.776227282764},{"loc_time":1679014919,"latitude":23.040370075181,"longitude":113.74708762303,"speed":20.719854751648,"direction":26.114492063654},{"loc_time":1679014985,"latitude":23.041187072999,"longitude":113.74754103564,"speed":11.697512550476,"direction":77.510620986221},{"loc_time":1679014985,"latitude":23.041239660484,"longitude":113.74784815615,"speed":11.697512550476,"direction":131.92597686604},{"loc_time":1679015005,"latitude":23.040969396432,"longitude":113.74817291415,"speed":13.182249962354,"direction":108.65775667928},{"loc_time":1679015021,"latitude":23.040789740542,"longitude":113.74875103172,"speed":25.968065215871,"direction":104.6808437},{"loc_time":1679015021,"latitude":23.039816287172,"longitude":113.75261075747,"speed":25.968065215871,"direction":102.70912429562},{"loc_time":1679015100,"latitude":23.039466981611,"longitude":113.75437040027,"speed":9.9012387623271,"direction":155.10979131128},{"loc_time":1679015121,"latitude":23.039186814557,"longitude":113.7545497483,"speed":21.518346770263,"direction":200.65254051739},{"loc_time":1679015132,"latitude":23.038601052728,"longitude":113.75429773189,"speed":15.045603596532,"direction":284.90141564478},{"loc_time":1679015169,"latitude":23.038920910564,"longitude":113.7528473307,"speed":1.8324417001755,"direction":275.02089731568},{"loc_time":1679015353,"latitude":23.038601052728,"longitude":113.75429773189,"speed":7.3929870660701,"direction":201.90659043246},{"loc_time":1679015527,"latitude":23.03526706325,"longitude":113.75282905339,"speed":11.34289636073,"direction":282.51762386788},{"loc_time":1679015564,"latitude":23.035641631198,"longitude":113.75187471494,"speed":10.62146107396,"direction":272.98722779664},{"loc_time":1679015594,"latitude":23.035475971912,"longitude":113.75005337607,"speed":5.0932289656843,"direction":259.02147991595},{"loc_time":1679015702,"latitude":23.035075133868,"longitude":113.74802088068,"speed":11.121200377629,"direction":237.3656767591},{"loc_time":1679015702,"latitude":23.03502281567,"longitude":113.74793210215,"speed":11.121200377629,"direction":189.23626441093},{"loc_time":1679015725,"latitude":23.034700774954,"longitude":113.74793282568,"speed":12.023503652411,"direction":253.7465476813},{"loc_time":1679015751,"latitude":23.034611288965,"longitude":113.74683909907,"speed":20.570797223868,"direction":222.12001358334},{"loc_time":1679015762,"latitude":23.034032394446,"longitude":113.74633420177,"speed":15.898425080893,"direction":254.11022222329},{"loc_time":1679015772,"latitude":23.034021792616,"longitude":113.74584973813,"speed":13.679585177488,"direction":296.34089849557},{"loc_time":1679015785,"latitude":23.034206714634,"longitude":113.74559072655,"speed":8.3198367907996,"direction":249.00772689973},{"loc_time":1679015809,"latitude":23.034073794946,"longitude":113.74522181542,"speed":17.284834935021,"direction":233.75664175864},{"loc_time":1679015820,"latitude":23.033807376024,"longitude":113.74482689228,"speed":13.658296456243,"direction":145.0405870888},{"loc_time":1679015820,"latitude":23.033076730568,"longitude":113.74541437747,"speed":13.658296456243,"direction":213.31645504385},{"loc_time":1679015849,"latitude":23.032898434933,"longitude":113.74527269731,"speed":24.419083366493,"direction":187.17268759104},{"loc_time":1679015860,"latitude":23.031881482232,"longitude":113.74516027902,"speed":3.430964627367,"direction":90.836089589905},{"loc_time":1679016061,"latitude":23.031870433104,"longitude":113.74565765468,"speed":2.8277478067006,"direction":91.50452759305},{"loc_time":1679017941,"latitude":23.031637132129,"longitude":113.74581791179,"speed":4.7226,"direction":353},{"loc_time":1679018586,"latitude":23.031556511118,"longitude":113.74624854648,"speed":2.6314273372147,"direction":7.1881577730348},{"loc_time":1679018643,"latitude":23.031928190973,"longitude":113.74629925732,"speed":2.6314273372147,"direction":187.11829890952}]},
        latLngArray:[],
        // 地图实例
        map: null,
        // Point集合,由经纬度集合转化,用来绘制地图轨迹,路书动画
        pois: [],
        // 路书实例
            lushu: null,
        // 动画速度
        speed: 100,
        // 是否正在播放动画
        isPlay: true,
        // 当前动画经过的经纬度索引
        currentPos: 1,

      }
  },
  mounted(){
    this.__initMap()
    this.__initListener()
  },
  beforeDestroy(){
    let range = this.$refs.rangeRef
    range.removeEventListener('mousemove', this.onmousemove)
    range.removeEventListener('mouseleave', this.onmouseleave)
    range.removeEventListener('change', this.onchange)
  },
  methods: {
    __initMap(){
      let carCenterPoint = new BMap.Point(113.74533852002, 23.032945497212);
      // 地图实例初始化
      this.mapInit('allmap', carCenterPoint, window)

      /// 接下来,请求接口数据,将数据发送给百度纠偏,之后将百度返回的数据赋值给this.trackBaiRes,然后调用this.__initTrack();
      this.__initTrack();
      ///
    },
    __initTrack(){
      this.latLngArray = this.trackBaiRes.points.map(e => {
        return e.longitude +','+ e.latitude
      })
      // 开始点牌子标记
      let carCenterPoint = new BMap.Point((this.latLngArray[0].split(','))[0], (this.latLngArray[0].split(','))[1]);
      this.showStartTag(BMap, this.map, carCenterPoint, "这是一段车辆轨迹")
      // 创建polyline对象
      this.pois = this.transToPois(BMap, this.latLngArray, this.map);
      this.showTrack(BMap, this.pois, this.map, window)
      this.lushu = this.lushuInit(BMapLib, this.map, this.pois, "");
      this.lushu.start();
    },
    __initListener(){
      let range = this.$refs.rangeRef
      range.addEventListener('mousemove', this.onmousemove)
      range.addEventListener('mouseleave', this.onmouseleave)
      range.addEventListener('change', this.onchange)
    },
    mapInit(mapId, carCenterPoint, window){
        let map = new BMap.Map(mapId, { minZoom: 9, maxZoom: 19 });
        // 添加比例尺控件
        map.addControl(new BMap.ScaleControl({ anchor: window.BMAP_ANCHOR_TOP_LEFT }));
        // 启用滚轮放大缩小
        map.enableScrollWheelZoom();
        // 地图显示中心位置
        map.centerAndZoom(carCenterPoint, 17);
        this.map = map;
    },
    // 开始点牌子标记
    showStartTag(BMap,map, Point, text){
        let carOpts = {
            position: Point,    // 指定文本标注所在的地理位置
            offset: new BMap.Size(15, -20)    //设置文本偏移量
        }
        let carlabel = new BMap.Label(text, carOpts);  // 创建文本标注对象
        carlabel.setStyle({
            color: "green",
            fontSize: "12px",
            padding:"2px 5px",
            fontFamily: "微软雅黑",
            borderColor:"blue"
        });
        map.addOverlay(carlabel);
    },
    transToPois(BMap, latLngArray, map){
        let pois = []
        for(let i = 0; i < latLngArray.length ; i++) {
            let latLng = latLngArray[i];
            let pointArray = latLng.split(",");
            pois.push(new BMap.Point(pointArray[0], pointArray[1]));
            // 创建标注
            this.setUpMark(BMap, new BMap.Point(pointArray[0],pointArray[1]),map)
        }
        return pois;
    },
    // 创建标注
    setUpMark(BMap, Point, map){
        let marker = new BMap.Marker(Point);
        map.addOverlay(marker);
    },
    // 轨迹显示
    showTrack(BMap, pois, map,window){
        // 轨迹显示样式
        let sy = new BMap.Symbol(window.BMap_Symbol_SHAPE_BACKWARD_OPEN_ARROW, {
            scale: 0.6,//图标缩放大小
            strokeColor: '#fff',//设置矢量图标的线填充颜色
            strokeWeight: '2',//设置线宽
        });
        let icons = new BMap.IconSequence(sy, '10', '30');
        let polyline = new BMap.Polyline(pois, {
            enableEditing: false,//是否启用线编辑,默认为false
            enableClicking: true,//是否响应点击事件,默认为true
            icons: [icons],
            strokeWeight: '8',//折线的宽度,以像素为单位
            strokeOpacity: 0.8,//折线的透明度,取值范围0 - 1
            strokeColor: "blue" //折线颜色
        });
        map.addOverlay(polyline);
    },
    lushuInit(BMapLib, map, pois, trackContent ){
        // 车辆图标
        let icon_gps_car_run = new BMap.Icon(car, new BMap.Size(32,32),{anchor: new BMap.Size(18, 18)});
        // map.setViewport(pois); // 轨迹显示中心位置
        let lushu = new BMapLib.LuShu(map, pois, {
            defaultContent: trackContent,
            autoView:false,//是否开启自动视野调整,如果开启那么路书在运动过程中会根据视野自动调整
            icon: icon_gps_car_run,
            speed: this.speed,
            enableRotation:true,//是否设置marker随着道路的走向进行旋转
            // 加一个,不加源码报错
            landmarkPois: [
                   {lng:116.314782,lat:39.913508,html:'加油站',pauseTime:2}
          ]
        });
        return lushu
    },
    // 加速
    speedChange() {
        this.lushu._opts.speed = 500
    },
    //// 进度条相关操作
    // 拉进度条
    tempChange() {
      if(this.latLngArray.length < 1) return
      if(!this.currentPos) this.currentPos = 1
      console.log(this.currentPos);
      this.lushu.i = this.currentPos
      if (this.currentPos >= this.latLngArray.length - 2) {
          this.isPlay = false
      }
    },
    // 开始&暂停
    playChange() {
        if (this.isPlay) {
          this.lushu.pause();
          this.isPlay = false
        } else {
          //alert(1)
          this.lushu.start();
          this.isPlay = true
        }
    },
    // 重置轨迹
    reset() {
        this.currentPos = 1
        this.lushu._opts.speed = this.speed
        this.isPlay = false
        this.lushu.stop()
    },
    onmousemove(e){
      if(this.latLngArray.length < 1) return
      let tooltip = this.$refs.tooltipRef
      // 时间提示框显示
      tooltip.style.display = "block";
      tooltip.style.left = e.offsetX + 'px';
      let loc_time = this.trackBaiRes.points[Math.floor(e.offsetX / 1000 * this.latLngArray.length)].loc_time;
      let loc_timeDate = new Date(loc_time * 1000);
      let loc_timeMinutes = loc_timeDate.getMinutes()>10?loc_timeDate.getMinutes():"0"+loc_timeDate.getMinutes();
      let format = (loc_timeDate.getMonth()+1) + '-' + loc_timeDate.getDate() + ' ' + loc_timeDate.getHours() + ':' + loc_timeMinutes
      tooltip.innerText = format;
    },
    onmouseleave(e){
      if(this.latLngArray.length < 1) return
      let tooltip = this.$refs.tooltipRef
      // 时间提示框隐藏
      tooltip.style.display = "none"
    },
    onchange(e){
      if(this.latLngArray.length < 1) return
      let targetPoint = Math.round(e.target.value / 100 * this.latLngArray.length)
      if(targetPoint > this.latLngArray.length-2) targetPoint = targetPoint -3
      // 在播放先暂停
      if(this.isPlay) this.playChange()
      this.currentPos = targetPoint
      setTimeout(() => {
          this.tempChange()
          this.playChange()
      }, 20);

    }
    ////

  }

}
</script>

<style lang="scss" scoped>
@mixin wh(){
  width: 100%;height: calc(100vh - 84px);
}
.view-trajectory{
  @include wh();
  #allmap{
    @include wh();
    position: absolute;overflow: hidden;
  }
  .range-container{
    position: fixed;right: 40%;transform:translateX(50%);bottom:50px;
    .tooltip{
      min-width:80px;position: absolute; top: -20px; background-color: rgb(255, 255, 255); padding: 1px 6px; font-size: 15px; color: rgb(108, 150, 247); border-radius: 3px;display: none;
    }
    .range{width: 1000px;height:50px;cursor: pointer;}
    .control-panel{
      display: flex; justify-content: center;
      .control-button{
        padding: 5px 13px;margin-right: 5px; border-radius: 6px; font-size: 13px; color: #fff; background: #1890ff; cursor: pointer;
      }
    }
  }
}

</style>
  • 小车图片资源

car.png

Last modification:July 8th, 2023 at 11:06 am

Leave a Comment