[Vue3] 在uniapp中实现trackreview

124 阅读6分钟

问题

  1. 没有倍速按钮
  2. 不能拖动进度条
  3. 画面大小, 图例等样式问题

一.创建vue3-uniapp项目

文件-新建-项目-uniapp项目

二.安装扩展(不用创建package.json会自动创建)

pnpm install @vuemap/vue-amap view-ui-plus

三.初始化

修改main.js

import App from './App'
import '@vuemap/vue-amap/dist/style.css'
import 'view-ui-plus/dist/styles/viewuiplus.css'
import ViewUIPlus from 'view-ui-plus'
import VueAMap, { initAMapApiLoader } from '@vuemap/vue-amap';

import { createSSRApp } from 'vue'

export function createApp() {
  const app = createSSRApp(App)
  
  initAMapApiLoader({
	  // 高德的key
	  key: 'youkey',
	  // 插件集合
	  plugin: [],
	  AMapUI: {},
	  // 高德 sdk 版本,默认为 1.4.4
	  v: '2.0'
  })
  app.use(VueAMap)
  app.use(ViewUIPlus)
	  
  return {
    app
  }
}

4.页面

<template>
  <div class="map-outbox">
    <!-- 地图 -->
    <div id="container"></div>
    <!-- 进度条 -->
    <div class="map-control">
      <Icon v-if="!isPlay" class="play-icon" type="ios-play" @click="isPlay = true; navgControl(playIcon)" />
      <Icon v-else class="play-icon" type="ios-pause" @click="isPlay = false; navgControl('pause')" />
      <span class="passed-time">{{ passedTime }}</span>
      <Slider class="map-slider" v-model="sliderVal" @on-change="sliderChange" :tip-format="hideFormat" :step="0.0001">
      </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">
            <li v-for="item in speedList" :key="item" :class="{ active: times === item }" @click="changeSpeed(item)">倍速
              {{ item }}</li>
          </ul>
        </div>
      </div>
      <span class="passed-time">{{ totalTime }}</span>
    </div>
  </div>
</template>
  
  <script setup>
  // import { linePath, marks } from '/@/api/public/index'

  import car from "/static/car.png";
  // import VueAMap, { initAMapApiLoader } from '@vuemap/vue-amap';
  import { lazyAMapApiLoaderInstance } from '@vuemap/vue-amap';
  import { onMounted, onUnmounted, ref, watch } from 'vue'
  let map = ref(null)
  let isOnSlider = ref(false) //是否为手动鼠标拉动进度条
  let playIcon = ref('resume');  //开始按钮是重新开始还是继续
  let isTimesChoose = ref(false) //选择速度弹窗的open/close
  let passedTime = ref('00:00:00') //已经走了的时间
  let totalTime = ref('00:00:00') //已经走了的时间
  let isPlay = ref(false)
  let sliderVal = ref(0) // 进度条滑动速度
  let speed = ref(100) //初始速度,km、h
  let times = ref(1) //几倍速度播放
  let navgtr = ref(null)  //巡航器
  let speedList = ref([8, 4, 2, 1])
  let pathList = ref([])
  let trackList = ref([])
  let pathSimplifierIns = ref(null)
  
  const 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.998453,
        longitude: 116.480151,
        time: "2020-08-21 16:21:36"
      },
      {
        latitude: 39.998184,
        longitude: 116.481149,
        time: "2020-08-21 16:21:42"
      },
      {
        latitude: 39.997846,
        longitude: 116.481863,
        time: "2020-08-21 16:21:48"
      },
      {
        latitude: 39.997718,
        longitude: 116.482362,
        time: "2020-08-21 16:21:54"
      },
      {
        latitude: 39.999861,
        longitude: 116.484648,
        time: "2020-08-21 16:22:03"
      }
    ]
	
	const marks = [
	{
	  latitude: 39.997761,
	  longitude: 116.478935
	},
	{
	  latitude: 39.999861,
	  longitude: 116.484648
	}
  ]
  
  let emits = defineEmits(['handleqktraV2IdId'])
  onMounted(() => {
    let param = {
      resizeEnable: true,
      zoom: 15,
      center: [116.47984, 39.998524],
    };
    lazyAMapApiLoaderInstance.then(() => {
      // your code ...
      map.value = new AMap.Map("container", param);
      init();
    });
  })
  
  const init = () => {
    // 创建起始和经过的icon
    let iconList = [];
    marks.forEach(item => {
      addMarker(item);
    });
  
    // 轨迹
    let list = linePath;
    let len = list.length;
    let startPoint = list[0];
    let endPoint = list[len - 1];
    pathList.value.splice(0, pathList.value.length);
    list.forEach(item => {
      pathList.value.push([item.longitude, item.latitude]);
      item.stampTime = new Date(item.time).getTime(); //当前时间戳
    });
    // 下一段路程经历了多少s,intervalTime,nextDistance:下一段路程:m,nextDistance:下一段路速度:km/h
    list.forEach((item, i) => {
      let next = list[i + 1];
      if (next) {
        item.intervalTime = (next.stampTime - item.stampTime) / 1000;
        item.nextDistance = distanceFun(
          [item.longitude, item.latitude],
          [next.longitude, next.latitude]
        );
        item.nextSpeed =
          item.nextDistance / 1000 / (item.intervalTime / 60 / 60);
      }
    });
    // 订单记录总时间,hh:mm:ss
    totalTime.value = getTime(
      (endPoint.stampTime - startPoint.stampTime) / 1000
    );
    trackList.value = list;
    setPath();
    drag();
  }
  
  const setPath = () => {
    AMapUI.load(["ui/misc/PathSimplifier", "lib/$"], function (
      PathSimplifier
    ) {
      if (!PathSimplifier.supportCanvas) {
        console.log("当前环境不支持 Canvas!");
        return;
      }
      let len = trackList.value.length;
      let startPoint = trackList.value[0];
      let endPoint = trackList.value[len - 1];
      // 轨迹总数
      function onload() {
        pathSimplifierIns.value.renderLater();
      }
      function onerror() {
        infoContent;
        console.log("图片加载失败!");
      }
  
      // 历史轨迹巡航器
      pathSimplifierIns.value = new PathSimplifier({
        zIndex: 100,
        //autoSetFitView:false,
        map: map.value, //所属的地图实例
  
        getPath: function (pathData) {
          return pathData.path;
        },
        getHoverTitle: function (pathData) {
          return pathData.index;
        },
        autoSetFitView: true,
        // 巡航器样式
        renderOptions: {
          pathNavigatorStyle: {
            initRotateDegree: 0,
            width: 20,
            height: 32,
            autoRotate: true,
            lineJoin: "round",
            content: PathSimplifier.Render.Canvas.getImageContent(
              car,
              onload,
              onerror
            ),
            fillStyle: null,
            strokeStyle: null,
            lineWidth: 1,
            pathLinePassedStyle: {
              lineWidth: 6,
              strokeStyle: "#2cdf4d"
            }
          },
          // 这个会修改所有颜色
          pathLineStyle: {
            lineWidth: 6,
            strokeStyle: "#2e9c08"
          },
          pathLineHoverStyle: {
            lineWidth: 0,
            borderWidth: 0
          },
          pathLineSelectedStyle: {
            lineWidth: 6,
            borderWidth: 0,
            strokeStyle: "#2e9c08"
          },
          pathTolerance: 0,
          keyPointTolerance: -1,
          renderAllPointsIfNumberBelow: 0 //绘制路线节点,如不需要可设置为-1
        }
      });
  
      //历史轨迹巡航器设置数据
      pathSimplifierIns.value.setData([
        {
          name: "轨迹",
          path: pathList.value
        }
      ]);
      pathSimplifierIns.value.setFitView(-1);
  
      let startSpeed = speedFun(
        pathList.value[0],
        pathList.value[1],
        startPoint.intervalTime
      );
      startSpeed === 0 && (startSpeed = 0.1);
  
      //对第一条线路(即索引 0)创建一个巡航器
      navgtr.value = pathSimplifierIns.value.createPathNavigator(0, {
        loop: false, //循环播放
        speed: startSpeed * times.value //巡航速度,单位千米/小时
      });
      //构建自定义信息窗体
      let infoContent = `<p class="info-window">时间:<span>${startPoint.time} `;
      let infoWindow = new AMap.InfoWindow({
        anchor: "bottom-center",
        content: infoContent
      });
  
      infoWindow.open(map.value, pathList.value[0]);
      // 移动过程中
      navgtr.value.on("move", function () {
        playIcon.value = "resume";
        let idx = this.getCursor().idx; //走到了第几个点
        let tail = this.getCursor().tail; //至下一个节点的比例位置
        let totalIdx = idx + tail;
  
        // 计算下一个距离速度
        let point = trackList.value[idx];
        if (idx < len - 1) {
          point.nextSpeed === 0 && (point.nextSpeed = 0.1);
          navgtr.value.setSpeed(point.nextSpeed * times.value);
        }
  
        // 剩余公里数,窗体随时移动展示
        point &&
          point.time &&
          infoWindow.setContent(
            `<p class="info-window">时间:<span>${point.time}`
          );
        infoWindow.open(map.value, navgtr.value.getPosition());
        // 进度条实时展示tail
        !isOnSlider.value && (sliderVal.value = (totalIdx / len) * 100);
        // 已经播放时间
        // let sTime = (pointObj.stampTime-startStampTime)/1000;
        let sTime = parseInt(
          (((endPoint.stampTime - startPoint.stampTime) / 1000) *
            sliderVal.value) /
          100
        );
  
        passedTime.value = getTime(sTime);
        // 如果到头了,回到初始状态
        if (navgtr.value.isCursorAtPathEnd()) {
          playIcon.value = "start";
          isPlay.value = false;
          sliderVal.value = 100;
          passedTime.value = totalTime.value;
        }
      });
  
      navgtr.value.on("start resume", function () {
  
        navgtr.value._startTime = Date.now();
        navgtr.value._startDist = this.getMovedDistance();
      });
      navgtr.value.on("stop pause", function () {
        navgtr.value._movedTime = Date.now() - navgtr.value._startTime;
        navgtr.value._movedDist =
          this.getMovedDistance() - navgtr.value._startDist;
      });
    });
  }
  
  // 开始、暂停、继续等操作
  const navgControl = (action) => {
    if (action === "start") {
      sliderVal.value = 0;
      passedTime.value = "00:00:00";
      setTimeout(() => {
        navgtr.value[action]();
      }, 300);
    } else {
      navgtr.value[action]();
    }
  }
  
  //     // 格式化时间
  const 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;
  }
  const hideFormat = () => {
    return null;
  }
  // 计算两个坐标点之间的距离
  const distanceFun = (point1, point2) => {
    // point1:[longitude,latitude]
    let p1 = new AMap.LngLat(point1[0], point1[1]);
    let p2 = new AMap.LngLat(point2[0], point2[1]);
    let distance = Math.round(p1.distance(p2));
    return distance;
  }
  const speedFun = (point1, point2, time) => {
    // point1,point2:经纬度数组,time:时间,s
    let distance = distanceFun(point1, point2);
    if (distance === 0) {
      return 0;
    } else {
      let speed = distance / 1000 / (time / 60 / 60);
      // speed:km/h
      return speed;
    }
  }
  
  const drag = (isRemove) => {
    let el = document.getElementsByClassName("ivu-slider-button-wrap")[0];
    let el2 = document.getElementsByClassName("ivu-slider-wrap")[0];
  
    if (isRemove) {
      el && el.removeEventListener("mousedown", openSlider.value, false);
      document.removeEventListener("mouseup", closeSlider.value, false);
      el2 && el2.removeEventListener("click", sliderChange.value, false);
      return false;
    }
    el2.addEventListener("click", sliderChange.value, false);
    el.addEventListener("mousedown", openSlider.value, false);
    // 此处用document是因为,滑动较为随意时,mouseup可能不是作用在el上
    document.addEventListener("mouseup", closeSlider.value, false);
  }
  
  
  const openSlider = () => {
    isOnSlider.value = true;
  }
  
  const closeSlider = () => {
    isOnSlider.value = false;
  }
  
  // 修改倍速
  const changeSpeed = (item) => {
    isTimesChoose.value = false;
    times.value = item;
  }
  
  const sliderChange = (val) => {
    let newVal = typeof val === "number" ? val : sliderVal.value;
    let num = parseInt((newVal / 100) * pathList.value.length);
    let decimal =
      String((newVal / 100) * pathList.value.length).split(".")[1] || 0;
    navgtr.value.moveToPoint(num, Number("0." + decimal));
    pathSimplifierIns.value.renderLater();
  }
  
  const addMarker = (item) => {
    let 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(map.value);
  }
  
  // 新增假如当前是子组件关闭的时候判断是播放还是其他状态,防止setSpeed报错null
  const cancelsubmitfotm = () => {
    if (isPlay.value) {
      isPlay.value = false;
      navgControl("pause");
    }
    navgtr.value = null;
    drag(true);
    emits("handleqktraV2IdId", this.traV2Id)
    dialogFormVisible.value = false;
  }
  onUnmounted(() => {
    navgtr.value = ref(null);
    drag(true);
  })
  
  watch(() => sliderVal.value,
    (val) => {
      if (!isOnSlider.value) {
        return false;
      }
      sliderChange(val);
    },
    {
      deep: true,
    })
  
  </script>
  
<style>
/* 根容器样式 */
.map-outbox {
  width: 100%;
  padding: 40rpx;
  border: 1px solid #ddd;
  margin: auto;
}

/* 地图容器样式 */
#container {
  width: 100%;
  height: 50vh;
}

/* 控制条样式 */
.map-control {
  position: fixed;
  bottom: 0;
  width: 100%;
  left: 0;
  z-index: 200;
  height: 160rpx;
  line-height: 160rpx;
  color: #fff;
  background-image: linear-gradient(to top, rgba(0, 0, 0, 0.7), transparent);
  padding: 0 40rpx;
}

/* 播放按钮样式 */
.play-icon {
  font-size: 36rpx;
}

/* 进度条样式 */
.map-slider {
  display: inline-block;
  width: 45%;
  margin-left: 15rpx;
  position: relative;
  top: 28rpx;
}

/* 已播放时间样式 */
.passed-time {
  position: relative;
  top: 8rpx;
  display: inline-block;
  margin-left: 15rpx;
  font-size: 28rpx;
}

/* 倍速选择样式 */
.map-times {
  display: inline-block;
  position: relative;
  margin-left: 15rpx;
}

.map-times .times-show {
  padding: 0 10rpx;
  line-height: 48rpx;
  font-size: 26rpx;
  border: 1px solid #fff;
  border-radius: 4rpx;
  cursor: default;
}

.map-times .choose-box {
  position: absolute;
  top: -135rpx;
  left: -6rpx;
  height: 162rpx;
  transition: all 0.5s linear;
}

/* 倍速长度 */
.map-times ul {
  background: rgba(0, 0, 0, 0.7);
  padding: 10rpx;
  width: 150rpx;
  text-align: center;
  border-radius: 3rpx;
}

.map-times li {
  height: 36rpx;
  line-height: 36rpx;
  cursor: pointer;
}

.map-times li.active {
  color: #ff8533;
}

.map-times li:hover {
  font-size: 13px;
}
</style>

对接API获取数据(未完)

<template>
  <div class="map-outbox">
    <!-- 地图 -->
    <div id="container"></div>
    <!-- 进度条 -->
    <div class="map-control">
      <Icon v-if="!isPlay" class="play-icon" type="ios-play" @click="isPlay = true; navgControl(playIcon)" />
      <Icon v-else class="play-icon" type="ios-pause" @click="isPlay = false; navgControl('pause')" />
      <span class="passed-time">{{ passedTime }}</span>
      <Slider class="map-slider" v-model="sliderVal" @on-change="sliderChange" :tip-format="hideFormat" :step="0.0001">
      </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">
            <li v-for="item in speedList" :key="item" :class="{ active: times === item }" @click="changeSpeed(item)">倍速
              {{ item }}</li>
          </ul>
        </div>
      </div>
      <span class="passed-time">{{ totalTime }}</span>
    </div>
  </div>
</template>
  
  <script setup>
  // import { linePath, marks } from '/@/api/public/index'

  import car from "/static/car.png";
  // import VueAMap, { initAMapApiLoader } from '@vuemap/vue-amap';
  import { lazyAMapApiLoaderInstance } from '@vuemap/vue-amap';
  import { onMounted, onUnmounted, ref, watch } from 'vue'
  let map = ref(null)
  let isOnSlider = ref(false) //是否为手动鼠标拉动进度条
  let playIcon = ref('resume');  //开始按钮是重新开始还是继续
  let isTimesChoose = ref(false) //选择速度弹窗的open/close
  let passedTime = ref('00:00:00') //已经走了的时间
  let totalTime = ref('00:00:00') //已经走了的时间
  let isPlay = ref(false)
  let sliderVal = ref(0) // 进度条滑动速度
  let speed = ref(100) //初始速度,km、h
  let times = ref(1) //几倍速度播放
  let navgtr = ref(null)  //巡航器
  let speedList = ref([8, 4, 2, 1])
  let pathList = ref([])
  let trackList = ref([])
  let pathSimplifierIns = ref(null)
 
  
  let linePathData = ref(null);
  let marksData = ref(null);
  
  let emits = defineEmits(['handleqktraV2IdId'])
  onMounted(() => {
    let param = {
      resizeEnable: true,
      zoom: 15,
      center: [116.47984, 39.998524],
    };
    lazyAMapApiLoaderInstance.then(() => {
      // your code ...
      map.value = new AMap.Map("container", param);
	  
	  uni.request({
	      url: 'http://localhost:8000/admin/dashboard/getTrackData', //仅为示例,并非真实接口地址。
	      data: {
	          server: 1
	      },
	      header: {
	          'batoken': '733728bd-3565-4f2a-ae00-7ce645637f42' //自定义请求头信息
	      },
	      success: (res) => {
	          console.log('@@@', res.data);
			  linePathData.value = res.data.list
			  marksData.value = res.data.point
			  console.log('@@@2', linePathData.value);
	          init();
	      }
	  });
     
    });
  })
  
  const init = () => {
    // 创建起始和经过的icon
    let iconList = [];
    marksData.value.forEach(item => {
      addMarker(item);
    });
  
    // 轨迹
    let list = linePathData.value;
    let len = list.length;
    let startPoint = list[0];
    let endPoint = list[len - 1];
    pathList.value.splice(0, pathList.value.length);
    list.forEach(item => {
      pathList.value.push([item.longitude, item.latitude]);
      item.stampTime = new Date(item.time).getTime(); //当前时间戳
    });
    // 下一段路程经历了多少s,intervalTime,nextDistance:下一段路程:m,nextDistance:下一段路速度:km/h
    list.forEach((item, i) => {
      let next = list[i + 1];
      if (next) {
        item.intervalTime = (next.stampTime - item.stampTime) / 1000;
        item.nextDistance = distanceFun(
          [item.longitude, item.latitude],
          [next.longitude, next.latitude]
        );
        item.nextSpeed =
          item.nextDistance / 1000 / (item.intervalTime / 60 / 60);
      }
    });
    // 订单记录总时间,hh:mm:ss
    totalTime.value = getTime(
      (endPoint.stampTime - startPoint.stampTime) / 1000
    );
    trackList.value = list;
    setPath();
    drag();
  }
  
  const setPath = () => {
    AMapUI.load(["ui/misc/PathSimplifier", "lib/$"], function (
      PathSimplifier
    ) {
      if (!PathSimplifier.supportCanvas) {
        console.log("当前环境不支持 Canvas!");
        return;
      }
      let len = trackList.value.length;
      let startPoint = trackList.value[0];
      let endPoint = trackList.value[len - 1];
      // 轨迹总数
      function onload() {
        pathSimplifierIns.value.renderLater();
      }
      function onerror() {
        infoContent;
        console.log("图片加载失败!");
      }
  
      // 历史轨迹巡航器
      pathSimplifierIns.value = new PathSimplifier({
        zIndex: 100,
        //autoSetFitView:false,
        map: map.value, //所属的地图实例
  
        getPath: function (pathData) {
          return pathData.path;
        },
        getHoverTitle: function (pathData) {
          return pathData.index;
        },
        autoSetFitView: true,
        // 巡航器样式
        renderOptions: {
          pathNavigatorStyle: {
            initRotateDegree: 0,
            width: 20,
            height: 32,
            autoRotate: true,
            lineJoin: "round",
            content: PathSimplifier.Render.Canvas.getImageContent(
              car,
              onload,
              onerror
            ),
            fillStyle: null,
            strokeStyle: null,
            lineWidth: 1,
            pathLinePassedStyle: {
              lineWidth: 6,
              strokeStyle: "#2cdf4d"
            }
          },
          // 这个会修改所有颜色
          pathLineStyle: {
            lineWidth: 6,
            strokeStyle: "#2e9c08"
          },
          pathLineHoverStyle: {
            lineWidth: 0,
            borderWidth: 0
          },
          pathLineSelectedStyle: {
            lineWidth: 6,
            borderWidth: 0,
            strokeStyle: "#2e9c08"
          },
          pathTolerance: 0,
          keyPointTolerance: -1,
          renderAllPointsIfNumberBelow: 0 //绘制路线节点,如不需要可设置为-1
        }
      });
  
      //历史轨迹巡航器设置数据
      pathSimplifierIns.value.setData([
        {
          name: "轨迹",
          path: pathList.value
        }
      ]);
      pathSimplifierIns.value.setFitView(-1);
  
      let startSpeed = speedFun(
        pathList.value[0],
        pathList.value[1],
        startPoint.intervalTime
      );
      startSpeed === 0 && (startSpeed = 0.1);
  
      //对第一条线路(即索引 0)创建一个巡航器
      navgtr.value = pathSimplifierIns.value.createPathNavigator(0, {
        loop: false, //循环播放
        speed: startSpeed * times.value //巡航速度,单位千米/小时
      });
      //构建自定义信息窗体
      let infoContent = `<p class="info-window">时间:<span>${startPoint.time} `;
      let infoWindow = new AMap.InfoWindow({
        anchor: "bottom-center",
        content: infoContent
      });
  
      infoWindow.open(map.value, pathList.value[0]);
      // 移动过程中
      navgtr.value.on("move", function () {
        playIcon.value = "resume";
        let idx = this.getCursor().idx; //走到了第几个点
        let tail = this.getCursor().tail; //至下一个节点的比例位置
        let totalIdx = idx + tail;
  
        // 计算下一个距离速度
        let point = trackList.value[idx];
        if (idx < len - 1) {
          point.nextSpeed === 0 && (point.nextSpeed = 0.1);
          navgtr.value.setSpeed(point.nextSpeed * times.value);
        }
  
        // 剩余公里数,窗体随时移动展示
        point &&
          point.time &&
          infoWindow.setContent(
            `<p class="info-window">时间:<span>${point.time}`
          );
        infoWindow.open(map.value, navgtr.value.getPosition());
        // 进度条实时展示tail
        !isOnSlider.value && (sliderVal.value = (totalIdx / len) * 100);
        // 已经播放时间
        // let sTime = (pointObj.stampTime-startStampTime)/1000;
        let sTime = parseInt(
          (((endPoint.stampTime - startPoint.stampTime) / 1000) *
            sliderVal.value) /
          100
        );
  
        passedTime.value = getTime(sTime);
        // 如果到头了,回到初始状态
        if (navgtr.value.isCursorAtPathEnd()) {
          playIcon.value = "start";
          isPlay.value = false;
          sliderVal.value = 100;
          passedTime.value = totalTime.value;
        }
      });
  
      navgtr.value.on("start resume", function () {
  
        navgtr.value._startTime = Date.now();
        navgtr.value._startDist = this.getMovedDistance();
      });
      navgtr.value.on("stop pause", function () {
        navgtr.value._movedTime = Date.now() - navgtr.value._startTime;
        navgtr.value._movedDist =
          this.getMovedDistance() - navgtr.value._startDist;
      });
    });
  }
  
  // 开始、暂停、继续等操作
  const navgControl = (action) => {
    if (action === "start") {
      sliderVal.value = 0;
      passedTime.value = "00:00:00";
      setTimeout(() => {
        navgtr.value[action]();
      }, 300);
    } else {
      navgtr.value[action]();
    }
  }
  
  //     // 格式化时间
  const 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;
  }
  const hideFormat = () => {
    return null;
  }
  // 计算两个坐标点之间的距离
  const distanceFun = (point1, point2) => {
    // point1:[longitude,latitude]
    let p1 = new AMap.LngLat(point1[0], point1[1]);
    let p2 = new AMap.LngLat(point2[0], point2[1]);
    let distance = Math.round(p1.distance(p2));
    return distance;
  }
  const speedFun = (point1, point2, time) => {
    // point1,point2:经纬度数组,time:时间,s
    let distance = distanceFun(point1, point2);
    if (distance === 0) {
      return 0;
    } else {
      let speed = distance / 1000 / (time / 60 / 60);
      // speed:km/h
      return speed;
    }
  }
  
  const drag = (isRemove) => {
    let el = document.getElementsByClassName("ivu-slider-button-wrap")[0];
    let el2 = document.getElementsByClassName("ivu-slider-wrap")[0];
  
    if (isRemove) {
      el && el.removeEventListener("mousedown", openSlider.value, false);
      document.removeEventListener("mouseup", closeSlider.value, false);
      el2 && el2.removeEventListener("click", sliderChange.value, false);
      return false;
    }
    el2.addEventListener("click", sliderChange.value, false);
    el.addEventListener("mousedown", openSlider.value, false);
    // 此处用document是因为,滑动较为随意时,mouseup可能不是作用在el上
    document.addEventListener("mouseup", closeSlider.value, false);
  }
  
  
  const openSlider = () => {
    isOnSlider.value = true;
  }
  
  const closeSlider = () => {
    isOnSlider.value = false;
  }
  
  // 修改倍速
  const changeSpeed = (item) => {
    isTimesChoose.value = false;
    times.value = item;
  }
  
  const sliderChange = (val) => {
    let newVal = typeof val === "number" ? val : sliderVal.value;
    let num = parseInt((newVal / 100) * pathList.value.length);
    let decimal =
      String((newVal / 100) * pathList.value.length).split(".")[1] || 0;
    navgtr.value.moveToPoint(num, Number("0." + decimal));
    pathSimplifierIns.value.renderLater();
  }
  
  const addMarker = (item) => {
    let 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(map.value);
  }
  
  // 新增假如当前是子组件关闭的时候判断是播放还是其他状态,防止setSpeed报错null
  const cancelsubmitfotm = () => {
    if (isPlay.value) {
      isPlay.value = false;
      navgControl("pause");
    }
    navgtr.value = null;
    drag(true);
    emits("handleqktraV2IdId", this.traV2Id)
    dialogFormVisible.value = false;
  }
  onUnmounted(() => {
    navgtr.value = ref(null);
    drag(true);
  })
  
  watch(() => sliderVal.value,
    (val) => {
      if (!isOnSlider.value) {
        return false;
      }
      sliderChange(val);
    },
    {
      deep: true,
    })
  
  </script>
  
<style>
/* 根容器样式 */
.map-outbox {
  width: 100%;
  padding: 40rpx;
  border: 1px solid #ddd;
  margin: auto;
}

/* 地图容器样式 */
#container {
  width: 100%;
  height: 50vh;
}

/* 控制条样式 */
.map-control {
  position: fixed;
  bottom: 0;
  width: 100%;
  left: 0;
  z-index: 200;
  height: 160rpx;
  line-height: 160rpx;
  color: #fff;
  background-image: linear-gradient(to top, rgba(0, 0, 0, 0.7), transparent);
  padding: 0 40rpx;
}

/* 播放按钮样式 */
.play-icon {
  font-size: 36rpx;
}

/* 进度条样式 */
.map-slider {
  display: inline-block;
  width: 45%;
  margin-left: 15rpx;
  position: relative;
  top: 28rpx;
}

/* 已播放时间样式 */
.passed-time {
  position: relative;
  top: 8rpx;
  display: inline-block;
  margin-left: 15rpx;
  font-size: 28rpx;
}

/* 倍速选择样式 */
.map-times {
  display: inline-block;
  position: relative;
  margin-left: 15rpx;
}

.map-times .times-show {
  padding: 0 10rpx;
  line-height: 48rpx;
  font-size: 26rpx;
  border: 1px solid #fff;
  border-radius: 4rpx;
  cursor: default;
}

.map-times .choose-box {
  position: absolute;
  top: -135rpx;
  left: -6rpx;
  height: 162rpx;
  transition: all 0.5s linear;
}

/* 倍速长度 */
.map-times ul {
  background: rgba(0, 0, 0, 0.7);
  padding: 10rpx;
  width: 150rpx;
  text-align: center;
  border-radius: 3rpx;
}

.map-times li {
  height: 36rpx;
  line-height: 36rpx;
  cursor: pointer;
}

.map-times li.active {
  color: #ff8533;
}

.map-times li:hover {
  font-size: 13px;
}
</style>