(1)需求介绍:

该组件可查看某个设备在某10分钟内的秒级数据,点击播放按钮后,折线图的节点与提示框随进度条右移。可以点击图例关闭数据的显示,支持倍速调节,支持快进后退,支持折线图的展开收起

(2)预览图:

(3)实现思路:

  • 播放器的核心是el-slider组件,一切事件都围绕它的绑定值进行。
  • 考虑到进度条为主,折线图为次,因此需添加一层蒙版屏蔽所有来自echart的交互。
  • 监听el-slider的变量改变,依次触发echart的downplayhighlightshowTip事件,实现折线图和进度条的交互、联动
  • 考虑到只要鼠标移入echart范围内,就会影响高亮与提示框的显示,因此legend图例需要自己写,点击后改变legend-selected参数,实现数据的显隐
  • 播放、暂停、倍速调节,需要用到计时器setInterval改变el-slider的值

(4)效果展示:

  • 播放、倍速调节

  • 改变图例:

  • 拖拽进度条、快进后退

(5)实现代码:

  • html:
<template><div class="line-player"><div class="top-box"><div class="echart-wraper" :class="{'hide': hideFlag}"><div class="echart-legend"><div v-for="(item, index) in yData" :key="index" class="echart-legend-item" @click="changeShow(index)" :class="{'hide-legend': !shows[index]}"><div class="line" :style="`background: ${colors[index]}`"></div><div class="name">{{item.name}}</div></div></div><div class="echart-content"><div class="echart" id="line-player"></div><div class="echart-block"></div></div><div></div></div><div class="player-body"><div class="detail"><div>{{ present }} / 00:10:00</div><div>{{ start }} - {{ end }}</div></div><el-slider@click.native="changePlayButton('stop')"v-model="percent":max="600":format-tooltip="formatTooltip":class="{'play': playFlag}"></el-slider><div class="player-button"><div class="iconfont icon-zuo" @click="deleteSecond"></div><div class="play-button" @click="changePlayButton"><divclass="iconfont":class="playFlag ? 'icon-zanting' : 'icon-bofang'"></div></div><div class="iconfont icon-you" @click="addSecond"></div><div class="right-buttons"><div class="ratio-button" @mouseover="ratioListFlag = true" @mouseleave ="ratioListFlag = false">倍速<div class="ratio-list" :class="{'show-list': ratioListFlag}"><!-- <div class="ratio-list"> --><div class="content">  <div @click="changeRatio(2)" :class="{'highlight': ratio === 2}">2.0X</div><div @click="changeRatio(1.5)" :class="{'highlight': ratio === 1.5}">1.5X</div><div @click="changeRatio(1)" :class="{'highlight': ratio === 1}">1.0X</div><div @click="changeRatio(0.5)" :class="{'highlight': ratio === 0.5}">0.5X</div></div></div></div><div class="logout-button" @click="back"><div class="iconfont icon-tuichu"></div><div class="text">退出</div></div></div></div></div></div><div class="bottom-button" @click="changeHideButton"><div><imgsrc="@/assets/alarm/bottom-button.png":class="{ hide: hideFlag }"/></div></div></div>
</template>
  • TS:
<script lang="ts">
import { Component, Vue, Watch } from "vue-property-decorator";
import * as echarts from "echarts";@Component({name: "LinePlayer",components: {},
})
export default class extends Vue {// 计算属性// 获取已播放时长private get present(): any {var temp = this.time_to_sec1("00:00:00");temp += this.percent;return this.times1(temp);}// 获取当前播放时间点private get now(): any {var date: any = new Date(this.start);date.setSeconds(date.getSeconds() + this.percent);return this.times2(date);}// 监听@Watch("percent")onchecked(val: any) {// 根据计时器执行折线图的高亮操作this.highlightEvent(val)}// TODOtabindex = 1start = "2021-03-23 20:55:00";end = "2021-03-23 21:05:00";percent = 0;ratio = 1;playFlag = false;hideFlag = false;ratioListFlag = false;timeClock: any = null;lastIndex:any = 0;chart: any = null;xData: any = [];yData: any = [{name: "220kv副母Ua",data: [],},{name: "220kv副母Ub",data: [],},{name: "220kv副母Uc",data: [],},];colors = ["rgb(0,253,4)", "rgb(254,2,0)", "rgb(9,248,254)"];shows = [] // legend图例显隐标志// 退出事件private back(): void {this.$router.back()}// 自定义tooltip提示框private tooltipStr(value: any): string {console.log(value);var res = `<div class="line-player-tooltip-box">`;// 筛选提示框里的圆点颜色var colors: any = []for (let i = 0; i < this.shows.length; i++) {if (this.shows[i]) colors.push(this.colors[i])}for (let i = 0; i < value.length; i++) {var item = value[i]res += `<div class="item"><div class="point" style="background: ${colors[i]}"></div><div class="name">${item.seriesName}</div><div class="data">${item.data} V</div></div>`}res += '</div>'return res}// 折线图的高亮事件private highlightEvent(val: any) {// 取消高亮上个图形this.chart.dispatchAction({type: 'downplay',dataIndex: this.lastIndex});// 高亮当前图形this.chart.dispatchAction({type: 'highlight',dataIndex: val});// 显示 tooltipvar index = this.shows.findIndex(item => item === true)this.chart.dispatchAction({type: 'showTip',seriesIndex: index > -1 ? index : 0, // 如果直接用-1,会导致明明关闭了所以数据项,但是提示框还是停留在最后一次有数据的情况上dataIndex: val});this.lastIndex = val}private initEchart(): void {for (let i = 0; i < 600; i++) {this.xData.push(i);this.yData[0].data.push(130.1);this.yData[1].data.push(130.3);this.yData[2].data.push(130.5);}this.shows = this.yData.map(() => {return true});this.chart = echarts.init(document.getElementById("line-player") as HTMLDivElement);var option = {tooltip: {trigger: "axis",axisPointer: {type: "shadow",textStyle: {color: "#fff",},},// padding: 2,backgroundColor: "transparent",borderWidth: 0,extraCssText: "border-radius: 0;",confine: true,// // position: "right",formatter: (data: any) => {return this.tooltipStr(data);},},grid: {left: 28,right: 28,top: 10,bottom: 40},legend: {show: false},calculable: true,xAxis: [{type: "category",axisLine: {lineStyle: {color: 'rgba(0, 202, 253, 0.15)'},},splitLine: {show: false,},axisTick: {show: false,},axisLabel: {show: false,},data: this.xData,},],yAxis: [{type: "value",scale: true,// min: 130,// max: 131,splitLine: {// show: false,lineStyle: {color: 'rgba(0, 202, 253, 0.15)'}},axisLabel: {show: false,},axisTick: {show: false,},axisLine: {lineStyle: {color: "rgba(204,187,225,0.5)",},},},],series: [{name: this.yData[0].name,type: "line",symbolSize: 7,symbol: "circle",smooth: true,lineStyle: {color: this.colors[0],opacity: .7,width: 2},itemStyle: {color: "rgb(0,26,41)",borderColor: this.colors[0],borderWidth: 2},data: this.yData[0].data,},{name: this.yData[1].name,type: "line",symbolSize: 7,symbol: "circle",smooth: true,lineStyle: {color: this.colors[1],opacity: .7,width: 2},itemStyle: {color: "rgb(0,26,41)",borderColor: this.colors[1],borderWidth: 2},data: this.yData[1].data,},{name: this.yData[2].name,type: "line",symbolSize: 7,symbol: "circle",smooth: true,lineStyle: {color: this.colors[2],opacity: .7,width: 2},itemStyle: {color: "rgb(0,26,41)",borderColor: this.colors[2],borderWidth: 2},data: this.yData[2].data,},],};this.chart.setOption(option);// 渲染完毕后直接高亮第0个点this.$nextTick(() => {this.highlightEvent(0)})}// 改变倍速事件private changeRatio(val: any): void {this.ratioListFlag = falsethis.ratio = valclearInterval(this.timeClock);if (this.playFlag) {this.timeClock = setInterval(() => {this.percent++;}, 1000/this.ratio);}}// 是否播放playerprivate changePlayButton(res: any): void {if (res === "stop") {this.playFlag = false;} else {this.playFlag = !this.playFlag;}if (this.playFlag) {this.hideFlag = falsethis.timeClock = setInterval(() => {this.percent++;}, 1000/this.ratio);} else {clearInterval(this.timeClock);}}// 是否收起Playerprivate changeHideButton(): void {this.hideFlag = !this.hideFlag;if (this.hideFlag) {// 收起时,暂停播放器this.changePlayButton('stop')}}// 计时器的提示框private formatTooltip(val: number): any {return this.now;}// 时间戳转时分秒private times1(data: any) {var time: any = Number(data);var h = Math.floor(time / 3600);var m = Math.floor((time % 3600) / 60);var temp: any = time % 3600;var s = parseInt(temp) % 60;var hh = h < 10 ? "0" + h : h;var mm = m < 10 ? "0" + m : m;var ss = s < 10 ? "0" + s : s;return hh + ":" + mm + ":" + ss;}private time_to_sec1(time: any) {if (time !== null) {var s: any = "";var hour = time.split(":")[0];var min = time.split(":")[1];var sec = time.split(":")[2];s = Number(hour * 3600) + Number(min * 60) + Number(sec);return s;}}// 时间戳转年月日时分秒private times2(data: any) {var DateIn = new Date(data);var Year = DateIn.getFullYear(); //年var Month: any = DateIn.getMonth() + 1; //月var Day: any = DateIn.getDate(); //日var Hour: any = DateIn.getHours(); //时var Minute: any = DateIn.getMinutes(); //分var second: any = DateIn.getSeconds(); //秒Month = Month < 10 ? "0" + Month : Month;Day = Day < 10 ? "0" + Day : Day;Hour = Hour < 10 ? "0" + Hour : Hour;Minute = Minute < 10 ? "0" + Minute : Minute;second = second < 10 ? "0" + second : second;return `${Year}-${Month}-${Day} ${Hour}:${Minute}:${second}`;}private time_to_sec2(time: any) {return new Date(time).getTime();}// 快进private addSecond() {this.changePlayButton("stop");if (this.percent < 600) this.percent++;}// 后退private deleteSecond() {this.changePlayButton("stop");if (this.percent > 0) this.percent--;}// 点击改变图例事件private changeShow (index: any) {this.$set(this.shows, index, !this.shows[index])this.chart.setOption({legend: {selected: {'220kv副母Ua': this.shows[0],'220kv副母Ub': this.shows[1],'220kv副母Uc': this.shows[2]}}})this.highlightEvent(this.lastIndex)}// 销毁后清除计时器public destroyed(): void {clearInterval(this.timeClock);}public mounted(): void {this.initEchart();}
}
</script>
  • CSS:
<style lang="scss">
.line-player {position: absolute;bottom: 0;left: 0;width: 100%;// height: 443px;.top-box {// height: 414px;width: 100%;position: absolute;bottom: 29px;left: 0;.echart-wraper {width: 100%;height: 325px;background: url("~@/assets/alarm/top-background.png") no-repeat;background-size: cover;transition: all .5s ease-out;overflow: hidden;.echart-legend {width: 100%;height: 40px;display: flex;align-items: center;justify-content: center;.echart-legend-item {margin: 0 15px;display: flex;align-items: center;justify-content: center;cursor: pointer;.line {width: 20px;height: 2px;margin-right: 10px;opacity: .7;transition: all .3s ease-out;}.name {font-size: 12px;color: #fff;transition: all .3s ease-out;}}.echart-legend-item.hide-legend {.line {background: rgba(255, 255, 255, 0.6) !important;transition: all .3s ease-out;}.name {color: rgba(255, 255, 255, 0.6) !important;transition: all .3s ease-out;}}}.echart-content {width: 100%;height: 285px;position: relative;.echart {width: 100%;height: 100%;}.echart-block {width: 100%;height: 100%;position: absolute;left: 0;top: 0;z-index: 9999999;}}.line-player-tooltip-box {width: 237px;// height: 119px;background: url("~@/assets/alarm/tooltip-background.png") no-repeat;background-size: 100% 100%;margin: 0 auto;display: flex;flex-direction: column;align-content: center;justify-content: center;padding: 20px 0;box-shadow: 0 0 21px 4px rgb(0 0 0 / 80%);// margin: 15px auto;.item {display: flex;justify-content: center;align-items: center;// margin-bottom: 15px;&:not(:first-child) {margin-top: 10px;}.point {border-radius: 90%;width: 8px;height: 8px;margin-bottom: 1px;}.name {font-size: 12px;color: #fff;margin: 0 15px 0 8px;}.data {font-size: 12px;color: rgb(0, 202, 253);}}}}.echart-wraper.hide {height: 0;transition: all .5s ease-out;}.player-body {background: url("~@/assets/alarm/player-background.png") no-repeat;background-size: cover;width: 100%;height: 89px;padding: 0 28px;.detail {padding-top: 10px;display: flex;justify-content: space-between;font-size: 12px;color: rgb(0, 202, 253);}.el-slider__runway {margin: 10px 0;background-color: rgb(1, 71, 89);.el-slider__bar {background-color: rgb(4, 181, 182);}.el-slider__button {width: 10px;height: 10px;border: 0;box-shadow: 0 0 5px 2px rgb(3, 255, 255);background-color: rgb(3, 255, 255);}.hover {.el-slider__button {box-shadow: 0 0 10px rgb(3, 255, 255);}}}.play {.el-slider__button {animation: sparkling 3s infinite;animation-delay: .5s;}@keyframes sparkling {0% {box-shadow: 0 0 5px 2px rgb(3, 255, 255);}75% {box-shadow: 0 0 20px 8px rgba(3, 255, 255, 1);}100% {box-shadow: 0 0 10px rgb(3, 255, 255);}}}.player-button {margin-top: -5px;display: flex;justify-content: center;align-items: center;position: relative;.iconfont {font-size: 15px;color: #fff;cursor: pointer;}.play-button {background: url("~@/assets/alarm/play-background.png");background-size: cover;width: 37px;height: 37px;margin: 0 20px;display: flex;justify-content: center;align-items: center;cursor: pointer;.iconfont {color: rgb(24, 198, 235);padding-left: 2px;}.icon-zanting {font-size: 28px;}}.right-buttons {position: absolute;right: 0;top: 5px;display: flex;div {font-size: 12px;color: rgb(0, 202, 253);}.ratio-button {cursor: pointer;position: relative;padding-top: 10px;margin-top: -10px;.ratio-list {position: absolute;width: 75px;// height: 131px;height: 0;bottom: 25px;left:50%;transform:translate(-50%,0);z-index: 9999999;overflow: hidden;transition: all .15s ease-out;.content {position: absolute;width: 100%;bottom: 0;left: 0;padding: 5px 0;height: 131px;background: url("~@/assets/alarm/ratio-list-background.png") no-repeat;background-size: cover;display: flex;flex-direction: column;justify-content: space-around;align-items: center;div {width: 100%;position: relative;text-align: center;transition: .3s all ease-out;}div:hover {color: #fff;transition: .3s all ease-out;}div:not(:first-child) {&::after {position: absolute;content: '';width: 100%;height: 1px;background-color: rgb(1, 71, 89);top: -7px;left: 0px;}}.highlight {color: #fff;}}}.ratio-list.show-list {height: 131px;transition: all .15s ease-out;}}.logout-button {cursor: pointer;width: 58px;height: 20px;margin-left: 15px;background: url("~@/assets/alarm/logout-background.png") no-repeat;background-size: cover;display: flex;align-items: center;justify-content: center;.iconfont {margin-right: 5px;}.text {margin-bottom: 1px;}}}}}}.bottom-button {margin: 0 auto;width: 319px;height: 29px;background: url("~@/assets/alarm/bottom-button-background.png");background-size: cover;cursor: pointer;display: flex;justify-content: center;align-items: center;&:hover {div {animation: buttonRotate 1s infinite;}@keyframes buttonRotate {0% {transform: rotateY(0deg);}100% {transform: rotateY(180deg);}}}img {// width: 104px;margin-top: 5px;height: 18px;transition: all 0.3s ease-out;}.hide {transform: rotateX(180deg) translateY(0px);transition: all 0.3s ease-out;}}
}
.line-player.hide {height: 118px;
}
</style>

Do what you can, with what you have, where you are.
在你所处的位置,用你所有的资源,做你力所能及的事。(西奥多·罗斯福)

折线图播放器组件 - elementui - ehcart相关推荐

  1. Vue3实现简易的音乐播放器组件

    前言 用Vue3实现一个简易的音乐播放器组件 其效果图如下所示: 实现这个组件需要提前做的准备: 引入ElementUI 引入字节跳动图标库 一张唱见图片 将要播放的音乐上传到文件服务器上,并提供一个 ...

  2. rideo选中 vue_适用于 Vue 的播放器组件Vue-Video-Player操作

    如果h5的标签不能满足你的需求,那就用这个组件Vue-Video-Player吧,也许可以覆盖到你的需求. class="video-player vjs-custom-skin" ...

  3. 微信小程序之网易云音乐(五)- 排行详情页、歌单详情页、播放器组件开发

    微信小程序之网易云音乐(五)- 排行详情页.歌单详情页.播放器组件开发 一. 排行详情页模块 二. 歌单详情页模块 三. 播放器组件 微信小程序之网易云音乐导航 一. 排行详情页模块 rank.vue ...

  4. vue自定义音频播放组件_易于创建Vue的自定义音频播放器组件

    vue自定义音频播放组件 音频更好 (vue-audio-better) Easy to create custom audio player components for Vue.js. 易于为Vu ...

  5. Vue 自定义音乐播放器组件为H5添加背景音乐

    自定义音乐播放器组件为H5添加背景音乐: 1.创建music.vue组件 <template><div><div @click="changeOn" ...

  6. video网络页面播放器: 组件video-player-vue和video.js 常用库

    网页放置视频播放器,一般都是用video.js(h5也使用过)和它的插件vue-video-player: 正常情况下对于简单的视频 video.js够用了,支持H5和flash视频播放:  播放RT ...

  7. vue音频播放器组件

    因为原生audio 播放器太丑了 重新整理 百度综合完成了播放器, 基于element ui 组件书写的 需要的自取 <template><div class="audio ...

  8. h5的开源播放器组件

    哈喽,大家好,今天我要给大家推荐一个非常棒的看片神器,那就是[moovie].它是一款专注于电影的HTML5 播放器. 先展示一下效果,测试了一下,支持倍速播放.快捷键操作.字幕偏移即时调整,还有一些 ...

  9. 微信小程序点播插件_微信小程序音乐播放器组件

    wxml JS Page({ data:{ isPlay:false }, onLoad(){ var self = this; //监听音乐播放 wx.onBackgroundAudioPlay(( ...

最新文章

  1. java socket编写服务器_Java网络学习笔记1:用(Server)Socket编写简单的客户/服务器程序...
  2. Hook API (C++)
  3. FB面经Prepare: Dot Product
  4. 排序算法之--归并排序(好玩的一个算法o。o)快速入门
  5. Ubuntu安装过程中的问题
  6. 使用XStream注解处理复杂xml的属性及数据集合(xml转对象)
  7. Java学习(四)异常
  8. DOS命令行使用pscp实现远程文件和文件夹传输(转)
  9. html5轮播图代码效果图,JavaScript实现轮播图效果代码实例
  10. 速卖通关键词挖掘工具_SEMer如何利用工具挖掘更多的关键词?拓词技巧
  11. 如何设置excel为0的单元格内容为不显示
  12. linux系统取消时间同步,Linux系统时间不同步问题
  13. KEAZ128 时钟配置
  14. 谐音单词背诵,持续补充中......欢迎留言添加
  15. catia制作物料明细,如何在CATIA中生成产品物料清单 划重点了
  16. Adobe Photoshop CS5 标准版新增功能
  17. 整理一篇iOS经典面试题大全
  18. 招聘要求之一:是个好人
  19. vue中解决用户双击鼠标触发事件
  20. Windows 10系统环境下设置及安装共享打印机图文详解

热门文章

  1. 第七周学习周报20181022-20181028
  2. HDU 2566 统计硬币 【模拟】
  3. 世界上最大的问题,就是最大的商业机会
  4. 解读数据处理白皮书、共话核心软件创新,软博会又一主题论坛拉开帷幕!
  5. python元组创建_python新建元组
  6. 织梦网站如何设置404错误页面?
  7. 中国招聘网站调研报告
  8. 【RPO技巧拓展】————5、RPO攻击初探
  9. 论文研读 —— 6. ImageNet Classification with Deep Convolutional Neural Networks (2/3)
  10. mac mysql.sock_Mac OS 下 mysql 找不到 mysql.sock 的解决过程