自定义时间轴组件

前言

开发工作中常常有一个通过启动时间轴切换地图图层切换的功能需求,但是又很难找到一个满足要求的时间轴,所以自己撸了一个,目前还有一些功能需要改进,这里先记录一下代码

代码

/**
* AnimationSlider.vue 可以播放的timeLine
* @Author ZhangJun
* @Date  2024/2/20 16:08
**/
<template><div class="animationSliderContainer flex"><a-space :size="5" style="padding: 10px;margin: auto;" align="end" direction="vertical"><slot name="operation"><a-space><a-popover content="上一个"><a-button type="primary" @click="preTickItem()" icon="step-backward" size="small"></a-button></a-popover><a-popover content="开始/暂停"><a-button type="primary" @click="onPlay()" :icon="isStartPlay?'pause':'caret-right'"size="small"></a-button></a-popover><a-popover content="下一个"><a-button type="primary" @click="nextTickItem()" icon="step-forward" size="small"></a-button></a-popover><a-popover content="重播"><a-button type="primary" @click="onReset()" icon="redo" size="small"></a-button></a-popover></a-space></slot><slot name="currentDateTime" :dateTime="getCurrentDateTime"><div :style="{color:tickColor}">{{ getCurrentDateTime }}</div></slot></a-space><div class="tickBox" ref="tickBox" :style="{height:hourTickHeight+60+'px'}"><!--过去/未来标记--><a-space size="0" align="top" class="relative text-white" :style="{left:this.nowDateTimeMarkPosition}"style="width: 0;height:0;bottom:0;"><span style="white-space: nowrap;color: #84a4de">过去</span><a-icon type="caret-left"/><div class="divider_now"></div><a-icon type="caret-right"/><span style="white-space: nowrap;color: #92d292">未来</span></a-space><a-space :size="0" align="center"><template v-for="(item,index) in getTicks"><div :key="index"><!--刻度--><div class="tick_l"><!--里面的小刻度--><template v-for="(t,i) in item.values"><div class="flex"><a-popover :key="i"><template slot="content">{{ moment(t.dateTime, 'YYYYMMDDHHmm').format('YYYY-MM-DD HH:mm') }}</template><a-space :size="0" align="end"><div class="tick_s" :style="getActiveTickItemStyle(t)"@click="onClickTickItem(t)"></div><div class="divider_sm" v-if="item.values.length-1>i"></div></a-space></a-popover></div></template><!--上面的label--><div class="divider_lg" v-if="item.label" :style="{backgroundColor: dayTickColor}"><div class="relative":style="{left:(item.label.length/2)*(-9.5)+'px',top:'-24px',whiteSpace:'nowrap',color:tickTextColor}">{{ item.label }}</div></div><!--下面的刻度提示--><div class="divider_lg" v-else><span v-if="item.tickName" class="relative":style="{left:(item.tickName.length/2)*(-9.5)+'px',bottom:`-${hourTickHeightPix}`,whiteSpace:'nowrap',color:tickTextColor}">{{item.tickName}}</span></div></div></div></template></a-space></div></div>
</template><script>
import moment from "moment";
import {InvalidNodeTypeError} from "core-js/internals/dom-exception-constants";
import BigNumber from "bignumber.js";export default {name: "AnimationSlider",props: {//此刻的时间点nowDateTime: {type: String, default: moment().format('YYYYMMDDHHmm')},precision: {type: Number, default: 0.5},//每个单位刻度代表的小时数daysSpan: {Type: Array, default: [2, 2]},//时间段的分布(前面2天,后面2天)hourly: {type: Number, default: 3},//刻度值显示的范围距离(小时)timeout: {type: Number, default: 500},//播放间隔时间tickWidth: {type: Number, default: 30},//每个刻度的widthtickHeight: {type: Number, default: 10},//每个刻度的heighttickColor: {type: String, default: 'white'},//刻度线的颜色tickFillColor: {type: String, default: '#afb9cc'},//单位刻度填充的颜色tickBgColor: {type: String, default: '#5b5d60'},//背景的颜色tickTextColor: {type: String, default: 'white'},//文字的颜色hourTickColor: {type: String, default: 'white'},//显示小时刻度的颜色hourTickHeight: {type: Number, default: 20},//显示小时刻度的heightdayTickColor: {type: String, default: '#92d292'},//显示日期刻度的颜色activeTickColor: {type: String, default: '#6a98ea'},//显示日期刻度的颜色nowTickHeight: {type: Number, default: 50},//当前时间刻度的heightnowTickColor: {type: String, default: '#6a98ea'}///当前时间刻度的color},data() {return {moment: moment,startTick: 0,startDateTime: null,endDateTime: null,totalHours: 24,//一共展示的小时activeItems: null,//处于激活状态的tickItem集合isStartPlay: false,setIntervalHandler: null,scrollInterval: null,tickWidthValue: this.tickWidth + 'px',tickHeightValue: this.tickHeight + 'px',nowDateTimeMarkPosition: {},updateNowDateTimeMarkPositionHandler: null,nowTickHeightPix: `${this.nowTickHeight}px`,hourTickHeightPix: `${this.hourTickHeight}px`}},computed: {getTicks() {let ticks = [];let current = this.startTick;let tick_l = {values: []};//起始时间let startDateTime = moment(this.startDateTime, 'YYYYMMDDHH');while (current <= this.totalHours) {current = new BigNumber(current).plus(this.precision).toNumber();if (!tick_l?.values) {tick_l.values = [];}//单元刻度表示的时间let dateTime = startDateTime.add(this.precision, 'hour');dateTime = dateTime.format('YYYYMMDDHHmm');let tickItem = {value: current, dateTime}tick_l.values = [...tick_l.values, tickItem]//如果是整数if (Number.isInteger(current)) {// tick_l.label = '0分';ticks = [...ticks, tick_l];tick_l = {values: []};}}//如果有格式化的方法就格式化刻度的数据源ticks = this.defaultFormat(ticks);return ticks;},//得到当前选择的时间getCurrentDateTime() {if (this?.activeItems?.length > 1) {let [startItem] = this?.activeItems;let endItem = this?.activeItems[this.activeItems.length - 1];let startDateTime_temp = moment(startItem.dateTime, 'YYYYMMDDHHmm').format('YYYY年MM月DD日 HH:mm');let endDateTime_temp = moment(endItem.dateTime, 'YYYYMMDDHHmm').format('YYYY年MM月DD日 HH:mm');return `${startDateTime_temp} ~ ${endDateTime_temp}`;} else if (this?.activeItems?.length === 1) {let [{dateTime}] = this?.activeItems;if (dateTime) {return moment(dateTime, 'YYYYMMDDHHmm').format('YYYY/MM/DD HH:mm');}}return '';},},methods: {//根据逐时格式化刻度数据defaultFormat(data = []) {return data.map((item, index) => {index++;let {dateTime} = [...item.values].pop();dateTime = moment(dateTime, 'YYYYMMDDHH');//逐小时的数值if (index % this.hourly === 0) {item.tickName = dateTime.format('HH') + '时';}if (dateTime.format('HH') === '00') {item.label = dateTime.format('MM月DD日');}return item;});},//动态获取tick的样式getActiveTickItemStyle(tickItem) {let isActive = this?.activeItems?.findIndex(({dateTime}) => dateTime === tickItem?.dateTime) > -1;return isActive ? {backgroundColor: this.activeTickColor} : {};},//点击tickItem事件回调onClickTickItem(tickItem) {this.activeItems = [tickItem];},clearIntervalHandler() {if (this.setIntervalHandler) {clearInterval(this.setIntervalHandler);this.setIntervalHandler = null;}this.isStartPlay = false;this.clearAutoScroll();},//刻度添加一个单位值addTickItemsValue({dateTime, value}) {if (dateTime) {dateTime = moment(dateTime, 'YYYYMMDDHHmm').add(this.precision, 'hour').format('YYYYMMDDHHmm');return {dateTime,value: value + 1}}},//刻度减少一个单位值subtractTickItemsValue({dateTime, value}) {if (dateTime) {dateTime = moment(dateTime, 'YYYYMMDDHHmm').subtract(this.precision, 'hour').format('YYYYMMDDHHmm');return {dateTime,value: value - 1}}},//回到上一个刻度preTickItem() {let preItems = this.activeItems.map((item) => {return this.subtractTickItemsValue(item);});//上一个item超过了起始时间if (preItems?.[0]?.dateTime <= this.startDateTime) {return;}this.activeItems = preItems;},//前进下一个刻度nextTickItem() {let nextItems = this.activeItems.map((item) => {return this.addTickItemsValue(item);});if (nextItems?.[0]?.dateTime > this.endDateTime) {//默认从头开始this.activeItems = [{dateTime: this.startDateTime, value: this.startTick}];this.nextTickItem();} else {this.activeItems = nextItems;}},//重新开始onReset() {this.clearAllInterval();//默认从头开始this.activeItems = [{dateTime: this.startDateTime, value: this.startTick}];this.isStartPlay = false;let days = this.daysSpan.reduce((a, b) => a + b);//一个小时表示的widthlet hourWidth = new BigNumber(1).div(this.precision).times(this.tickWidth);//这几天tick的总的widthlet sumWidth = new BigNumber(days).times(24).times(hourWidth);this.$refs.tickBox.scrollBy(-sumWidth, 0);this.onPlay();},onPlay() {this.isStartPlay = !this.isStartPlay;if (this.isStartPlay) {this.nextTickItem();let tickBoxWidth = this?.$refs?.tickBox?.offsetWidth;this.setIntervalHandler = setInterval(() => {this.nextTickItem();if (!this.scrollInterval) {this.startAutoScroll(tickBoxWidth);}//播放到最后的时候就停止if (this?.activeItems?.[0]?.dateTime === this.endDateTime) {this.clearIntervalHandler();}}, this.timeout);} else {this.clearIntervalHandler();}},//更新当前时间标记的位置updateNowDateTimeMarkPosition() {//计算当前时间跟起点时间的时间差let durationHours = moment.duration(moment().diff(moment(this.startDateTime, 'YYYYMMDDHHmmss'))).asHours();//还要加上刻度线let tickWidth = new BigNumber(this.tickWidth).plus(1).toNumber();this.nowDateTimeMarkPosition = new BigNumber(1).div(this.precision).times(tickWidth).times(durationHours).minus(43).toString() + 'px';},//开始滚动startAutoScroll(tickBoxWidth, timeout = this.timeout) {if (this?.$refs?.tickBox) {let days = this.daysSpan.reduce((a, b) => a + b);//一个小时表示的widthlet hourWidth = new BigNumber(1).div(this.precision).times(this.tickWidth);//这几天tick的总的widthlet sumWidth = new BigNumber(days).times(24).times(hourWidth);//一共拥有多少个tickBoxlet count = new BigNumber(sumWidth).div(tickBoxWidth);//还要加上刻度线let tickWidth = new BigNumber(this.tickWidth).plus(1).toNumber();timeout = new BigNumber(timeout).times(new BigNumber(1).div(count.minus(0.5)).plus(1));this.scrollInterval = setInterval(() => {this.$refs.tickBox.scrollBy(tickWidth, 0);}, timeout)}},//停止滚动clearAutoScroll() {if (this.scrollInterval) {clearInterval(this.scrollInterval);this.scrollInterval = null;}},//开始自动更新当前时间标记startUpdateNowDateTimeMark() {this.updateNowDateTimeMarkPosition();this.updateNowDateTimeMarkPositionHandler = setInterval(() => {this.updateNowDateTimeMarkPosition();}, 1000 * 60);},//停止自动更新当前时间标记clearUpdateNowDateTimeMark() {if (this.updateNowDateTimeMarkPositionHandler) {clearInterval(this.updateNowDateTimeMarkPositionHandler);this.updateNowDateTimeMarkPositionHandler = null;}},init() {//一共有多少小时this.totalHours = this.daysSpan.reduce((a, b) => a + b) * 24;let [pre, next] = this.daysSpan;//获取开始时间this.startDateTime = pre > 0 ? moment(this.nowDateTime, 'YYYYMMDD').subtract(pre, 'days').format('YYYYMMDDHHmm') : this.nowDateTime;//获取结束时间this.endDateTime = next > 0 ? moment(this.nowDateTime, 'YYYYMMDD').add(next, 'days').format('YYYYMMDDHHmm') : this.nowDateTime;//开始自动更新this.startUpdateNowDateTimeMark();},clearAllInterval() {this.clearUpdateNowDateTimeMark();this.clearIntervalHandler();this.clearAutoScroll();},},created() {this.init();},mounted() {//默认从头开始this.activeItems = [{dateTime: this.startDateTime, value: this.startTick}];},destroyed() {this.clearAllInterval();}
}
</script><style lang="less" scoped>
@borderColor: lightblue;
@tickHeight: v-bind(tickHeightValue);
@tickWidth: v-bind(tickWidthValue);
@tickColor: v-bind(tickColor);
@hourTickColor: v-bind(hourTickColor);
@tickBgColor: v-bind(tickBgColor);
@tickFillColor: v-bind(tickFillColor);
@nowTickHeight: v-bind(nowTickHeightPix);
@nowTickColor: v-bind(nowTickColor);
@hourTickHeight: v-bind(hourTickHeightPix);.animationSliderContainer {border: 1px solid @borderColor;background-color: @tickBgColor;width: 100%;overflow: hidden;/* 滚动条样式 */::-webkit-scrollbar {width: 8px; /* 设置滚动条宽度 */height: 8px; /* 设置滚动条高度 */}::-webkit-scrollbar-thumb {background-color: #999; /* 设置滑块背景色 */border-radius: 2px; /* 设置滑块边角圆角程度 */}::-webkit-scrollbar-track {background-color: #f1f1f1; /* 设置滚动条轨道背景色 */border-radius: 0; /* 设置滚动条轨道边角圆角程度 */}::-webkit-scrollbar-button {display: none; /* 不显示按钮 */}
}.tickBox {border-left: 1px solid @borderColor;overflow: auto;padding: 5px 0;
}.tick_l {display: flex;align-items: flex-end;
}.tick_s {width: @tickWidth;height: @tickHeight;background-color: @tickFillColor;
}.divider_lg {height: @hourTickHeight;width: 1px;background-color: @hourTickColor;
}.divider_sm {height: @tickHeight;width: 1px;background-color: @tickColor;
}.divider_now {height: @nowTickHeight;width: 1px;background-color: @nowTickColor;
}.flex {display: flex;
}.w-full {width: 100%;
}.text-right {text-align: right;
}.relative {position: relative;
}.text-white {color: white;
}
</style>

参数说明

  //此刻的时间点nowDateTime: {type: String, default: moment().format('YYYYMMDDHHmm')},precision: {type: Number, default: 0.5},//每个单位刻度代表的小时数daysSpan: {Type: Array, default: [2, 2]},//时间段的分布(前面2天,后面2天)hourly: {type: Number, default: 3},//刻度值显示的范围距离(小时)timeout: {type: Number, default: 500},//播放间隔时间tickWidth: {type: Number, default: 30},//每个刻度的widthtickHeight: {type: Number, default: 10},//每个刻度的heighttickColor: {type: String, default: 'white'},//刻度线的颜色tickFillColor: {type: String, default: '#afb9cc'},//单位刻度填充的颜色tickBgColor: {type: String, default: '#5b5d60'},//背景的颜色tickTextColor: {type: String, default: 'white'},//文字的颜色hourTickColor: {type: String, default: 'white'},//显示小时刻度的颜色hourTickHeight: {type: Number, default: 20},//显示小时刻度的heightdayTickColor: {type: String, default: '#92d292'},//显示日期刻度的颜色activeTickColor: {type: String, default: '#6a98ea'},//显示日期刻度的颜色nowTickHeight: {type: Number, default: 50},//当前时间刻度的heightnowTickColor: {type: String, default: '#6a98ea'}///当前时间刻度的color

效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/493491.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

flashback to timestamp 耗时

flashback pluggable database XX to timestamp to_date(2024-02-26 13:11:56,yyyy-mm-dd hh24:mi:ss); 1TB 花费2小时&#xff0c;如果做了还原点好像很快 select trunc( a.FIRST_TIME,HH24),count(*) from v$flashback_database_logfile a group by trunc( a.FIRST_TIME,…

图形系统开发实战课程:进阶篇(上)——7.图形交互操作: 视点控制与动画

图形开发学院&#xff5c;GraphAnyWhere 课程名称&#xff1a;图形系统开发实战课程&#xff1a;进阶篇(上)课程章节&#xff1a;“图形交互操作: 视点控制与动画”原文地址&#xff1a;https://www.graphanywhere.com/graph/advanced/2-7.html 第七章 图形交互操作: 视点控制与…

【精品】OnlyOffice 8.0 版本深度测评

引言 官网链接&#xff1a; ONLYOFFICE 官方网址 OnlyOffice 是一套全面的开源办公协作软件&#xff0c;旨在为用户提供强大、便捷和安全的文档处理和协作环境。最新发布的 OnlyOffice 8.0 版本带来了一系列引人瞩目的新特性和功能改进&#xff0c;进一步提升了其在功能丰富性…

BIO实战、NIO编程与直接内存、零拷贝深入辨析

BIO实战、NIO编程与直接内存、零拷贝深入辨析 长连接、短连接 长连接 socket连接后不管是否使用都会保持连接状态多用于操作频繁&#xff0c;点对点的通讯&#xff0c;避免频繁socket创建造成资源浪费&#xff0c;比如TCP 短连接 socket连接后发送完数据后就断开早期的http服…

prometheus+grafana监控nginx的简单实现

1.编译安装NGINX 加入编译安装nginx-module-vts模块,目的是为了获取更多的监控数据(虚拟主机&#xff0c;upstream等) nginx下载 http://nginx.org/download/nginx-1.20.2.tar.gz nginx-module-vts下载 https://github.com/vozlt/nginx-module-vts/archive/refs/tags/v0.2…

自动驾驶---行业发展及就业环境杂谈

进入21世纪以来&#xff0c;自动驾驶行业有着飞速的发展&#xff0c;自动驾驶技术&#xff08;L2---L3&#xff09;也逐渐落地量产到寻常百姓家。虽然最早期量产FSD的特斯拉有着深厚的技术积累&#xff0c;但是进入2010年以后&#xff0c;国内的公司也逐渐发展起来自己的自动驾…

WebSocket实现聊天

基于webSocket通信的库主要有 socket.io&#xff0c;SockJS&#xff0c;这次用的是 SockJS。 这里我们使用sockjs-client、stomjs这两个模块&#xff0c;要实现webSocket通信&#xff0c;需要后台配合&#xff0c;也使用相应的模块。 WebSocket 1、http&#xff1a;http超文…

2024-2-26-进程线程通信作业

课上代码&#xff1a; sem.h #ifndef _SEM_H_ #define _SEM_H_int open_sem(int semcount); int P(int semid,int semno); int V(int semid,int semno); int del_sem(int semid);#endif sem.c #include <myhead.h> union semun {int val;struct semid_ds *buf;unsign…

【web APIs】1、(学习笔记)有案例!

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、概念二、使用步骤1.获取DOM对象2.操作元素内容3.属性修改3.1.常用属性修改3.2.控制样式属性3.3.操作类名(className) 操作CSS3.4.操作表单元素属性3.5.自定…

【深入理解设计模式】建造者设计模式

建造者设计模式 建造者设计模式&#xff08;Builder Pattern&#xff09;是一种创建型设计模式&#xff0c;旨在通过将复杂对象的构建过程拆分成多个简单的步骤&#xff0c;使得相同的构建过程可以创建不同的表示。该模式允许您使用相同的构建过程来创建不同的对象表示。 概述…

Leetcode刷题笔记题解(C++):6. Z 字形变换

思路&#xff1a;遍历时候需要更新步进长度 到达0行的时候步进长度为1&#xff1b;到达最后一行numRows-1行的时候步进长度为-1&#xff1b;代码如下所示&#xff1a; class Solution { public:string convert(string s, int numRows) {//如果字符串长度为1或者所给行数为1 …

[c++] char * 和 std::string

1 char * 和 std::string 的区别 char * 字符串是常量字符串&#xff0c;不能修改&#xff1b;std::string 指向的字符串可以修改 实例代码如下图所示&#xff0c;s1 和 s2 均是常量字符串&#xff0c;字符串常量保存在只读数据区&#xff0c;是只读的&#xff0c;不能写&…

Unity类银河恶魔城学习记录7-9 P75 Saw spin sword源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili Sword_Skill_Controller.cs using System.Collections; using System.Col…

QT信号槽实现分析

1.宏定义 qt中引入了MOC来反射&#xff0c;编译阶段变成 MOC–>预处理–>编译–>汇编–>链接 1-1、Q_OBJECT 这个宏定义了一系列代码&#xff0c;包括元对象和处理的函数 #define Q_OBJECT \public: \QT_WARNING_PUSH \Q_OBJECT_NO_OVERRIDE_WARNING \static c…

设计模式(二)单例模式的七种写法

相关文章设计模式系列 面试的时候&#xff0c;问到许多年轻的Android开发他所会的设计模式是什么&#xff0c;基本上都会提到单例模式&#xff0c;但是对单例模式也是一知半解&#xff0c;在Android开发中我们经常会运用单例模式&#xff0c;所以我们还是要更了解单例模式才对…

汇编语言与接口技术实践——秒表

1. 设计要求 基于 51 开发板,利用键盘作为按键输入,将数码管作为显示输出,实现电子秒表。 功能要求: (1)计时精度达到百分之一秒; (2)能按键记录下5次时间并通过按键回看 (3)设置时间,实现倒计时,时间到,数码管闪烁 10 次,并激发蜂鸣器,可通过按键解除。 2. 设计思…

音视频技术-电脑连接调音台时交流声的产生与消除

当电脑&#xff08;笔记本/台式机&#xff09;声卡通过音频线与调音台&#xff08;或扩音机&#xff09;连接时&#xff0c;能听到“交流声”。有时很轻微&#xff0c;有时很明显&#xff0c;甚至干扰正常的演讲或发言。 很多时候&#xff0c;我们在台上演讲时&#xff0c;都会…

模拟、排序(归并排序)算法

模拟、排序算法 一、模拟例题1、错误票据题目信息思路题解 2、回文日期题目信息思路方法一&#xff1a;暴力做法方法二&#xff1a;优化解法 题解方法一&#xff1a;暴力求解方法二&#xff1a;优化解法 二、排序例题1、归并排序题目信息思路题解 一、模拟 例题 1、错误票据 …

springboot222学生网上选课系统的设计与实现

学生网上选课系统的设计与实现 摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统学生选课信息管理难度大&…

MDC500-16-ASEMI工业电机专用MDC500-16

编辑&#xff1a;ll MDC500-16-ASEMI工业电机专用MDC500-16 型号&#xff1a;MDC500-16 品牌&#xff1a;ASEMI 正向电流&#xff08;Id&#xff09;&#xff1a;500A 反向耐压&#xff08;VRRM&#xff09;&#xff1a;1600V 正向浪涌电流&#xff1a;600A 正向电压&a…