自学内容网 自学内容网

简易回放时间轴

简易回放时间轴

在这里插入图片描述

<template>
  <div class="controls-container">
    <div class="controls-container__header">
      <el-date-picker v-model="search.date" :clearable="false" popper-class="dialog-detial-date" type="date"
        placeholder="请选择日期" class="data-picker" :picker-options="pickerOptions" style="width: 160px;" />
      <span class="split-line"></span>
      <el-radio-group v-model="search.speed" class="radio-group">
        <el-radio v-for="item in speedOptions" :key="item.speed" :label="item.speed">{{ item.speed }}x</el-radio>
      </el-radio-group>
      <span class="split-line"></span>
      <div :class="isPlaying ? 'btn-pause' : 'btn-play'" @click="handlePlayPause"></div>
    </div>
    <!-- 时间轴 -->
    <div id="timeLineContainer" class="time-line-container" :style="{ width: `${totalLength}px` }" @dragover="allowDrop"
      @drop="drop" @click="handleJump" @mouseover="handleMouseover" @mousemove="handleMouseover"
      @mouseout="hoverTimeVisible = false">
      <div class="scale-container">
        <div v-for="n in timeList.length - 1" :key="`calc_${n}`" class="scale-item"
          :style="{ width: `${100 / (timeList.length - 1)}%` }">
          <div class="low-scale"></div>
          <div class="low-scale"></div>
          <div class="low-scale"></div>
          <div class="low-scale"></div>
          <div class="label">
            {{ timeList[n - 1] }}
          </div>
          <div v-if="n === timeList.length - 1" class="last-label">{{ timeList[timeList.length - 1] }}</div>
        </div>
      </div>
      <div id="axleLine" class="axle-line"></div>
      <!-- 指针上方时间 -->
      <div id="currentTime" class="current-time" :style="{ left: offsetX }">
        <span v-show="tweened1.toFixed(0) < 10">0</span>
        {{ tweened1.toFixed(0) }}
        <span>:</span>
        <span v-show="tweened2.toFixed(0) < 10">0</span>
        {{ tweened2.toFixed(0) }}
        <span>:</span>
        <span v-show="tweened3.toFixed(0) < 10">0</span>
        {{ tweened3.toFixed(0) }}
      </div>
      <!-- 指针 -->
      <div id="pointer" class="pointer" :style="{ left: offsetX }" draggable="true" @dragstart="drag"></div>
      <!-- 浮动时间 -->
      <div v-if="hoverTimeVisible" class="hover-time" :style="{ left: hoverTimeOffset }">{{ hoverTime }}</div>
    </div>
  </div>
</template>

<script>
import moment from 'moment'
import gsap from 'gsap'
export default {
  data() {
    return {
      search: {
        date: moment().format('YYYY-MM-DD'),
        speed: 1,
      },
      // 是否正在播放
      isPlaying: false,
      timeLineStartTime: new Date(moment().subtract(1, 'day')),
      // 时间轴label
      timeList: [
        '00:00',
        // '01:00',
        '02:00',
        // '03:00',
        '04:00',
        // '05:00',
        '06:00',
        // '07:00',
        '08:00',
        // '09:00',
        '10:00',
        // '11:00',
        '12:00',
        // '13:00',
        '14:00',
        // '15:00',
        '16:00',
        // '17:00',
        '18:00',
        // '19:00',
        '20:00',
        // '21:00',
        '22:00',
        // '23:00',
        '24:00'
      ],
      // 时间轴总长度
      totalLength: 864,
      // 时间轴开始时间
      startHour: 0,
      // 时间轴结束时间
      endHour: 24,
      // 时间轴总时间
      totalTime: 86400,
      hoverTimeVisible: false,
      // 浮动时间偏移量
      hoverTimeOffset: '0px',
      // 指针定位偏移量
      offsetX: '0px',
      // 拖放开始坐标
      startPositionX: 468,
      // 拖放结束坐标
      endPositionX: 468,
      interval: null,
      tweened1: 0,
      tweened2: 0,
      tweened3: 0,
      speedOptions: [
        {
          speed: 1,
          interval: 1,
          dataInterval: 1,
          label: 5
        },
        {
          speed: 2,
          interval: 0.5,
          dataInterval: 1,
          label: 10
        },
        {
          speed: 4,
          interval: 0.25,
          dataInterval: 1,
          label: 20
        },
        {
          speed: 8,
          interval: 0.125,
          dataInterval: 1,
          label: 40
        }
      ], // 1倍速(1s 请求5s时间段的数据) 2倍速(0.5s请求 5s时间段的数据)  4倍速(0.25s请求 5s数据)  8(0.125s 5s数据)  16(0.125s 10s数据)
      pickerOptions: {
        disabledDate(time) {
          return time.getTime() > Date.now()
        }
      },
      selectStartTime: '', // 手动选择的时间
    }
  },

  computed: {
    currentTime() {
      const time = this.getTimeFromX(this.offsetX)
      console.log('打印时间', time)
      return time
    },
    hoverTime() {
      return this.getTimeFromX(this.hoverTimeOffset)
    },
  },

  watch: {
    currentTime(val) {
      this.heatEndTime = null
      this.oceanEndTime = null
      const [hour, minute, second] = val.split(':')
      gsap.to(this, { duration: 1, tweened1: Number(hour) || 0 })
      gsap.to(this, { duration: 1, tweened2: Number(minute) || 0 })
      gsap.to(this, { duration: 1, tweened3: Number(second) || 0 })
    },
  },

  methods: {
    allowDrop(event) {
      event.preventDefault()
    },

    drop(event) {
      console.log('drop')
      event.preventDefault()
      this.endPositionX = event.x
      const data = event.dataTransfer.getData('text')
      const target = document.getElementById(data)
      const container = document.getElementById('timeLineContainer')
      container.appendChild(target)
      this.offsetX = `${Number(this.offsetX.replace('px', '')) + this.endPositionX - this.startPositionX}px`
      this.selectStartTime = this.getTimeFromX(this.offsetX)
    },

    drag(event) {
      console.log(event.x)
      this.startPositionX = event.x
      event.dataTransfer.setData('text', event.target.id)
    },

    // 时间轴点击事件
    handleJump(e) {
      console.log('handleJump')
      this.oceanData = []
      this.heatData = []
      console.log(e.offsetX)
      let {
        target: { id },
        offsetX,
        clientX
      } = e
      offsetX = offsetX < 0 ? 0 : offsetX
      if (id === 'axleLine' || true) {
        this.offsetX = `${offsetX}px`
      }
      this.selectStartTime = this.getTimeFromX(this.offsetX)
    },

    // 时间轴鼠标悬浮事件
    handleMouseover(e) {
      let {
        offsetX
      } = e
      offsetX = offsetX < 0 ? 0 : offsetX
      this.hoverTimeOffset = `${offsetX}px`
      this.hoverTimeVisible = true
    },

    // x偏移量转时间
    getTimeFromX(x) {
      // 偏移量
      const offsetX = Number(x.replace('px', ''))
      // 偏移时间
      const offsetTime = (offsetX * this.totalTime) / this.totalLength
      const hour = parseInt(offsetTime / (60 * 60))
      const minute = parseInt((offsetTime % (60 * 60)) / 60)
      const second = parseInt((offsetTime % (60 * 60)) % 60)
      const hourFormat = this.startHour + hour < 10 ? `0${this.startHour + hour}` : this.startHour + hour
      const minuteFormat = minute < 10 ? `0${minute}` : minute
      const secondFormat = second < 10 ? `0${second}` : second
      return `${hourFormat}:${minuteFormat}:${secondFormat}`
    },

    handlePlayPause() {
      if (this.isPlaying) {

      } else {
        this.sendIntervalHandle()
      }
      this.isPlaying = !this.isPlaying
    },

    async sendIntervalHandle() {
      const speedOp = this.speedOptions.find(x => x.speed === this.search.speed)
      // await Promise.all([this.getHeatOceanData(), this.getHeatMapData()])
      this.play()
      this.interval = setTimeout(() => {
        if (this.isPlaying) {
          this.sendIntervalHandle()
        }
      }, speedOp.interval * 1000)
    },
    play() {
      const speedOp = this.speedOptions.find(x => x.speed === this.search.speed)
      // 当前时间小于时间轴终点时间
      if (this.currentTime < `${this.endHour - 1}:59:59`) {
        const newOffsetX = `${Number(this.offsetX.replace('px', '')) +
          (this.totalLength * speedOp.dataInterval) / this.totalTime}px`
        this.offsetX = newOffsetX
      } else {
        this.interval && clearInterval(this.interval)
        this.isPlaying = false
      }
    },
  }
}
</script>

<style lang="scss" scoped>
.controls-container {
  width: 924px;
  height: 140px;
  background: rgba(51, 59, 73, 0.80);
  border: 1px solid rgba(255, 255, 255, 0.30);
  border-radius: 4px;
  padding: 12px 30px 24px 30px;
  position: absolute;
  left: 470px;
  bottom: 102px;
  z-index: 99;
  display: flex;
  flex-direction: column;
  justify-content: space-between;

  &__header {
    display: flex;
    align-items: center;

    .split-line {
      width: 2px;
      height: 24px;
      background: rgba(216, 216, 216, 0.30);
      margin: 0 24px;
    }

    .btn-play,
    .btn-pause {
      width: 24px;
      height: 24px;
      background-image: url(~@/assets/images/jyScreen/playbackControls/play.png);
      background-size: 100% 100%;
      cursor: pointer;

      &:hover {
        background-image: url(~@/assets/images/jyScreen/playbackControls/play_hov.png);
      }
    }

    .btn-pause {
      background-image: url(~@/assets/images/jyScreen/playbackControls/pause.png);

      &:hover {
        background-image: url(~@/assets/images/jyScreen/playbackControls/pause_hov.png);
      }
    }
  }

  .time-line-container {
    width: 864px;
    height: 33px;
    padding: 10px 0;
    position: relative;
    pointer-events: all;
    cursor: pointer;

    .scale-container {
      display: flex;
      justify-content: space-between;

      &::after {
        content: '';
        display: block;
        width: 1px;
        height: 10px;
        background: rgba($color: #a6d2ff, $alpha: 0.4);
      }

      .scale-item {
        position: relative;
        display: flex;

        // justify-content: space-evenly;
        &::before {
          content: '';
          display: block;
          width: 1px;
          height: 10px;
          background: rgba($color: #a6d2ff, $alpha: 0.4);
        }

        .label,
        .last-label {
          font-family: HIKLDH-Number-CondensedMedium;
          font-size: 14px;
          color: rgba($color: #a6d2ff, $alpha: 0.7);
          font-weight: 500;
        }

        .label {
          position: absolute;
          left: 0;
          transform: translate(-50%, 100%);
        }

        .last-label {
          position: absolute;
          right: 0;
          transform: translate(50%, 100%);
        }
      }


      .low-scale {
        width: 25%;

        &:not(:first-child) {
          &::before {
            content: '';
            display: block;
            width: 1px;
            height: 5px;
            background: rgba($color: #a6d2ff, $alpha: 0.4);
            margin-top: 5px;
          }
        }
      }
    }

    .axle-line {
      height: 4px;
      background: rgba($color: #a6d2ff, $alpha: 0.4);
      position: relative;
      cursor: pointer;

      .yellow-axle-line {
        height: 4px;
        background: rgba($color: #ffb03d, $alpha: 0.8);
        position: absolute;
        top: 0;
      }
    }

    .pointer {
      width: 20px;
      height: 33px;
      position: absolute;
      top: 0;
      background-image: url(~@/assets/images/jyScreen/playbackControls/pointer.png);
      background-size: 100% 100%;
      z-index: 2;
      transform: translate(-50%, -6px);
      cursor: pointer;
      -webkit-backface-visibility: hidden; // 去抖动
      transition: all 1s linear;

      &:hover {
        background-image: url(~@/assets/images/jyScreen/playbackControls/pointer_hov.png);
      }
    }

    .current-time {
      width: 80px;
      height: 23px;
      position: absolute;
      top: 0;
      background-image: url(~@/assets/images/jyScreen/playbackControls/time-bg.png);
      background-size: 100% 100%;
      z-index: 2;
      transform: translate(-50%, -30px);
      display: flex;
      justify-content: center;
      align-items: center;
      font-family: HIKLDH-Number-Heavy;
      font-size: 14px;
      color: #ffffff;
      font-weight: 900;
      -webkit-backface-visibility: hidden; // 去抖动
      transition: all 1s linear;
    }

    .hover-time {
      width: 44px;
      height: 20px;
      background: rgba(26, 38, 68, 0.9);
      border: 1px solid rgba(75, 112, 188, 1);
      border-radius: 13px;
      display: flex;
      justify-content: center;
      align-items: center;
      font-family: HIKLDH-Number-CondensedMedium;
      font-size: 14px;
      color: #ffffff;
      font-weight: 500;
      position: absolute;
      top: -12px;
      transform: translateX(-50%);
    }

    div {
      pointer-events: none;
    }
  }
}
</style>
<style lang="scss">
@import '../../../style/dialog.scss';

.controls-container {

  .data-picker,
  .number-input {
    .el-input__inner {
      border: 1px solid rgba(186, 221, 255, 0.4);
      border-radius: 2px;
      background-color: transparent;
      color: #ffffff;
    }
  }

  .number-input {
    .el-input__inner {
      border-radius: 0;
      color: #ffffff;
      text-align: center;
    }
  }

  .el-input__prefix .el-input__icon,
  .el-input__suffix .el-input__icon {
    color: #ffffff;
  }

  .el-radio__input.is-checked .el-radio__inner {
    border-color: #ffffff;
  }

  .el-radio__inner {
    border-color: rgba(186, 221, 255, 0.4);
  }

  .el-radio__label {
    color: #ffffff;
  }
}
</style>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


原文地址:https://blog.csdn.net/qq_41985405/article/details/143918112

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!