2.在 Vue 3 中使用 ECharts 实现动态时间轴效果

在前端开发中,时间轴(Timeline)是一种常见且有效的方式来展示时间相关的数据。在本篇文章中,我们将展示如何在 Vue 3 项目中使用 ECharts 创建一个具有动态时间范围的时间轴,并添加了今日时间的标记以及通过按钮来前进和后退调整时间范围的功能。

前言

时间轴的可视化是展示与时间相关信息的重要方式,常常用于展示事件、任务进度、数据变化等。在这篇文章中,我们将实现一个交互式的时间轴,支持动态的时间范围选择、显示今日时间,并且通过前后按钮来调整时间范围。

主要功能

  • 显示具有时间段的自定义时间轴。
  • 动态更新 X 轴的时间范围。
  • 显示今日时间。
  • 使用按钮进行前进和后退的时间范围调整。

效果图

1. 安装必要的依赖

首先,确保你的 Vue 3 项目已经安装了 ECharts。如果没有安装,可以通过以下命令安装:

npm install vue@next npm install echarts

如果你还没有创建 Vue 3 项目,可以使用 Vue CLI 创建一个新的项目:

npm install -g @vue/cli vue create vue-echarts-timeline

然后选择 Vue 3 配置。

2. 创建 Vue 3 组件

在组件中,我们将使用 ECharts 的 custom 类型来绘制时间轴。以下是实现的基本步骤和代码。

2.1 完整代码

script setup 中,我们将初始化 ECharts,并根据时间段数据渲染时间轴。X 轴使用动态的时间范围,并且会在图表中标记今日时间。

<!--* @Author: 彭麒* @Date: 2024/12/24* @Email: 1062470959@qq.com* @Description: 此源码版权归吉檀迦俐所有,可供学习和借鉴或商用。-->
<template><div class="content"><button class="back-button" @click="goBack">返回</button><div class="font-bold text-[24px]">在Vue3中使用Echarts实现时间轴效果</div><div class="mt-[202px] px-10"><div class="w-full mx-auto p-4"><div class="relative"><!-- Timeline Bar --><div ref="chartContainer" class="w-full h-[200px]"></div><button@click="navigatePrev"class="absolute left-0 top-1/2 -translate-y-1/2 -translate-x-12 bg-white rounded-full p-2 shadow-lg hover:bg-gray-50"><svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-gray-600" fill="none" viewBox="0 0 24 24"stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/></svg></button><button@click="navigateNext"class="absolute right-0 top-1/2 -translate-y-1/2 translate-x-12 bg-white rounded-full p-2 shadow-lg hover:bg-gray-50"><svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-gray-600" fill="none" viewBox="0 0 24 24"stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg></button></div></div></div></div>
</template>
<script setup lang="ts">
import {onMounted, ref, onUnmounted} from 'vue'
import {useRoute} from 'vue-router'
import * as echarts from 'echarts'
import type {EChartsOption} from 'echarts'const chartContainer = ref<HTMLElement | null>(null)
let chart: echarts.ECharts | null = null
const route = useRoute()
const id = route.query.idonUnmounted(() => {chart?.dispose()window.removeEventListener('resize', handleResize)
})/*** 处理窗口大小变化*/
const handleResize = () => {chart?.resize()
}
/*** 循环颜色*/
const colors = ['#ECECEC', '#C192EB', '#92D8EB', '#92EBB1', '#EB9692', '#EB92BA']
const getRandomColor = (num: number) => {return colors[num % colors.length]
}
let clickedSegmentIndex: { seriesIndex: number; dataIndex: number } | null = null
let transformedMockList: { name: string; segments: { start: number; end: number; color: string }[] }[] = []
const currentMin = ref(new Date().getTime() - 90 * 24 * 60 * 60 * 1000) // 3 months ago
const currentMax = ref(new Date().getTime() + 90 * 24 * 60 * 60 * 1000) // 3 months from now
const initChart = () => {if (!chartContainer.value) returnchart = echarts.init(chartContainer.value)const todayTimestamp = Date.now()const option: EChartsOption = {tooltip: {trigger: 'item',formatter: (params: any) => {const start = formatDate(params.data[0])const end = formatDate(params.data[1])return `时间段:${start} - ${end}`},},dataZoom: [{show: true,realtime: true,bottom: 20,},],grid: {left: 50,right: 50,},xAxis: {type: 'time',min: currentMin.value,max: currentMax.value,axisLabel: {formatter: (value: number) => {const date = new Date(value)const year = date.getFullYear()const month = String(date.getMonth() + 1).padStart(2, '0')const day = String(date.getDate()).padStart(2, '0')return `${year}-${month}-${day}`},},},yAxis: {type: 'category',data: transformedMockList.map((item) => item.name || '时间线'),axisLine: {show: true},axisTick: {show: true},},series: transformedMockList.map((category, seriesIndex) => ({name: category.name || '时间线',type: 'custom',renderItem: (params: any, api: any) => {const segment = category.segments[params.dataIndex]const start = api.coord([segment.start, params.seriesIndex])const end = api.coord([segment.end, params.seriesIndex])const yOffset =clickedSegmentIndex && clickedSegmentIndex.seriesIndex === seriesIndex && clickedSegmentIndex.dataIndex === params.dataIndex ? -10 : 0return {type: 'rect',shape: {x: start[0],y: start[1] - 15 + yOffset,width: Math.max(end[0] - start[0], 1),height: 30,},style: {fill: segment.color,},}},data: category.segments.map((segment) => [segment.start, segment.end]),markLine: {data: [{xAxis: todayTimestamp,label: {formatter: '今天',position: 'end',},lineStyle: {color: 'red',type: 'solid',},tooltip: {formatter: () => {const date = new Date(todayTimestamp)const year = date.getFullYear()const month = String(date.getMonth() + 1).padStart(2, '0')const day = String(date.getDate()).padStart(2, '0')const hours = String(date.getHours()).padStart(2, '0')const minutes = String(date.getMinutes()).padStart(2, '0')const seconds = String(date.getSeconds()).padStart(2, '0')return `时间段:${year}-${month}-${day} ${hours}:${minutes}:${seconds}`},},},],},})),}chart.setOption(option)chart.on('click', (params: any) => {clickedSegmentIndex = {seriesIndex: params.seriesIndex, dataIndex: params.dataIndex}const segment = transformedMockList[params.seriesIndex].segments[params.dataIndex]ruleForm.value.start = segment.startruleForm.value.end = segment.endchart.setOption(option)})
}/*** 获取数据*/
const getList = async () => {transformedMockList = [{name: '',segments: [{id: 1,start: 1733044053000,end: 1733303253000,color: getRandomColor(1),},{id: 2,start: 1734167253000,end: 1735031253000,color: getRandomColor(2),},{id: 3,start: 1735722453000,end: 1736240853000,color: getRandomColor(3),},{id: 4,start: 1736244453000,end: 1736503653000,color: getRandomColor(4),},{id: 5,start: 1736676453000,end: 1739354853000,color: getRandomColor(5),},{id: 6,start: 1739527653000,end: 1771063653000,color: getRandomColor(6),},]},]updateChartView()
}
/*** 更新图表视图*/
const updateChartView = () => {if (!chart) returnchart.setOption({xAxis: {min: currentMin.value,max: currentMax.value,},series: transformedMockList.map((category) => ({name: category.name || '时间线',type: 'custom',renderItem: (params: any, api: any) => {const segment = category.segments[params.dataIndex]const start = api.coord([segment.start, params.seriesIndex])const end = api.coord([segment.end, params.seriesIndex])return {type: 'rect',shape: {x: start[0],y: start[1] - 15,width: Math.max(end[0] - start[0], 1), // Ensure width is at least 1 pixelheight: 30,},style: {fill: segment.color,},}},data: category.segments.map((segment) => [segment.start, segment.end]),})),})
}/*** 格式化日期* @param dateString* @param type*/
const formatDate = (timestamp: number) => {const date = new Date(timestamp)const year = date.getFullYear()const month = String(date.getMonth() + 1).padStart(2, '0')const day = String(date.getDate()).padStart(2, '0')const hours = String(date.getHours()).padStart(2, '0')const minutes = String(date.getMinutes()).padStart(2, '0')const seconds = String(date.getSeconds()).padStart(2, '0')return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
}/*** 导航到上一个日期范围*/
const navigatePrev = () => {const newMin = new Date(currentMin.value)newMin.setMonth(newMin.getMonth() - 3)currentMin.value = newMin.getTime()const newMax = new Date(currentMax.value)newMax.setMonth(newMax.getMonth() - 3)currentMax.value = newMax.getTime()getList()
}
/*** 导航到下一个日期范围*/
const navigateNext = () => {const newMin = new Date(currentMin.value)newMin.setMonth(newMin.getMonth() + 3)currentMin.value = newMin.getTime()const newMax = new Date(currentMax.value)newMax.setMonth(newMax.getMonth() + 3)currentMax.value = newMax.getTime()getList()
}
onMounted(() => {getList().then(() => {initChart()})window.addEventListener('resize', handleResize)if (id) {getMerInfo()}
})
</script><style scoped lang="scss">
.blue {color: #0177fb !important;border-bottom: 2px solid #0177fb;
}.btn {@apply text-[#757575] text-[14px] cursor-pointer h-[28px];
}
</style>

2.2 功能说明

  • 今日时间标记:我们通过 markLine 在图表上添加了一条红色的竖线,表示当前的日期。每次鼠标悬停在竖线时,会显示今天的具体时间。
  • 动态时间范围:X 轴的时间范围是动态的,我们使用 currentMincurrentMax 变量来控制时间的范围,并通过前进(navigatePrev)和后退(navigateNext)按钮来更新范围。
  • 前进/后退按钮:按钮可以分别将时间范围前后移动三个月,通过 setMonth() 方法动态调整 minmax 的值。

3. 总结

在这篇文章中,我们展示了如何在 Vue 3 中结合 ECharts 实现一个动态的时间轴效果。通过 ECharts 的 custom 类型、X 轴动态范围的控制以及前进后退按钮的交互,我们能够为用户提供一个灵活且直观的时间轴展示方式。希望这篇教程能为你的项目提供帮助,并且你能够根据自己的需求进一步定制和扩展功能。


4. 参考链接

  • ECharts 官方文档
  • Vue 3 官方文档

以上就是关于如何在 Vue 3 中使用 ECharts 实现动态时间轴效果的详细教程。

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

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

相关文章

Android修行手册 - 移动端几种常用动画方案对比

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

Java日志框架:log4j、log4j2、logback

文章目录 配置文件相关1. properties测试 2. XMl使用Dom4j解析XML Log4j与Log4j2日志门面 一、Log4j1.1 Logges1.2 Appenders1.3 Layouts1.4 使用1.5 配置文件详解1.5.1 配置根目录1.5.2 配置日志信息输出目的地Appender1.5.3 输出格式设置 二、Log4j22.1 XML配置文件解析2.2 使…

《信管通低代码信息管理系统开发平台》Linux环境安装说明

1 简介 信管通低代码信息管理系统应用平台提供多环境软件产品开发服务&#xff0c;包括单机、局域网和互联网。我们专注于适用国产硬件和操作系统应用软件开发应用。为事业单位和企业提供行业软件定制开发&#xff0c;满足其独特需求。无论是简单的应用还是复杂的系统&#xff…

HTTPS协议原理与CA认证

目录 引言 HTTPS 是什么 1.什么是"加密" 2. 为什么要加密 3. 常⻅的加密⽅式 对称加密 ⾮对称加密 4.数据摘要 && 数据指纹 5. 数字签名 HTTPS 的⼯作过程探究 ⽅案 1 - 只使⽤对称加密 ⽅案 2 - 只使⽤⾮对称加密 ⽅案 3 - 双⽅都使⽤⾮对称加密…

vulnhub靶场——Log4j2

第一步:搭建靶场环境 #开启环境 cd vulhub/log4j/CVE-2021-44228 docker-compose up -d 来到网站首页 第二步:搭建一个dnslog平台上获取我们注入的效果 第三步:发现 /solr/admin/cores?action 这里有个参数可以传 我们可以看到留下了访问记录并且前面的参数被执行后给我们回…

使用idea创建JDK8的SpringBoot项目

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 使用idea创建JDK8的SpringBoot项目 前言我们经常在创建新的springboot项目&#xff0c;默认使用的是spring.io进行创建&#xff0c;但是它总是只会提供高版本的创建方式&…

U9多组织销退业务流程的总结

多组织销退业务流程&#xff0c;它的运行模式也是奇葩&#xff0c;确实不好理解其中的道理。用户实践中更是障碍重重&#xff0c;束手无策。左也不是右也不是&#xff0c;无路可走。 不能理解透彻造成的吧&#xff0c;所以做一个总结。 既有退货&#xff0c;必有出货单。从出货…

cudnn版本gpu架构

nvcc --help 可以看 --gpu-architecture 写到的支持的架构 NVIDIA 的 GPU 架构是按代次发布的&#xff0c;以下是这些架构的对应说明&#xff1a; NVIDIA Hopper: 这是 NVIDIA 于 2022 年推出的架构之一&#xff0c;面向高性能计算&#xff08;HPC&#xff09;和人工智能&…

Prompt格式到底有多重要?它竟然这样影响LLM函数调用能力(附提示词模版)

函数调用能力的关键地位 在当前大语言模型&#xff08;LLM&#xff09;的应用生态中&#xff0c;函数调用能力&#xff08;Function Calling&#xff09;已经成为一项不可或缺的核心能力。它使LLM能够通过调用外部API获取实时信息、操作第三方服务&#xff0c;从而将模型的语言…

有了chatgpt4o,普通人还需要学代码吗?

或许AI到达“终极智能”时&#xff0c;普通人就不用学代码了。不过现阶段或很长的一段时间内这还是不可能的。目前AI编程还是以辅助编程为主&#xff0c;普通人可以借助AI实现一些简单的编程。 其实这个问题可以扩大到AI编程的出现对编程行业或程序员职业影响的问题。就这个问…

CE8.【C++ Cont】练习题组6

目录 1.矩阵转置 题目描述 输入格式 输出格式 输入输出样例 错误代码 提交结果 正确代码 提交结果 2.图像相似度 题目描述 输入格式 输出格式 输入输出样例 代码 提交结果 3. 计算矩阵边缘元素之和 题目描述 输入格式 输出格式 输入输出样例 说明/提示 …

哪个网页版思维导图好用?这5款高效软件不容错过!

眼下虽然每个人的电脑硬盘越来越大&#xff0c;但很多人还是保留着“能不装软件就不装”的理念&#xff0c;在选择办公软件时&#xff0c;会更倾向于选用推出了网页版的软件&#xff0c;这对思维导图来说也不例外。 那具体到思维导图网页版&#xff0c;有哪些软件值得推荐&…

【双指针算法】--复写零

文章目录 1. 题目2. 题目解析3. 代码 1. 题目 在线oj 给你一个长度固定的整数数组 arr &#xff0c;请你将该数组中出现的每个零都复写一遍&#xff0c;并将其余的元素向右平移。 注意&#xff1a;请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改&a…

石岩基督教福音堂

周末娃&#xff0c;娃的阿婆和我一起去石岩基督教福音堂做礼拜。 这是我第一次进入石岩的教堂。教堂很高。应该有3,4层楼高。 这周末做礼拜的人很多一楼人满了&#xff0c;阿婆去二楼做礼拜&#xff0c;娃和我去三楼的儿童室。很多家长楼下做礼拜&#xff0c;小朋友被安排三楼…

Flutter 异步编程简述

1、isolate 机制 1.1 基本使用 Dart 是基于单线程模型的语言。但是在开发当中我们经常会进行耗时操作比如网络请求&#xff0c;这种耗时操作会堵塞我们的代码。因此 Dart 也有并发机制 —— isolate。APP 的启动入口main函数就是一个类似 Android 主线程的一个主 isolate。与…

IDEA用jformdesigner插件做管理系统MVC架构

在 IntelliJ IDEA 中结合 JFormDesigner 插件&#xff0c;通过 Swing 框架实现一个管理系统的 MVC 架构是一种经典的开发方式。以下是具体的步骤和实现思路&#xff0c;包含从项目创建到 MVC 架构的核心代码实现。 1. 项目结构设计 为了清晰的 MVC 分层架构&#xff0c;建议按…

Linux内核调度优先级详解:如何优化你的系统性能

个人主页&#xff1a;chian-ocean 文章专栏-Linux 前言&#xff1a; 进程优先级调度是操作系统中的一种调度机制&#xff0c;其核心是为每个进程分配一个 优先级&#xff08;Priority&#xff09;&#xff0c;然后根据优先级的高低决定进程执行的顺序和时间。这种机制确保了关…

Axure RP9 的详细安装及Axure入门应用

文章目录 一、Axure 是什么?二、Axure 的应用场景三、Axure 安装1. 下载安装2. 汉化授权 附&#xff1a;下载链接 一、Axure 是什么? 1、Axure 是一种强大的原型设计工具&#xff0c;它可以帮助设计师和产品经理快速创建交互式的、高保真度的原型&#xff0c;并进行用户体验…

pro文件转换为CMakeLists.txt文件,QT官方工具使用教程

某些情况需要使用cmake&#xff0c;如果手动将QT的pro文件转换成CMakeLists.txt&#xff0c;简短一点的pro还好&#xff0c;如果是比较复杂的pro&#xff0c;手动转换的时候需要长时间的debug&#xff0c;本人深有感受。 工具介绍&#xff1a; qmake2cmake工具创建一个CMakeL…

CDN信息收集(小迪网络安全笔记~

免责声明&#xff1a;本文章仅用于交流学习&#xff0c;因文章内容而产生的任何违法&未授权行为&#xff0c;与文章作者无关&#xff01;&#xff01;&#xff01; 附&#xff1a;完整笔记目录~ ps&#xff1a;本人小白&#xff0c;笔记均在个人理解基础上整理&#xff0c;…