简易回放时间轴
简易回放时间轴
<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)!