VUE3+TS+element UI +高德地图实现轨迹回放带进度条

记录一下,由于项目需要做车辆的历史轨迹回放,查了很多资料,在高德地图里有这几种解决方案。

所用技术:vue3 + TS +element UI plus +高德地图

 这是相关的Demo借鉴

高德地图的轨迹回放demo

轨迹巡航器控制

高德地图Amap UI

下面是效果图:

1,这是高德地图提供的轨迹回放demo

 2,这是使用的高德地图AMap UI的巡航器

 讲一下实现方法

1,轨迹回放的有两种写法,第一个是初始化加载的时候就把监听事件放进去


const initMap = () => {
  AMapLoader.load({
    key: "key", // 申请好的Web端开发者Key,首次调用 load 时必填
    version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
    plugins: ["AMap.moveAnimation"], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
    AMapUI: {
      // 是否加载 AMapUI,缺省不加载
      version: "1.1", // AMapUI 版本
      plugins: [], // 需要加载的 AMapUI ui插件
    },
  })
    .then((AMap) => {
      const map = new AMap.Map("container", {
        //设置地图容器id
        viewMode: "3D", //是否为3D地图模式
        zoom: 13, //初始化地图级别
        center: current_position.value, //初始化地图中心点位置
        mapStyle: "amap://styles/fresh",
      })
      // 添加插件
      AMap.plugin(
        [
          "AMap.ToolBar",
          "AMap.Scale",
          "AMap.HawkEye",
          "AMap.Geolocation",
          "AMap.MapType",
          "AMap.MouseTool",
          "AMap.Polyline",
        ],
        function () {
          //异步同时加载多个插件
          // 添加地图插件
          // map.addControl(new AMap.ToolBar()) // 工具条控件;范围选择控件
          map.addControl(new AMap.Scale()) // 显示当前地图中心的比例尺
          // map.addControl(new AMap.HawkEye()) // 显示缩略图
          // map.addControl(new AMap.Geolocation()) // 定位当前位置
          // map.addControl(new AMap.MapType()) // 实现默认图层与卫星图,实时交通图层之间切换

          // 以下是鼠标工具插件
          const mouseTool = new AMap.MouseTool(map)
          // mouseTool.rule();// 用户手动绘制折线图,测量距离
          // mouseTool.measureArea() // 测量面积
        }
      )
      // 实例化点标记
      const marker = new AMap.Marker({
        icon: "//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
        position: current_position.value, // 这里我们通过上面的点击获取经纬度坐标,实时添加标记
        // 通过设置 offset 来添加偏移量
        offset: new AMap.Pixel(-26, -54),
      })
//这里监听标注点的点击事件,触发实现动画效果
      marker.on("click", function () {
        animationMove()
      })
      marker.setMap(map)
      
      // 历史轨迹动画
      function animationMove() {
        AMap.plugin("AMap.MoveAnimation", function () {
          var marker,
            lineArr = [
              [116.478935, 39.997761],
              [116.478939, 39.997825],
              [116.478912, 39.998549],
              [116.478912, 39.998549],
              [116.478998, 39.998555],
              [116.478998, 39.998555],
              [116.479282, 39.99856],
              [116.479658, 39.998528],
              [116.480151, 39.998453],
              [116.480784, 39.998302],
              [116.480784, 39.998302],
              [116.481149, 39.998184],
              [116.481573, 39.997997],
              [116.481863, 39.997846],
              [116.482072, 39.997718],
              [116.482362, 39.997718],
              [116.483633, 39.998935],
              [116.48367, 39.998968],
              [116.484648, 39.999861],
            ]

          var map = new AMap.Map("container", {
            resizeEnable: true,
            center: [116.397428, 39.90923],
            zoom: 17,
          })

          marker = new AMap.Marker({
            map: map,
            position: [116.478935, 39.997761],
            icon: "https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png",
            offset: new AMap.Pixel(-13, -26),
          })

          // 绘制轨迹
          var polyline = new AMap.Polyline({
            map: map,
            path: lineArr,
            showDir: true,
            strokeColor: "#28F", //线颜色
            // strokeOpacity: 1,     //线透明度
            strokeWeight: 6, //线宽
            // strokeStyle: "solid"  //线样式
          })

          var passedPolyline = new AMap.Polyline({
            map: map,
            strokeColor: "#AF5", //线颜色
            strokeWeight: 6, //线宽
          })

          marker.on("moving", function (e: any) {
            passedPolyline.setPath(e.passedPath)
            map.setCenter(e.target.getPosition(), true)
          })

          map.setFitView()
          marker.moveAlong(lineArr, {
            // 每一段的时长
            duration: 500, //可根据实际采集时间间隔设置
            // JSAPI2.0 是否延道路自动设置角度在 moveAlong 里设置
            autoRotation: true,
          })
        })
      }
    })
    .catch((e) => {
      console.log(e)
    })
}
initMap()

2,轨迹回放的第二种写法,比较灵活一点

const listPath = async () => {
  //获取历史轨迹点
  list_Position.value = []
  //请求接口获取轨迹点数据
  const res: any = await getHistoryLocus(listSearch)
  //轨迹起点坐标
  start_position.value = changePosition(
    res.result[0].gLatitude,
    res.result[0].gLongitude
  ) as any

  lineList.value = res.result

  res.result.forEach((item: any) => {
    list_Position.push(changePosition(item.gLatitude, item.gLongitude))
  })
  console.log(list_Position, `打印list_Positionlist_Position`)
//加载地图
  let marker: any,
    map = new AMap.Map("container", {
      resizeEnable: true,
      center: start_position.value,
      zoom: 13,
    })
  marker = new AMap.Marker({
    icon: "https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png",
    position: start_position.value,
    offset: new AMap.Pixel(-13, -30),
  })

  marker.on("click", function () {
   
    ;(AMap as any).plugin("AMap.MoveAnimation", function () {
      marker.moveAlong(list_Position, {
        // 每一段的时长
        duration: 500, //可根据实际采集时间间隔设置
        // JSAPI2.0 是否延道路自动设置角度在 moveAlong 里设置
        autoRotation: true,
      })
    })
  })
  marker.setMap(map)
  // 绘制轨迹
  var polyline = new AMap.Polyline({
    map: map,
    path: list_Position,
    showDir: true,
    strokeColor: "#28F", //线颜色
    // strokeOpacity: 1,     //线透明度
    strokeWeight: 6, //线宽
    // strokeStyle: "solid"  //线样式
  })

  var passedPolyline = new AMap.Polyline({
    map: map,
    strokeColor: "#AF5", //线颜色
    strokeWeight: 6, //线宽
  })

  marker.on("moving", function (e: any) {
    passedPolyline.setPath(e.passedPath)
    map.setCenter(e.target.getPosition())
  })
  ;(map as any).setFitView()
}

 3,使用AMap UI的轨迹巡航器来实现,配合进度条,这样写会有个BUG就是点击开始的时候,直接拖动进度条会报错

const listPath = async () => {
  //获取历史轨迹点
  list_Position.value = []
  //请求接口获取轨迹点数据
  const res: any = await getHistoryLocus(listSearch)
  //轨迹起点坐标
  start_position.value = changePosition(
    res.result[0].gLatitude,
    res.result[0].gLongitude
  ) as any

  lineList.value = res.result

  res.result.forEach((item: any) => {
    list_Position.push(changePosition(item.gLatitude, item.gLongitude))
  })
  console.log(list_Position, `打印list_Positionlist_Position`)

  
  // -----------------轨迹巡航器--------------------------------------
  //@ts-ignore  单行忽略   解决TS语法提示 AMap UI 不存在
  AMapUI.load(
    ["ui/misc/PathSimplifier", "lib/$", "ui/overlay/SimpleMarker"],
    function (PathSimplifier: any, $: any, SimpleMarker: any) {
      if (!PathSimplifier.supportCanvas) {
        alert("当前环境不支持 Canvas!")
        return
      }
      // $.SimpleMarker

      let pathSimplifierIns: any = new PathSimplifier({
        zIndex: 100,
        SimpleMarker: SimpleMarker,
        //autoSetFitView:false,
        map: map, //所属的地图实例

        getPath: function (pathData: any, pathIndex: any) {
          return pathData.path
        },
        getHoverTitle: function (
          pathData: any,
          pathIndex: any,
          pointIndex: any
        ) {
          if (pointIndex >= 0) {
            //point
            return (
              pathData.name + ",点:" + pointIndex + "/" + pathData.path.length
            )
          }

          return pathData.name + ",定位点数量" + pathData.path.length
        },
       
        renderOptions: {
          pathLineStyle: {
            dirArrowStyle: true,
          },
          getPathStyle: function (pathItem: any, zoom: any) {
            let lineWidth = Math.round(4 * Math.pow(1.1, zoom - 3))

            return {
              pathLineStyle: {
                strokeStyle: "#28F",
                lineWidth: 6,
              },
              pathLineSelectedStyle: {
                lineWidth: 6,
              },
              pathNavigatorStyle: {
                fillStyle: "#AF5",
              },
            }
          },
        },
      })

      //设置数据
      pathSimplifierIns.setData([
        {
          name: "路线1",
          path: list_Position,
        },
      ])
      // 巡航器的样式
      let pathNavigatorStyles = [
        {
          width: 16,
          height: 32,
          //使用图片
          content: PathSimplifier.Render.Canvas.getImageContent(
            "https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png",
            pathSimplifierIns.renderLater()
          ),
        },
      ]
      //对第一条线路(即索引 0)创建一个巡航器
      var navg1 = pathSimplifierIns.createPathNavigator(0, {
        loop: false, //循环播放
        speed: times.value, //巡航速度,单位千米/小时
        pathNavigatorStyle: pathNavigatorStyles[0],
      })
      navgtr.value = navg1
     
      navg1.on("move", function () {
        let idx = navgtr.value.getCursor().idx //走到了第几个点
        let tail = navgtr.value.getCursor().tail //至下一个节点的比例位置
        let totalIdx = idx + tail
        // 进度条实时展示tail
        !isOnSlider.value && (currentIndex.value = totalIdx)
        //地图中心跟随变化
        map.setCenter(list_Position[idx])

        // 已经播放时间
        // 如果到头了,回到初始状态
        console.log(
          navgtr.value.isCursorAtPathEnd(),
          `打印navgtr.value.isCursorAtPathEnd()`
        )

        if (navgtr.value.isCursorAtPathEnd()) {
          currentIndex.value = list_Position.length
        }
      })
      pathSimplifier.value = pathSimplifierIns
    }
  )
  gmap.value = map
  console.log(res, `打印getHistoryLocusresres`)
}
// 开始按钮
const startBtn = () => {
  navgtr.value.start()
}
// 暂停按钮
const stopBtn = () => {
  
  navgtr.value.pause()
 
}
// 快进
const changeSpeed = () => {
  times.value = times.value + 200
  navgtr.value.setSpeed(times.value)
  console.log(times.value, `打印times.valuetimes.value`)
}
// 慢放
const slowSpeed = () => {
  if (times.value > 400) {
    times.value = times.value - 200
  }
  navgtr.value.setSpeed(times.value)
  console.log(times.value, `打印times.valuetimes.value`)
}
//继续
const puseSpeed = () => {
  navgtr.value.resume()
 
}

const stopMove = () => {
  console.log(`打印sahdjlahdasb;`)

  navgtr.value.pause()
}
//进度条带动巡航器变化
const changeSliderValue = () => {
  navgtr.value.pause()
  navgtr.value.moveToPoint(currentIndex.value, 0)
  pathSimplifier.value.renderLater()
  gmap.value.setCenter(list_Position[currentIndex.value])
}
// 滑块的提示信息 
const handlDelta = (e: any) => {
  e = e.toFixed(0)
  let nowtime: any = ""
  let dayMile: any = 0
  let totalMile: any = 0
  let str = ""
  if (lineList.value) {
    lineList.value.forEach((item: any, index: any) => {
      nowtime =
        item.gReportTime.split("T")[0] +
        " " +
        item.gReportTime.split("T")[1].split("+")[0]
      dayMile = item.sDayMileage.toFixed(2)
      totalMile = Number(totalMile) + Number(dayMile)
      if (index == e) {
        str =
          nowtime +
          " 今日:" +
          dayMile +
          " km 累计:" +
          totalMile.toFixed(2) +
          " km"
      }
    })
  }
  return str
  
}

这是dom的结构

 <div class="fix_bottom_close">
        <el-tabs type="border-card">
          <el-tab-pane label="时间轴">
            <el-button-group>
              <el-button type="primary" @click="slowSpeed">慢放</el-button>
              <el-button type="primary" @click="startBtn"> 开始 </el-button>
              <el-button type="primary" @click="stopBtn"> 暂停 </el-button>
              <el-button type="primary" @click="puseSpeed"> 继续 </el-button>
              <el-button type="primary" @click="changeSpeed"> 快进 </el-button>
            </el-button-group>
            <div class="fix_bottom_slider">
              <el-slider
                ref="timeSlider"
                v-model="currentIndex"
                show-stops
                :max="list_Position.length"
                :format-tooltip="handlDelta"
                @change="changeSliderValue"
              />
            </div>
          </el-tab-pane>
          <el-tab-pane label="速度曲线">Config</el-tab-pane>
          <el-tab-pane label="行程数据">Role</el-tab-pane>
          <el-tab-pane label="详细数据">Task</el-tab-pane>
        </el-tabs>
      </div>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值