uni-app map 轨迹回放

效过图:

 全部代码:

<!-- 轨迹回放 -->

<template>

  <view class="wrap" @tap="handleWrapTap">

    <map style="width: 100%; height: 100vh" id="myMap" :latitude="latitude" :longitude="longitude" :include-points="points" :polyline="polyline" :markers="markers"></map>

    <view class="tips">

      <view class="item tips_speed">{{ `当前时速${spd}km/h` }}</view>

      <view class="item tips_mile">{{

        `已行驶${mlg > 0 ? mlg / 10 : 0}km`

      }}</view>

    </view>

    <view class="bottom_wrap">

      <view class="header">

        <view class="header-content col" @click="putOut()">

          <img class="img" src="/business_module/static/location/exit-play.png" />

          <view>退出播放</view>

        </view>

        <progress style="width: 400rpx" class="item" id="progress" @tap="handleTapProgress" @activeend="handleActiveEnd" @touchmove="handletouchmove" @touchstart="handletouchstart" @touchend="handletouchend" :active="true" active-mode="forwards" :percent="percent" stroke-width="6" duration="10" />

        <view class="header-content col">

          <view class="progress">

            <view id="group" class="btn_group" v-if="showGroup">

              <image id="group1" @tap="speedMove" class="img speed mb20" mode="aspectFit" src="/business_module/static/location/add-speed.png" />

              <image id="group2" @tap="reduceMove" class="img speed mb20" mode="aspectFit" src="/business_module/static/location/reduce-speed.png" />

              <image id="group3" @tap="!startMove ? startMoveCar() : stopMove()" class="img" mode="aspectFit" :src="

                  !startMove

                    ? '/business_module/static/location/start-icon.png'

                    : '/business_module/static/location/stop-icon.png'

                " />

            </view>

            <image id="image" @tap="handleStartMove" v-else class="img_start" mode="aspectFit" :src="

                !startMove

                  ? '/business_module/static/location/start-icon.png'

                  : '/business_module/static/location/stop-icon.png'

              " />

          </view>

          <view>开始播放</view>

        </view>

      </view>

      <uni-segmented-control :current="current" :values="items" style-type="text" active-color="#0173FF" @clickItem="onClickItem" />

      <view class="progress_wrap">

        <uni-datetime-picker v-model="datetimerange" type="datetimerange" rangeSeparator="至" />

      </view>

      <view class="bottom">

        <view class="average_speed">

          <view class="value">{{ spd }}</view>

          <view class="label">平均速度(km/h)</view>

        </view>

        <view class="average_speed">

          <view class="value">{{ mlg > 0 ? mlg / 10 : 0 }}</view>

          <view class="label">总里程(km)</view>

        </view>

      </view>

    </view>

  </view>

</template>

<script>

  import store from "@/store/index"

  import common from "@/utils/common"

  import date from "@/utils/date"

  export default {

    data() {

      return {

        pwd: '', // 隐私密码

        datetimerange: [], // 搜索时间范围date.currentDate(), date.currentDate()

        // 车辆所有数据

        carData: {

          //  路线点

          track: [],

          // 车辆信息

          vehicle_info: {

            license_plate_number: "无",

            start_time: "2021-04-06 00:00:00",

            arrive_time: "2021-04-06 09:32:33",

          },

        },

        carInfo: null,

        percent: 0, // 进度条百分比

        showGroup: false,

        // 搜索条件

        formData: {

          license: "",

          startTime: "",

          endTime: "",

        },

        // 中心经纬度

        latitude: "",

        longitude: "",

        //   标记点

        markers: [],

        posi: {

          latitude: 0,

          longitude: 0,

          iconPath: "../../static/images/brand.png",

          callout: {

            content: "ssss", // 车牌信息

            display: "BYCLICK",

            fontWeight: "bold",

            color: "#5A7BEE", //文本颜色

            fontSize: "12px",

            bgColor: "#ffffff", //背景色

            padding: 5, //文本边缘留白

            textAlign: "center",

          },

          label: {

            content: 'dddd',

            color: '#666666',

            fontSize: '12',

            bgColor: '#ffffff',

            padding: 2,

            borderRadius: 4

          },

          anchor: {

            x: 0.5,

            y: 0.6,

          },

          width: 40,

          height: 40,

          id: 9,

        },

        //   线数据

        polyline: [{

          points: [],

          color: "#3591fc",

          arrowLine: true, //带箭头的线

          width: 4,

        }, ],

        lineArr: [], // 所有轨迹点数组

        points: [],

        timer: null,

        width: "",

        startX: "",

        spd: 0,

        mlg: 0,

        gtm: "",

        tipsDate: null, // 日期提示

        wait: 50,

        wait2: 50,

        iNum: 0, // 当前运动点在所有轨迹点数组的下标

        startMove: false, // 开始移动

        mapContext: null,

        clientX_start: 0,

        clientX_end: 0,

        posi_x: 0,

        current: 0,

        items: ["今天", "昨天", "本周", "本月", "自定义"],

      }

    },

    computed: {

      currentDevice: () => store.state.device.currentDevice,

    },

    watch: {

      datetimerange(newval) {

        // 如果选择自定, 必须先选择时间再查询

        if (!newval || !newval.length) {

          return

        }

        this.getData()

      },

      // 车辆当前时间点

      gtm: {

        handler() {

          if (this.gtm) {

            this.tipsDate = {

              date: `${this.gtm[0].substring(4).substring(0, 2)}-${this.gtm[0].substring(4).substring(2)}`,

              // time: `${this.gtm[1].substring(0, 2)}:${this.gtm[1].substring(2,4)}:${this.gtm[1].substring(4)}`,

            }

          }

        },

        deep: true,

        immediate: true,

      },

    },

    methods: {

      onClickItem(e) {

        this.current = e.currentIndex

        // 选择时间段

        this.setTime()

      },

      handletouchmove(e) {

        this.startMove = false

        let currentX = e.touches[0].pageX

        let currentY = e.touches[0].pageY

        let tx = currentX - this.lastX

        let ty = currentY - this.lastY

        let text = ""

        //左右方向滑动

        if (Math.abs(tx) > Math.abs(ty)) {

          if (tx < 0) {

            text = "向左滑动"

          } else if (tx > 0) {

            text = "向右滑动"

          }

        }

        //上下方向滑动

        else {

          if (ty < 0) {

            text = "向上滑动"

          } else if (ty > 0) {

            text = "向下滑动"

          }

        }

        //将当前坐标进行保存以进行下一次计算

        this.lastX = currentX

        this.lastY = currentY

        this.text = text

        this.clientX_end = currentX

      },

      handletouchstart(e) {

        this.clientX_start = e.touches[0].pageX

      },

      handletouchend(e) {

        uni.showLoading({

          title: "加载中",

        })

        // 清楚定时器

        this.startMove = false

        clearInterval(this.timer)

        this.timer = null

        let endX = parseInt(e.detail.x)

        let x = parseInt(this.clientX_end - this.clientX_start)

        this.posi_x += parseInt(this.clientX_end - this.clientX_start)

        this.posi_x = this.posi_x > 0 ? this.posi_x : 0

        // 点击进度条 设置进度

        this.percent = this.posi_x > 0 ? (this.posi_x / this.width).toFixed(2) * 100 : 0

        // 获取当前进度节点对应的  经纬度数据

        let index = this.posi_x > 0 ? parseInt((this.posi_x / this.width) * this.lineArr.length) : 0

        index = index > this.lineArr.length ? this.lineArr.length - 1 : index

        let posi = {

          ...this.posi,

          latitude: this.lineArr[index].lat ? this.lineArr[index].lat : 0,

          longitude: this.lineArr[index].lng ? this.lineArr[index].lng : 0,

        }

        this.$set(this.markers, 1, posi)

        this.spd = this.lineArr[index].spd

        this.mlg = this.lineArr[index].mlg

        this.gtm = this.lineArr[index].gtm.split("/")

        this.iNum = parseInt(this.percent / (100 / this.lineArr.length))

        setTimeout(function() {

          uni.hideLoading()

        }, 1000)

      },

      // handleChange() {

      //   clearInterval(this.timer)

      //   uni.navigateTo({

      //     url: "/pages/car/carList",

      //   })

      // },

      // 点击 控制标签(开始、加速、减速)以外的部分就隐藏控制标签

      handleWrapTap(e) {

        let arr = ["group", "group1", "group2", "group3", "image"]

        let isInclude = arr.includes(e.target.id)

        this.showGroup = isInclude

      },

      // 点击进度条

      handleTapProgress(e) {

        // 清楚定时器

        this.startMove = false

        clearInterval(this.timer)

        let endX = parseInt(e.detail.x)

        let x = endX - this.startX

        // 点击进度条 设置进度

        this.percent = (x / this.width).toFixed(2) * 100

        this.posi_x = this.percent * (this.width / 100)

        // 获取当前进度节点对应的  经纬度数据

        let index = parseInt((x / this.width) * this.lineArr.length)

        index = index > this.lineArr.length ? this.lineArr.length - 1 : index

        let posi = {

          ...this.posi,

          latitude: this.lineArr[index].lat,

          longitude: this.lineArr[index].lng,

        }

        this.$set(this.markers, 1, posi)

        this.spd = this.lineArr[index].spd

        this.mlg = this.lineArr[index].mlg

        this.gtm = this.lineArr[index].gtm.split("/")

        this.iNum = parseInt(this.percent / (100 / this.lineArr.length))

      },

      // 播放完毕

      handleActiveEnd(e) {},

      // 点击开始图标

      handleStartMove() {

        this.showGroup = true

        this.startMoveCar()

      },

      startMoveCar() {

        // common.toast("开始播放")

        this.startMove = true

        this.start()

      },

      // 退出播放

      putOut() {

        this.iNum = 0

        this.percent = 0

        this.startMove = false

        clearInterval(this.timer)

        const currentPoint = this.lineArr[0]

        // 退出播放, 将车辆图标平移到起始点

        this.mapContext.translateMarker({

          // 平移marker, 带动画

          markerId: 9,

          destination: {

            longitude: currentPoint.lng,

            latitude: currentPoint.lat,

          },

          autoRotate: true,

          // rotate: rotate, // 传入角度直接报错

          duration: 200,

          animationEnd: function() {

            this.spd = currentPoint.spd

            this.mlg = currentPoint.mlg

            this.gtm = currentPoint.gtm.split("/")

          }.bind(this),

          fail(e) {

            console.log(e, "平移marker 失败")

          },

        })

      },

      // 暂停播放

      stopMove() {

        this.startMove = false

        clearInterval(this.timer)

        // this.iNum = 1

        // common.toast("暂停播放")

      },

      // 加速播放

      speedMove() {

        if (this.wait2 / this.wait === 8) {

          common.toast(`当前播放速度为×8,以达到最大,无法再加速`)

        } else {

          clearInterval(this.timer)

          this.startMove = false

          this.wait = this.wait / 2

          common.toast(`当前播放速度为×${this.wait2 / this.wait}`)

          this.startMove = true

          this.start()

        }

      },

      // 减速播放

      reduceMove() {

        if (this.wait2 / this.wait === 0.25) {

          common.toast(`当前播放速度为0.25,以达到最小,无法再减速`)

        } else {

          clearInterval(this.timer)

          this.startMove = false

          this.wait = this.wait * 2

          common.toast(`当前播放速度为×${this.wait2 / this.wait}`)

          this.startMove = true

          this.start()

        }

      },

      // 开始播放

      start() {

        clearInterval(this.timer)

        this.timer = null

        this.mapContext = uni.createMapContext("myMap", this)

        if (!this.lineArr[this.iNum]) {

          return

        }

        const long = this.lineArr[this.iNum].lng

        const lat = this.lineArr[this.iNum].lat

        const rotate = parseInt(this.lineArr[this.iNum].agl)

        this.startMove ?

          (this.timer = setInterval(() => {

            this.$set(

              this.posi.label,

              "content",

             '[' + this.carInfo.license_plate_number + ']' + this.lineArr[this.iNum].gtm

            )

            this.startMove ?

              this.mapContext.translateMarker({

                // 平移marker, 带动画

                markerId: 9,

                destination: {

                  longitude: long,

                  latitude: lat,

                },

                autoRotate: true,

                // rotate: rotate, // 传入角度直接报错

                duration: 200,

                animationEnd: function() {

                  this.spd = this.lineArr[this.iNum].spd

                  this.mlg = this.lineArr[this.iNum].mlg

                  this.gtm = this.lineArr[this.iNum].gtm.split("/")

                  this.percent = (100 / this.lineArr.length) * this.iNum

                  this.posi_x = this.percent * (this.width / 100)

                  if (this.iNum === this.lineArr.length - 1) {

                    this.percent = 100

                    clearInterval(this.timer)

                  }

                  this.iNum++

                  this.start()

                }.bind(this),

                fail(e) {

                  console.log(e, "平移marker 失败")

                },

              }) :

              ""

            clearInterval(this.timer)

          }, this.wait)) :

          ""

      },

      // 设置 起始、终点 标记点

      setMarkers() {

        this.$set(this.posi, "latitude", this.lineArr[0].lat)

        this.$set(this.posi, "longitude", this.lineArr[0].lng)

        this.spd = this.lineArr[0].spd

        this.mlg = this.lineArr[0].mlg

        this.gtm = this.lineArr[0].gtm.split("/")

        this.points = []

        // this.lineArr.forEach((v) => {

        //   this.points.push({

        //     latitude: v.lat,

        //     longitude: v.lng,

        //   })

        // })

        this.markers = [{

            latitude: this.lineArr[0].lat,

            longitude: this.lineArr[0].lng,

            iconPath: "/business_module/static/location/begin.png",

            width: 21,

            height: 21,

            id: 8,

          },

          {

            ...this.posi,

          },

          {

            latitude: this.lineArr[this.lineArr.length - 1].lat,

            longitude: this.lineArr[this.lineArr.length - 1].lng,

            iconPath: "/business_module/static/location/end.png",

            width: 21,

            height: 21,

            id: 10,

          },

        ]

      },

      // 设置  路线

      setPolyline() {

        if (!this.lineArr || !this.lineArr.length) {

          return

        }

        this.polyline[0].points.splice(0, this.polyline[0].points.length)

        this.lineArr.forEach((line) => {

          this.polyline[0].points.push({

            longitude: line.lng,

            latitude: line.lat,

          })

        })

      },

      async getTrajectory() {

        // 轨迹数据

        const param = {

          deviceId: this.currentDevice.deviceId,

          startTime: this.datetimerange && this.datetimerange[0],

          endTime: this.datetimerange && this.datetimerange[1],

          checkFilter: false,

          pwd: this.pwd

        }

        const res = await this.$store.dispatch("device/getTrajectory", param)

        if (!res.success) {

          this.$tips.error(res.respMag)

          return

        }

        if (res.content && res.content.listCheck.length > 0) {

          // 经纬度坐标系转换

          const data = res.content.listCheck

          data.forEach((it) => {

            const newd = common.transform(it.lng, it.lat)

            it.lng = newd[0]

            it.lat = newd[1]

            it.spd = it.speed

            it.gtm = it.gpsTime

            it.mlg = 0

          })

          this.carData.track = data

        } else {

          this.$tips.info('该时间段没有轨迹数据')

          this.carData.track.splice(0, this.carData.track.length)

          this.carData.track.push({

            agl: 0,

            gtm: date.currentPosDateTime(),

            hgt: 0,

            lat: this.currentDevice.lat,

            lng: this.currentDevice.lon,

            lon: null,

            mlg: 0,

            spd: 0,

          }, {

            agl: 0,

            gtm: date.currentPosDateTime(),

            hgt: 0,

            lat: this.currentDevice.lat,

            lng: this.currentDevice.lon,

            lon: null,

            mlg: 0,

            spd: 0,

          })

        }

      },

      // 获取车辆轨迹数据

      async getData(data) {

        await this.getTrajectory()

        if (this.currentDevice && this.currentDevice.deviceId) {

          this.carData.vehicle_info.license_plate_number = this.currentDevice.carnum

        }

        // 获取后台数据

        this.lineArr = this.carData.track

        this.carInfo = this.carData.vehicle_info

        this.carInfo.start_time = this.carInfo.start_time.substr(5)

        this.carInfo.arrive_time = this.carInfo.arrive_time.substr(5)

        if (this.carInfo.license_plate_number) {

          this.carInfo.license = this.carInfo.license_plate_number

        }

        console.log(this.carInfo, this.carData.vehicle_info, 'ddddd', this.currentDevice)

        // 设置  中心经纬度

        this.latitude = this.lineArr[0].lat

        this.longitude = this.lineArr[0].lng

        // 设置车牌号

        this.$set(

          this.posi.label,

          "content",

          this.carInfo.license_plate_number + ''

        )

        // 设置初始标记点 起点 终点

        this.setMarkers()

        this.setPolyline()

      },

      setTime() {

        switch (this.current) {

          case 0:

            this.datetimerange = [

              date.addDay(-1).split(" ")[0] + ' 00:00:00',

              date.currentDate(),

            ]

            break

          case 1:

            this.datetimerange = [

              date.addDay(-2).split(" ")[0] + ' 00:00:00',

              date.addDay(-1).split(" ")[0] + ' 00:00:00',

            ]

            break

          case 2:

            this.datetimerange = [

              date.currentWeekFirstDay(),

              date.currentWeekLastDay(),

            ]

            break

          case 3:

            this.datetimerange = [

              date.currentMonthFirstDay(),

              date.currentMonthLastDay(),

            ]

            break

          case 4:

            this.datetimerange = []

            break

        }

        // console.log(this.datetimerange, "----")

      },

    },

    async mounted() {

      this.setTime()

      // 获取progress进度条的长度

      const query = uni.createSelectorQuery().in(this)

      query

        .select("#progress")

        .boundingClientRect((data) => {

          this.width = data.width

          this.startX = data.left

        })

        .exec()

      console.log(this.width, this.startX, '进度条的长和款')

    },

    onLoad(query) {

      this.pwd = (query && query.pwd) || ''

    },

  }

</script>

<style lang="scss" scoped>

  .tips {

    position: absolute;

    top: 20%;

    left: 30rpx;

    .mr10 {

      margin-right: 10rpx;

    }

    .item {

      height: 50rpx;

      width: 255rpx;

      background: #ffffff;

      border-radius: 50rpx;

      margin-bottom: 20rpx;

      font-weight: bold;

      font-size: 26rpx;

      line-height: 50rpx;

      text-align: center;

      color: #5a7bee;

    }

  }

  .bottom_wrap {

    position: absolute;

    bottom: 0rpx;

    width: 100%;

    background: #fff;

    // padding: 30rpx;

    box-sizing: border-box;

    height: 410rpx;

    .header {

      display: flex;

      justify-content: space-between;

      height: 100rpx;

      padding: 0 60rpx;

      .header-content {

        align-items: center;

        justify-content: center;

        font-size: 22rpx;

      }

      .img {

        width: 40rpx;

        height: 40rpx;

        // margin-bottom: 40rpx;

      }

      .license {

        font-weight: bold;

        font-size: 34rpx;

        line-height: 48rpx;

        color: #000000;

      }

      .change {

        font-size: 34rpx;

        line-height: 48rpx;

        color: #5a7bee;

      }

    }

    .flex {

      display: flex;

      font-size: 24rpx;

      line-height: 34rpx;

      color: #888888;

    }

    .progress_wrap {

      margin: 30rpx 0 10rpx;

      .flex {

        display: flex;

        justify-content: space-between;

        font-weight: bold;

        font-size: 24px;

        line-height: 34px;

        padding-left: 100rpx;

        color: #000000;

      }

    }

    .progress {

      display: flex;

      position: relative;

      // padding-left: 100rpx;

      // margin-top: 50rpx;

      width: 56rpx;

      height: 56rpx;

      .img_start {

        width: 56rpx;

        height: 56rpx;

        position: absolute;

        left: 0;

        bottom: 0rpx;

      }

      .btn_group {

        display: flex;

        flex-direction: column;

        align-items: center;

        position: absolute;

        left: 0;

        bottom: 0rpx;

        padding: 20rpx 10rpx;

        background: #ffffff;

        box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.25);

        border-radius: 50rpx;

        .img {

          width: 56rpx;

          height: 56rpx;

          // margin-bottom: 40rpx;

        }

        .mb20 {

          margin-bottom: 40rpx;

        }

        .speed {

          width: 43rpx;

          height: 36rpx;

        }

      }

    }

    .bottom {

      display: flex;

      margin-bottom: 40rpx;

      .average_speed {

        display: flex;

        flex-direction: column;

        justify-content: space-between;

        width: 50%;

        .value {

          width: 100%;

          text-align: center;

          // font-weight: bold;

          font-size: 34rpx;

          line-height: 48rpx;

          color: #333333;

        }

        .label {

          width: 100%;

          text-align: center;

          font-weight: normal;

          font-size: 26rpx;

          line-height: 36rpx;

          color: #000000;

        }

      }

    }

  }

</style>

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值