高德地图路径回放(亲妈式教学 90%以上注释)

高德地图路径回放

在这里插入图片描述

创建出高德地图

  • 安装我们的vue-amap依赖
    • 官网https://github.com/ElemeFE/vue-amap里面有详细教学
    • 可视化面板安装(推荐 本人超级喜欢的一种方式)
    • npm install -S vue-amap
  • 在main.js上进行配置
    // 导入AMap
    import AMap from 'vue-amap'
    // 注册
    Vue.use(AMap)
    // 加载
    AMap.initAMapApiLoader({
      // 高德的key
      key: '你可爱的key',
      // 插件集合
      plugin: ['AMapManager', 'AMap.Autocomplete', 'AMap.PlaceSearch', 'AMap.Scale', 'AMap.OverView', 'AMap.ToolBar', 'AMap.MapType', 'AMap.PolyEditor', 'AMap.CircleEditor', 'Geocoder', 'Geolocation', 'AMap.MarkerClusterer', 'AMap.PolyEditor', 'AMap.CircleEditor', 'AMap.MouseTool', 'AMap.Driving', 'AMap.CitySearch', 'AMap.InfoWindow', 'AMap.LngLat', 'AMap.DistrictSearch', 'AMap.TileLayer.Traffic', 'AMap.Heatmap', 'AMap.Autocomplete', 'AMap.PlaceSearch'],
      // 高德 sdk 版本,默认为 1.4.4
      v: '1.4.4'
    })
    
  • 如果出现AMap’ is not defined尝试以下方法解决
    • 在.eslintrc.js进行配置
      globals: {
        AMap: true,
        AMapUI: true,
      },
      
    • 在index.html里进行配置
      <script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=你可爱的key">
      </script>
      <script src="//webapi.amap.com/ui/1.1/main.js?v=1.1.1"></script>
      
  • 设置存放地图的容器(没出地图的设置div大小)
    <!-- 地图 -->
    <div id="container"></div>
    
  • 设置地图
    mounted() {
      // 设置地图基本上配置
      const param = {
        // 是否监控地图容器尺寸变化
        resizeEnable: true,
         // 初始地图级别
        zoom: 15
      }
      this.map = new AMap.Map('container', param)
    },
    

做到这一步地图就可以显示出来了
在这里插入图片描述

创建路线

路线的样式:https://lbs.amap.com/api/amap-ui/reference-amap-ui/mass-data/pathsimplifier/

  • 后台传递来的数据(丢在data或者js导入进来都可以)

    // 后台传递来的路线
    linePath: [
      {
        latitude: 39.997761,
        longitude: 116.478935,
        time: '2020-08-21 16:21:18'
      },
      {
        latitude: 39.997825,
        longitude: 116.478939,
        time: '2020-08-21 16:21:21'
      },
      {
        latitude: 39.998549,
        longitude: 116.478912,
        time: '2020-08-21 16:21:24'
      },
      {
        latitude: 39.998555,
        longitude: 116.478998,
        time: '2020-08-21 16:21:27'
      },
      {
        latitude: 39.99856,
        longitude: 116.479282,
        time: '2020-08-21 16:21:30'
      },
      {
        latitude: 39.998528,
        longitude: 116.479658,
        time: '2020-08-21 16:21:33'
      },
      {
        latitude: 39.998453,
        longitude: 116.480151,
        time: '2020-08-21 16:21:36'
      },
      {
        latitude: 39.998302,
        longitude: 116.480784,
        time: '2020-08-21 16:21:39'
      },
      {
        latitude: 39.998184,
        longitude: 116.481149,
        time: '2020-08-21 16:21:42'
      },
      {
        latitude: 39.997997,
        longitude: 116.481573,
        time: '2020-08-21 16:21:45'
      },
      {
        latitude: 39.997846,
        longitude: 116.481863,
        time: '2020-08-21 16:21:48'
      },
      {
        latitude: 39.997718,
        longitude: 116.482072,
        time: '2020-08-21 16:21:51'
      },
      {
        latitude: 39.997718,
        longitude: 116.482362,
        time: '2020-08-21 16:21:54'
      },
      {
        latitude: 39.998935,
        longitude: 116.483633,
        time: '2020-08-21 16:21:57'
      },
      {
        latitude: 39.998968,
        longitude: 116.48367,
        time: '2020-08-21 16:22:00'
      },
      {
        latitude: 39.999861,
        longitude: 116.484648,
        time: '2020-08-21 16:22:03'
      }
    ]
    
  • 后台传递的json,我们需要给他转换为数组

     // 初始化
     init() {
       // 后台传递来的数据是json的,所以我们改成数组
       // 轨迹
       // 线条路线
       let linePath = this.linePath
       linePath.forEach(item => {
         // 把json转为数组
         this.pathList.push([item.longitude, item.latitude])
       })
       // 设置路线
       this.setPath()
     },
    
  • 设置路线

     // 设置路线
     setPath() {
       let that = this
       AMapUI.load(['ui/misc/PathSimplifier', 'lib/$'], function(
         PathSimplifier
       ) {
         if (!PathSimplifier.supportCanvas) {
           console.log('当前环境不支持 Canvas!')
           return
         }
         function onload() {
           that.pathSimplifierIns.renderLater()
         }
         function onerror() {
           console.log('图片加载失败!')
         }
         // 历史轨迹巡航器
         that.pathSimplifierIns = new PathSimplifier({
           zIndex: 100,
           map: that.map, // 所属的地图实例
           getPath: function(pathData) {
             // 这里的pathData保存的是路线
             return pathData.path
           },
           // 自动设置视图
           autoSetFitView: true,
           // 巡航器样式
           renderOptions: {
             // 路径导航样式
             pathNavigatorStyle: {
               // 一开始小车的旋转角度
               initRotateDegree: 0,
               // 小车的宽
               width: 20,
               // 小车的高
               height: 32,
               // 自动旋转
               autoRotate: true,
               // 折线拐点连接处样式
               lineJoin: 'round',
               // PathSimplifier提供了一个快捷方法用于创建图片内容的content(function):
               // 图片地址
               // 图片加载成功,重新绘制一次 onload方法
               // 图片加载失败 onerror方法
               content: PathSimplifier.Render.Canvas.getImageContent(
                 'https://webapi.amap.com/images/car.png',
                 onload,
                 onerror
               ),
               // 这个位置提示一下 因为我们用的是图片所以看不见效果
               // 想看见效果删除上面的content
               // 他是一个三角形 这里就是设置边框颜色和内部颜色的
               // 填充色
               fillStyle: null,
               // 描边色
               strokeStyle: null,
               // 边的宽度
               lineWidth: 1,
               // 巡航器经过的路径的样式
               pathLinePassedStyle: {
                 lineWidth: 6,
                 strokeStyle: 'skyblue'
               }
             },
             // 线条样式
             pathLineStyle: {
               lineWidth: 6,
               strokeStyle: 'pink'
             },
             // 鼠标移入之后线条的样式
             pathLineHoverStyle: {
               lineWidth: 0,
               borderWidth: 0
             },
             // 鼠标单击之后线条的样式
             pathLineSelectedStyle: {
               lineWidth: 6,
               borderWidth: 0,
               strokeStyle: 'blue'
             },
             pathTolerance: 0,
             keyPointTolerance: -1,
             renderAllPointsIfNumberBelow: 0 // 绘制路线节点,如不需要可设置为-1
           }
         })
         // 历史轨迹巡航器设置数据 这里设置的就是上面pathData的数据
         that.pathSimplifierIns.setData([
           {
             name: '轨迹',
             path: that.pathList
           }
         ])
       })
     }
    

做到这一步路线就可以显示出来了在这里插入图片描述

创建小图标

  • 后台传递来的数据(丢在data或者js导入进来都可以)

    // 后台传递来的地图上的icon
    inco: [
      {
        latitude: 39.997761,
        longitude: 116.478935
      },
      {
        latitude: 39.99856,
        longitude: 116.479282
      },
      {
        latitude: 39.999861,
        longitude: 116.484648
      }
    ]
    
  • 遍历创建icon

    // 初始
    init() {
      // 创建起始和经过的icon
      this.icon.forEach(item => {
        this.addIcon(item)
      })
    },
    addIcon(item) {
      // 设置每个icon的内容
      const marker = new AMap.Marker({
        // 图片
        icon:
          '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png',
          // 位置
        position: [item.longitude, item.latitude],
          //设置基点偏移
        offset: new AMap.Pixel(-13, -30)
      })
      // 把图标放在地图上
      marker.setMap(this.map)
    }
    
  • 修改样式(如果图标太大可以修改一下图片 f12去查,设置失败需要考虑作用域更深一层)

    // 设置图标大小
    /deep/.amap-icon img {
      width: 25px;
      height: 34px;
    }
    

做到这一步icon就可以显示出来了
在这里插入图片描述

创建巡航器

我们先创建巡航器然后再去研究然后动起来

  • data里设置一个巡航器
     // 巡航器
     navgtr: null
    
  • setPath
     // 开启中心自适应
     that.pathSimplifierIns.setFitView(-1)
     // 对第一条线路(即索引 0)创建一个巡航器
     that.navgtr = that.pathSimplifierIns.createPathNavigator(0, {
       loop: false // 循环播放
     })
    

做到这一步小车就可以显示出来了
在这里插入图片描述

添导入加进度条

  • 使用什么框架都可以这里使用iview

    • 安装依赖
    • 导入(main.js)
      // 导入 vue-amap
      import AMap from 'vue-amap'
      // 导入iview
      import iView from 'iview'
      // 注册iview
      Vue.use(iView)
      
  • 代码部分

        <!-- 进度条 -->
        <div class="map-control">
          <!-- 开始按钮 -->
          <Icon v-if="!start" class="play-icon" type="ios-play" @click="navgControl"/>
          <!-- 暂停按钮 -->
          <Icon v-else class="play-icon" type="ios-pause" @click="navgControl"/>
          <!-- 开始时间 -->
          <span class="passed-time">00:00:00</span>
          <Slider class="map-slider"></Slider>
          <!-- 倍数 -->
          <div class="map-times" @mouseenter="isTimesChoose=true" @mouseleave="isTimesChoose=false">
            <div class="times-show">倍速{{times}}</div>
            <div class="choose-box">
              <!-- <ul v-show="isTimesChoose"> -->
              <ul v-show="isTimesChoose">
                <li v-for="item in speedList" :key="item" :class="{active:times==item}" @click="changeSpeed(1)">倍速 {{item}}</li>
              </ul>
            </div>
          </div>>
          <!-- 结束 -->
          <span class="passed-time">00:00:00</span>
        </div>
    
    // 设置图标大小
    /deep/.amap-icon img {
      width: 25px;
      height: 34px;
    }
    // 设置循环器样式
    .map-control {
      // 绝对定位
      position: absolute;
      bottom: 0;
      left: 0;
      width: 1200px;
      height: 80px;
      line-height: 80px;
      color: #fff;
      background-image: linear-gradient(to top, rgba(0, 0, 0, 0.7), transparent);
      padding: 0 40px;
      z-index: 1000;
      // 设置按钮大小
      .play-icon {
        font-size: 36px;
      }
      // 设置时间样式
      .passed-time {
        // 相对定位
        position: relative;
        // 转为行内元素
        display: inline-block;
        top: 1px;
        margin-left: 15px;
        font-size: 14px;
      }
      // 进度条样式
      .map-slider {
        // 转为行内元素
        display: inline-block;
        width: 75%;
        margin-left: 15px;
        position: relative;
        top: 14px;
      }
      // 修改默认的进度条样式
      .choose-box {
        // 相对定位
        position: absolute;
        top: -135px;
        left: -6px;
        height: 162px;
        // 过滤
        transition: all 0.5s linear;
      }
      // 倍数
      .map-times {
        display: inline-block;
        position: relative;
        margin-left: 15px;
        // 倍速样式
        .times-show {
          padding: 0 10px;
          line-height: 24px;
          font-size: 13px;
          border: 1px solid #fff;
          border-radius: 4px;
          // 鼠标设置为默认样式
          cursor: default;
        }
        // 倍数
        ul {
          background: rgba(0, 0, 0, 0.7);
          padding: 10px;
          width: 70px;
          text-align: center;
          border-radius: 3px;
          li {
            height: 26px;
            line-height: 26px;
            cursor: pointer;
          }
          li.active {
            color: #ff8533;
          }
          li:hover {
            font-size: 13px;
          }
        }
      }
    }
    
    // 暂停和播放按钮
    navgControl() {
      this.start = !this.start
    },
    // 进度条
    changeSpeed(item) {
      this.times = item
    }
    

在这里插入图片描述

计算速度和播放时间

  • 我们需要把后台传递给我们的时间转换为时间戳

    • 2020-08-21 16:21:18 — 1597998078000

    • 在init里继续进行编写代码

      linePath.forEach(item => {
        // 把json转为数组
        this.pathList.push([item.longitude, item.latitude])
        // 当前时间戳
        item.stampTime = new Date(item.time).getTime()
      })
      
  • 我们需要计算出每个路程的速度,这里假设数组的长度为x,里面分别是a、b、c……

    • 我们需要计算出a-b的速度 时间 路程 以此类推

    • 时间和路程已经给我们了就差速度了这个小学问题就不解释了上代码

    • 计算出2点直接的距离,放在for里不方便 提取出来

      // 计算两个坐标点之间的距离
      distanceFun(point1, point2) {
        // 那数组转化为经纬度
        let p1 = new AMap.LngLat(point1[0], point1[1])
        let p2 = new AMap.LngLat(point2[0], point2[1])
        // 计算2点直接的距离  distance这个函数有继续可以了解一下
        let distance = Math.round(p1.distance(p2))
        return distance
      }
      
    • 计算2点直接的速度

      • 计算下一段路程经历了多少s,
      • intervalTime间隔时间 秒
      • nextDistance:下一段路程:m,
      • nextDistance:下一段路速度:km/h
      linePath.forEach((item, i) => {
        // 获得到下一个位置
        let next = linePath[i + 1]
        // 判断是否还有下一个
        if (next) {
          // 计算出间隔时间 每秒
          item.intervalTime = (next.stampTime - item.stampTime) / 1000
          // 计算出下一站
          item.nextDistance = this.distanceFun(
            [item.longitude, item.latitude],
            [next.longitude, next.latitude]
          )
          // 求出具体的速度
          item.nextSpeed =
            item.nextDistance / 1000 / (item.intervalTime / 60 / 60)
        }
      })
      
    • 计算出总时间(因为太简单了,所以就放在这里直接说了)

      // 计算总时间,hh:mm:ss 因为计算出来是时间搓 所以要进行格式化
      this.totalTime = this.getTime(
        (endPoint.stampTime - startPoint.stampTime) / 1000
      )
      
      // 格式化时间(不解释)
      getTime(sTime) {
        let ss
        let mm = '00'
        let hh = '00'
        if (sTime > 60) {
          let s = sTime % 60
          ss = s > 9 ? s : '0' + s
          let mTime = parseInt(sTime / 60)
          if (mTime > 60) {
            let m = mTime % 60
            mm = m > 9 ? m : '0' + m
            hh = parseInt(mTime / 60)
          } else {
            mm = mTime > 9 ? mTime : '0' + mTime
          }
        } else {
          ss = sTime > 9 ? sTime : '0' + sTime
        }
        return hh + ':' + mm + ':' + ss
      }
      
      • 在date里添加
         // 总时间
         totalTime: '00:00:00',
        
      • 修改页面的总时间
          <span class="passed-time">{{totalTime}}</span>
        

滑动条改变事件

给滑动条绑定滑动事件

<Slider class="map-slider" @on-input="sliderChange"></Slider>
// 滑动条改变事件
sliderChange(val) {
  // 计算开始距离
  let num = parseInt((val / 100) * this.pathList.length)
  // 计算结束的距离
  let decimal =
    String((val / 100) * this.pathList.length).split('.')[1] || 0
  // 移动小车
  this.navgtr.moveToPoint(num, Number('0.' + decimal))
  // 重新绘制
  this.pathSimplifierIns.renderLater()
},

完成之后移动滑块就可以改变小车位置了

设置移动中的状态

  • 我们需要获取到一开的速度,2个办法

    • 计算一下一开始的速度
    • 直接获取数组0的速度
  • 我们采取方案2 首先先把之前遍历的数据设置到data里

     // 在init方法加上这行代码
     // 修改全局的路线数据
     this.linePath = linePath
    
  • 在setPath里编写,获取开始的速度以及给巡航器设置最开始的速度

     // 获取初始速度
     // 设置默认的为 0.1
     let startSpeed = 0.1
     if (that.linePath.length !== 0) {
       // 获取一开始的速度 并且判断是否为0 如果不为0直接返回 为0给一个初始的速度
       startSpeed =
         that.linePath[0].nextSpeed === 0 ? 0.1 : that.linePath[0].nextSpeed
     }
     // 对第一条线路(即索引 0)创建一个巡航器
     that.navgtr = that.pathSimplifierIns.createPathNavigator(0, {
       loop: false, // 循环播放
       // 速度×倍速
       speed: startSpeed * that.times
     })
    
  • 计算出开始时间和结束时间,原来展现的 在setPath里编写

     let linePath = that.linePath
     let len = linePath.length
     let startPoint = linePath[0]
     let endPoint = linePath[len - 1]
    
  • 编写移动状态

    • 修改滑动条和开始时间的样式

       <!-- 开始时间 将00 设置为经过的时间 不能再固定写死了-->
       <span class="passed-time">{{passedTime}}</span>
       <!-- 滑动条修改2个地方 step步长 tip-forma提示框 -->
       <Slider class="map-slider" @on-input="sliderChange" :step="0.0001" :tip-format="hideFormat"></Slider>
      
      // 滑动条的提示
      hideFormat() {
        return this.passedTime
      }
      
    • 移动状态

        // 移动过程中
        that.navgtr.on('move', function() {
          // 走到了第几个点
          let idx = this.getCursor().idx
          // 至下一个节点的比例位置
          let tail = this.getCursor().tail
          // 总路程
          let totalIdx = idx + tail
          // 计算下一个距离速度
          let point = linePath[idx]
          if (idx < len - 1) {
            // 判断速度是否为0 如果为0 需要给个0.1的速度
            point.nextSpeed === 0 && (point.nextSpeed = 0.1)
            // 这里的速度记得×倍数
            that.navgtr.setSpeed(point.nextSpeed * that.times)
          }
          // 剩余公里数,窗体随时移动展示
          // 判断是否还有下一个点和时间
          point &&
            point.time &&
            infoWindow.setContent(
              `<p class="info-window">时间:<span>${point.time}`
            )
          // 设置提示框
          infoWindow.open(that.map, that.navgtr.getPosition())
          // 进度条实时展示tail
          !that.isOnSlider && (that.sliderVal = (totalIdx / len) * 100)
          // 已经播放时间
          let sTime = parseInt(
            (((endPoint.stampTime - startPoint.stampTime) / 1000) *
              that.sliderVal) /
              100
          )
          // 格式化时间
          that.passedTime = that.getTime(sTime)
          // 如果到头了,回到初始状态
          if (that.navgtr.isCursorAtPathEnd()) {
            // 设置为暂停按钮
            that.start = false
            that.passedTime = that.totalTime
          }
        })
      

小车移动

  • 首先我们可以先了解一下小车的事件有哪些

    • resume 继续(不会绘制已经走过的颜色)
    • pause 暂停
    • start 开始 这里会回到原位
  • 所以根据这个我们应该就可以有清楚的思路了

    • 如果开始按钮设置了start ,那么你重新开始的时候就会回到原位
    • 所以移动过程需要设置resume 继续是最好的
    • pause暂停之后只能使用resume 继续
    • 所以我们的思路就路程结束之后,需要设置start
  • 修改开始按钮

     <!-- 开始按钮 -->
     <Icon v-if="!start" class="play-icon" type="ios-play" @click="navgControl(playIcon)"/>
    
  • 修改暂停按钮

      <!-- 暂停按钮 -->
      <Icon v-else class="play-icon" type="ios-pause" @click="navgControl('pause')"/>
    
  • 设置playIcon的初始数据

    • playIcon: 'start' //开始按钮是重新开始还是继续
      
  • 修改setpath中路程结束的代码

     // 如果到头了,回到初始状态
     if (that.navgtr.isCursorAtPathEnd()) {
       // 设置为开始状态 让小车回到原来位置
       that.playIcon = 'start'
       // 设置图标状态
       that.start = false
       // 设置已经走过的时间
       that.passedTime = that.totalTime
       // 设置滑动条状态
       that.sliderVal = 100
     }
    
  • 暂停开始按钮

     // 暂停和播放按钮
     navgControl(action) {
       if (action === 'start') {
         let that = this
         this.passedTime = '00:00:00'
         setTimeout(() => {
           that.navgtr[action]()
         }, 300)
       } else {
         this.navgtr[action]()
       }
       // 修改图标状态
       this.start = !this.start
     },
    
  • 在移动过程也需要进行设置

     // 移动过程中
     that.navgtr.on('move', function() {
       that.playIcon = 'resume'
       //……………………
    
  • 设置滑块(之前忘记设计了)

    • 给滑块绑定数据 v-model=“sliderVal”

       <Slider class="map-slider" v-model="sliderVal" @on-input="sliderChange" :step="0.0001" :tip-format="hideFormat"></Slider>
       ```
      
      
  • 然后发现修改速度的也不行。。。。。。原来是我传值的时候传了1。。。(设置代码时候还是要注意呀)

    • changeSpeed(item) 这里记住是item哦

        <li v-for="item in speedList" :key="item" :class="{active:times==item}" @click="changeSpeed(item)">倍速 {{item}}</li>
        ```
      
      
    • 然后发现。。。ul的关闭也忘记设置为false了

        // 修改速度
        changeSpeed(item) {
          this.times = item
          this.isTimesChoose = false
        },
      
      
      
      
  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
对于Vue 3和高德地图的轨迹回放,你可以按照以下步骤进行操作: 1. 首先,确保你已经安装了Vue 3和高德地图的相关依赖。你可以使用npm或yarn来安装这些依赖。例如,在你的Vue项目中,可以运行以下命令来安装高德地图的依赖: ``` npm install vue-amap ``` 2. 在你的Vue组件中,引入Vue AMap库并注册该组件: ```javascript import VueAMap from 'vue-amap'; export default { ... mounted() { Vue.use(VueAMap); VueAMap.initAMapApiLoader({ key: 'your_amap_key', plugin: ['AMap.Polyline'] }); }, ... } ``` 在上述代码中,你需要将`your_amap_key`替换成你自己的高德地图API密钥。 3. 在模板中添加地图容器和控件: ```html <template> <div> <amap :zoom="13" :center="[lng, lat]"> <amap-polyline :path="path" :visible="true" :style="{ strokeColor: 'red', strokeWeight: 6 }"></amap-polyline> </amap> </div> </template> ``` 在上述代码中,`amap`是地图容器组件,`amap-polyline`是轨迹回放的折线组件。你可以根据需要调整地图的缩放级别和中心点位置,以及折线的样。 4. 在组件的`data`属性中定义轨迹回放的经纬度数据: ```javascript data() { return { lng: 116.397428, lat: 39.90923, path: [ [116.405289, 39.904987], [116.406089, 39.904987], [116.406289, 39.905087], // 更多经纬度数据... ] }; } ``` 你需要根据实际情况提供正确的经纬度数据。 5. 最后,你可以根据需求实现轨迹回放的逻辑。例如,你可以使用定时器来逐步显示折线上的点,实现轨迹的动态回放效果。 这样,你就可以在Vue 3中使用高德地图实现轨迹回放了。记得根据你的实际需求进行相应的调整和扩展。希望这能帮到你!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值