设备状态图表-甘特图

1.背景:设备状态监控图表,监控不同状态的时间段,可以使用甘特图来展示效果
在这里插入图片描述
鼠标经过时的数据提示框
在这里插入图片描述
在这里插入图片描述
2、代码实现

<template><divref="ganttChartRefs":style="{ height: '6.2rem', width: '100%' }"class="bg_screen"></div>
</template>
<script lang="ts" setup>
import { onMounted, ref, watch, nextTick,onBeforeUnmount } from "vue";
import * as echarts from "echarts";
// import { GaugeChart } from "echarts/charts";
import { useDebounceFn, useResizeObserver } from "@vueuse/core";
// echarts.use([GaugeChart]); // 引入仪表盘 看版本 echart5以上不需要引入
const chartInstance = ref<any>(null);
const ganttChartRefs = ref<any>(null);
const myChart = ref<any>(null);
const props = defineProps({chartData: {type: Array,default: () => [],},
});
function setChartOptions(data:any) {myChart.value = echarts.init(ganttChartRefs.value);var types:any = [{ value: "1", color: "#91cc75", label: '运行'},{ value: "2", color: "#ccc", label: '停机'},{ value: "3", color: "#fd666d", label: '故障'},];var startDate;startDate = new Date(data[0]?.RUNTIME);var datatemp = data.map((d:any) => ({  // 数据集处理name: types.filter((a:any) => a.value == d.STATUSDESC)[0].label,  // 状态名称value: [parseInt(d.GROUPID),new Date(d.RUNTIME).getTime(),  // 处理成时间辍的格式new Date(d.END_TIME).getTime(),],itemStyle: {normal: {color: types.filter((a:any) => a.value == d.STATUSDESC)[0].color, // 状态颜色的绑定},},}));var groupedData = datatemp.reduce((acc:any, curr:any) => {if (!acc[curr.value[0]]) {acc[curr.value[0]] = [];}acc[curr.value[0]].push(curr);return acc;}, {});  // 状态值组合成一组 以便后面排序var gaps:any = [];var startTime_ = new Date(startDate.getFullYear(),startDate.getMonth(),startDate.getDate()).getTime(); // 返回时间戳var endTime_ = startTime_ + 24 * 60 * 60 * 1000; // 24小时后的时间Object.keys(groupedData).forEach((groupID) => {var groupData = groupedData[groupID];// 按开始时间排序groupData.sort((a:any, b:any) => a.value[1] - b.value[1]);var lastEndTime = startTime_;for (var i = 0; i < groupData.length; i++) {var currentStartTime = groupData[i].value[1];var currentEndTime = groupData[i].value[2];if (currentStartTime > lastEndTime) {gaps.push([parseInt(groupID), lastEndTime, currentStartTime]);}lastEndTime = Math.max(lastEndTime, currentEndTime);}// 检查最后一个时间段结束时间与24小时结束时间之间的空隙if (lastEndTime < endTime_) {gaps.push([parseInt(groupID), lastEndTime, endTime_]);}});function renderItem(params:any, api: any) {var categoryIndex = api.value(0);var start = api.coord([api.value(1), categoryIndex]);var end = api.coord([api.value(2), categoryIndex]);var height = api.size([0, 1])[1] * 0.6;var rectShape = echarts.graphic.clipRectByRect({x: start[0],y: start[1] - height / 2,width: end[0] - start[0],height: height,},{x: params.coordSys.x,y: params.coordSys.y,width: params.coordSys.width,height: params.coordSys.height,});var shapes;shapes = rectShape && {type: "rect",transition: ["shape"],shape: rectShape,style: api.style(),};return shapes;}const series = [{type: "custom",renderItem: renderItem,encode: {x: [1, 2],y: 0,},data: datatemp,},{type: "custom",renderItem: renderItem,z: -1, // 放在最底层data: gaps,},];const option = {grid: {left: "1%",right: "1%",top: "1%",bottom: 2,height: "28%",width: "98%",containLabel: true,},tooltip: {show: true,textStyle: {fontSize: 10,},position: function (point:any, size:any) {var mouseX = point[0];var mouseY = point[1];// 获取容器的宽度和 tooltip 的宽度var containerWidth = size.viewSize&&size.viewSize[0];var tooltipWidth =  size.contentSize&&size.contentSize[0];// 调整 tooltip 的位置var offsetX = 10; // x 方向偏移量var offsetY = 1; // y 方向偏移量// 如果 tooltip 超出容器的右侧,将其显示在鼠标的左侧if (mouseX + tooltipWidth + offsetX > containerWidth) {// 新的位置坐标var newX = mouseX - tooltipWidth - offsetX;var newY = mouseY + offsetY;// 返回新的位置坐标return [newX, newY];} else {// tooltip 显示在鼠标的下方var newX:number = mouseX + offsetX;var newY:any = mouseY + offsetY;// 返回新的位置坐标return [newX, newY];}},formatter: function (params:any) {// 参数校验if (!Array.isArray(params.value) || params.value.length < 2) {return "";}try {const startTime = params.value[1];const endTime = params.value[2];if (endTime < startTime) {return "";}const duration = endTime - startTime;const hours = Math.floor(duration / (1000 * 60 * 60));const minutes = Math.floor((duration % (1000 * 60 * 60)) / (1000 * 60));const seconds = Math.floor((duration % (1000 * 60)) / 1000);// 获取带前导0的小时、分钟和秒const formatTimeUnit = (unit:any) =>unit < 10 ? "0" + unit : unit.toString();const formattedStartTimeHours = formatTimeUnit(new Date(startTime).getHours());const formattedStartTimeMinutes = formatTimeUnit(new Date(startTime).getMinutes());const formattedStartTimeSeconds = formatTimeUnit(new Date(startTime).getSeconds());const formattedEndTimeHours = formatTimeUnit(new Date(endTime).getHours());const formattedEndTimeMinutes = formatTimeUnit(new Date(endTime).getMinutes());const formattedEndTimeSeconds = formatTimeUnit(new Date(endTime).getSeconds());const formattedTimeSeconds = formatTimeUnit(seconds);let formattedDuration = `${hours}小时${minutes}分${formattedTimeSeconds}秒`;// output 鼠标经过的时候展示的文本let output = `${params.marker}${params.name}${params.seriesIndex === 1? `空闲时长:`: `时长:`}${formattedDuration}<br/>`;output += `${params.marker}时间区间:${formattedStartTimeHours}:${formattedStartTimeMinutes}:${formattedStartTimeSeconds} - ${formattedEndTimeHours}:${formattedEndTimeMinutes}:${formattedEndTimeSeconds}`;return output;} catch (error) {return ""; // 根据实际情况考虑是否返回错误信息或特定的格式化失败字符串}},},dataZoom: [{type: "inside",filterMode: "none",showDataShadow: false,show: true,},],xAxis: {type: "time",min: new Date().getTime() - 24 * 60 * 60 * 1000, // 24小时前max: new Date().getTime(), // 当前时间axisLabel: {formatter: function (value:any) {var date = new Date(value);var hours = date.getHours();var minutes = date.getMinutes();var seconds = date.getSeconds();// 如果分钟和秒都是0,则只显示小时(例如:00)if (minutes === 0 && seconds === 0) {return hours === 0? "00:00": echarts.format.formatTime("hh:mm", value);}// 其他情况显示小时、分钟和秒(例如:01:30:45)return echarts.format.formatTime("hh:mm:ss", value);},// 标签与轴线紧挨在一起padding: [0, 0, 0, 0], // 标签的内边距(可根据实际情况调整)// rotate: 30, // 旋转角度,避免标签重叠(可选)},splitNumber: 24,splitLine: {show: false,},axisLine: {show: false, // 隐藏坐标轴线},axisTick: {show: false, // 隐藏刻度线},},yAxis: [{yAxisIndex: 0,type: "category",data: [""],axisLine: {show: false,},axisTick: {show: false,},axisLabel: {show: false,},},],series: series,};useResizeObserver(ganttChartRefs.value, resizeChart);myChart.value.setOption(option);
}
// 窗口自适应并开启过渡动画
const resize = () => {if (chartInstance.value) {chartInstance.value.resize({ animation: { duration: 300 } });}
};
// 重绘图表函数
const resizeChart = useDebounceFn(() => {myChart.value?.resize();
}, 300);
const debouncedResize = useDebounceFn(resize, 500, { maxWait: 800 });
watch(() => props.chartData,() => {nextTick(() => {setChartOptions(props.chartData);});},{immediate: true,}
);
onMounted(() => {window.addEventListener("resize", debouncedResize);
});
onBeforeUnmount(() => {myChart.value?.dispose();myChart.value = null;window.removeEventListener("resize", debouncedResize);
});
</script>

3.数据源:组件传过来 props.chartData
格式如下:

var data = [{"GROUPID": "0",  // 组别 因为考虑到有多种设备情况 若只有一种 默认0就好"END_TIME": "2024-08-19 01:23:48", // 结束时间"RUNTIME": "2024-08-19 00:22:56",  // 开始时间"STATUSDESC": "1"  // 状态值},{"GROUPID": "0","END_TIME": "2024-08-19 15:24:01","RUNTIME": "2024-08-19 15:23:48","STATUSDESC": "2"},{"GROUPID": "0","END_TIME": "2024-08-19 15:24:54","RUNTIME": "2024-08-19 15:24:01","STATUSDESC": "2"},{"GROUPID": "0","END_TIME": "2024-08-19 15:25:07","RUNTIME": "2024-08-19 15:24:54","STATUSDESC": "2"},{"GROUPID": "0","END_TIME": "2024-08-19 15:25:58","RUNTIME": "2024-08-19 15:25:07","STATUSDESC": "1"},{"GROUPID": "0","END_TIME": "2024-08-19 15:26:14","RUNTIME": "2024-08-19 15:25:58","STATUSDESC": "3"},{"GROUPID": "0","END_TIME": "2024-08-19 15:27:05","RUNTIME": "2024-08-19 15:26:14","STATUSDESC": "1"},{"GROUPID": "0","END_TIME": "2024-08-19 15:27:16","RUNTIME": "2024-08-19 15:27:05","STATUSDESC": "3"},{"GROUPID": "0","END_TIME": "2024-08-19 15:28:14","RUNTIME": "2024-08-19 15:27:16","STATUSDESC": "1"},{"GROUPID": "0","END_TIME": "2024-08-19 15:28:24","RUNTIME": "2024-08-19 15:28:14","STATUSDESC": "3"},{"GROUPID": "0","END_TIME": "2024-08-19 15:29:16","RUNTIME": "2024-08-19 15:28:24","STATUSDESC": "2"},{"GROUPID": "0","END_TIME": "2024-08-19 15:29:32","RUNTIME": "2024-08-19 15:29:16","STATUSDESC": "3"},{"GROUPID": "0","END_TIME": "2024-08-19 15:30:26","RUNTIME": "2024-08-19 15:29:32","STATUSDESC": "1"},{"GROUPID": "0","END_TIME": "2024-08-19 15:30:35","RUNTIME": "2024-08-19 15:30:26","STATUSDESC": "3"},{"GROUPID": "0","END_TIME": "2024-08-19 15:31:30","RUNTIME": "2024-08-19 15:30:35","STATUSDESC": "1"},{"GROUPID": "0","END_TIME": "2024-08-19 15:31:43","RUNTIME": "2024-08-19 15:31:30","STATUSDESC": "3"},{"GROUPID": "0","END_TIME": "2024-08-19 15:32:36","RUNTIME": "2024-08-19 15:31:43","STATUSDESC": "1"},{"GROUPID": "0","END_TIME": "2024-08-19 15:32:48","RUNTIME": "2024-08-19 15:32:36","STATUSDESC": "3"},{"GROUPID": "0","END_TIME": "2024-08-19 15:33:45","RUNTIME": "2024-08-19 15:32:48","STATUSDESC": "1"},{"GROUPID": "0","END_TIME": "2024-08-19 15:33:54","RUNTIME": "2024-08-19 15:33:45","STATUSDESC": "3"},{"GROUPID": "0","END_TIME": "2024-08-19 15:34:49","RUNTIME": "2024-08-19 15:33:54","STATUSDESC": "1"},{"GROUPID": "0","END_TIME": "2024-08-19 15:35:04","RUNTIME": "2024-08-19 15:34:49","STATUSDESC": "3"},{"GROUPID": "0","END_TIME": "2024-08-19 15:35:55","RUNTIME": "2024-08-19 15:35:04","STATUSDESC": "1"},{"GROUPID": "0","END_TIME": "2024-08-19 15:36:04","RUNTIME": "2024-08-19 15:35:55","STATUSDESC": "3"},{"GROUPID": "0","END_TIME": "2024-08-19 15:36:59","RUNTIME": "2024-08-19 15:36:04","STATUSDESC": "1"},{"GROUPID": "0","END_TIME": "2024-08-19 15:37:12","RUNTIME": "2024-08-19 15:36:59","STATUSDESC": "3"},{"GROUPID": "0","END_TIME": "2024-08-19 15:38:04","RUNTIME": "2024-08-19 15:37:12","STATUSDESC": "1"},{"GROUPID": "0","END_TIME": "2024-08-19 15:38:16","RUNTIME": "2024-08-19 15:38:04","STATUSDESC": "3"},{"GROUPID": "0","END_TIME": "2024-08-19 15:39:12","RUNTIME": "2024-08-19 15:38:16","STATUSDESC": "1"},{"GROUPID": "0","END_TIME": "2024-08-19 15:39:23","RUNTIME": "2024-08-19 15:39:12","STATUSDESC": "3"},{"GROUPID": "0","END_TIME": "2024-08-19 15:40:19","RUNTIME": "2024-08-19 15:39:23","STATUSDESC": "1"},{"GROUPID": "0","END_TIME": "2024-08-19 15:40:32","RUNTIME": "2024-08-19 15:40:19","STATUSDESC": "3"},{"GROUPID": "0","END_TIME": "2024-08-19 15:41:24","RUNTIME": "2024-08-19 15:40:32","STATUSDESC": "1"},{"GROUPID": "0","END_TIME": "2024-08-19 15:41:36","RUNTIME": "2024-08-19 15:41:24","STATUSDESC": "3"},{"GROUPID": "0","END_TIME": "2024-08-19 15:41:36","RUNTIME": "2024-08-19 15:47:24","STATUSDESC": "3"}]

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

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

相关文章

视频项目开发,EasyCVR视频融合平台为何成为关键驱动力

智慧类视频项目是基于多个系统融合&#xff0c;旨在实现更广泛联动功能&#xff0c;以满足智能化应用需求为基石的信息化项目。当前&#xff0c;智慧社区、智慧园区、智慧工厂乃至智慧城市等应用场景的需求日益增长。这些智慧项目的整合进程中&#xff0c;视频融合能力扮演着不…

burpsuite xssValidator插件(xss插件)

安装 1. 商城安装插件 2. 安装环境 Download PhantomJShttps://phantomjs.org/download.htmlGitHub - NetSPI/xssValidator: This is a burp intruder extender that is designed for automation and validation of XSS

房价下跌的大环境下,我的佣金为何能逆市增长?

声明&#xff1a;此篇为 ai123.cn 原创文章&#xff0c;转载请标明出处链接&#xff1a;https://ai123.cn/2199.html &#x1f3e0;&#x1f4b0;最近房地产市场可不太景气&#xff0c;房价跌跌不休&#xff0c;咱们中介们的佣金收入也受到了影响。你知道那种心情吗&#xff1f…

【IoTDB 线上小课 06】列式写入=时序数据写入性能“利器”?

【IoTDB 视频小课】更新来啦&#xff01;今天已经是第六期了~ 关于 IoTDB&#xff0c;关于物联网&#xff0c;关于时序数据库&#xff0c;关于开源... 一个问题重点&#xff0c;3-5 分钟&#xff0c;我们讲给你听&#xff1a; 列式写入到底是&#xff1f; 上一期我们详细了解了…

汽车冷却液温度传感器的作用与检测方法

汽车冷却系统中的关键部件之一是冷却液温度传感器&#xff0c;它的位置通常在发动机的缸体或水泵附近&#xff0c;与冷却液直接接触。该传感器的作用是监测发动机冷却液的温度&#xff0c;它采用负温度系数热敏电阻&#xff0c;这种电阻随温度升高而降低。当冷却液温度达到预定…

AcWing 850. Dijkstra求最短路 II

迪杰斯特拉的优化算法采用堆优化&#xff0c;优化之前是花费 O ( n ) O(n) O(n)时间来查找未最优点里面距离点1最小的点。现在使用堆优化&#xff0c;直接花费 O ( 1 ) O(1) O(1)时间就完事儿了。 堆里面存储 p a i r < i n t , i n t > pair<int,int> pair<int…

Java毕业论文 【二手书电子商城网站】源码见github (原创项目,从0-1自己实现)

文章目录 项目背景主要功能模块分布模块分布具体部分功能 系统架构功能演示买家部分界面&#xff1a;卖家部分界面【8002模块】&#xff1a;管理员部分界面&#xff1a; 项目github地址 项目背景 主要面向高校学生&#xff0c;将高年级同学的书回收到低年级学生的手上&#xf…

CANoe.DiVa的应用——Diva进行诊断自动化测试执行过程详解(三)

🙋‍♂️【Vector CANdelastudio配置CDD】文章合集💁‍♂️点击跳转 ——————————————————————————————————–—— 从0开始学习CANoe使用 从0开始学习车载测试 相信时间的力量 星光不负赶路者,时光不负有心人。 目录 1.工程导入2.查看用…

什么是BOM,有哪些分类?

一、什么是BOM&#xff1f; BOM是物料清单的缩写&#xff0c;也称为产品结构表或产品结构树。 BOM的作用主要是通过计算机辅助企业生产管理&#xff0c;使计算机能够识别企业所制造的产品构成和所有要涉及的物料。 在制造业中&#xff0c;BOM是一份详细记录制造某个产品时所…

【算法基础实验】图论-最小生成树Kruskal实现

预备知识 【算法基础实验】图论-UnionFind连通性检测之quick-union_union find 判断是否成环-CSDN博客 【算法基础实验】排序-最小优先队列MinPQ_最小优先队列实现-CSDN博客 理论知识 Kruskal算法是一种用于查找加权无向图的最小生成树的贪心算法。最小生成树是一个连通的子…

uniapp使用live-pusher进行人脸识别打卡(安卓跟ios)

效果图 代码 使用live-pusher <live-pusher idlivePusher class"livePusher" mode"FHD" beauty"0" whiteness"0" aspect"9:16"min-bitrate"1000" audio-quality"16KHz" device-position"fron…

Apple pencil有替代品吗?2024开学季推荐五款实惠又好用的电容笔

如果只是用于学习和办工的话&#xff0c;Apple pencil是有替代品的&#xff0c;虽然Apple Pencil的性能不错&#xff0c;但它的高昂价格让很多用户不得不开始寻求性价比更高的平替电容笔。那么&#xff0c;在众多选择中&#xff0c;如何挑选一款合适的电容笔呢&#xff1f;以下…

【iOS】Block底层分析

目录 前言Block底层结构Block捕获变量原理捕获局部变量&#xff08;auto、static&#xff09;全局变量捕获实例self Block类型Block的copyBlock作为返回值将Block赋值给__strong指针Block作为Cocoa API中方法名含有usingBlock的方法参数Block作为GCD API的方法参数Block属性的写…

光性能 -- 边模抑制比眼图

最小边模抑制比 在最坏的发射条件下&#xff0c;主模的平均光功率与最显著边模的光功率之比即最小边模抑制比。 什么是边模 理想情况下&#xff0c;光模块发射的信号应当只是有特定波长的光信号。但实际情况下不仅有一个特定波长的主信号&#xff0c;还有一些其他波长的存在&…

Java学习笔记(02)接口的使用

1、接口关键字&#xff1a;interface 2、接口内部结构的说明&#xff1a; 可以声明抽象方法&#xff0c;属性由public static final修饰&#xff0c;但都会默认。 不可以声明&#xff1a;构造器&#xff0c;代码块等。 3、格式&#xff1a;class A extends SuperA implements…

开放式耳机别人能听到吗?现在开放式耳机用防漏音效果越来越好!

回答&#xff1a; 开放式耳机的通透的设计允许一部分声音泄露出来&#xff0c;因此站在您旁边的人确实有可能听到您耳机中的声音&#xff0c;尤其是当音量设置得比较高时。开放式耳机通常提供更为自然和宽敞的听感&#xff0c;但牺牲了一定的隔音效果和隐私性。如果您需要在公…

探索提示工程 Prompt Engineering的奥妙

一、探索提示工程 1. 介绍通用人工智能和专用人工智能 人工智能&#xff08;AI&#xff09;可以分为通用人工智能&#xff08;AGI&#xff09;和专用人工智能&#xff08;Narrow AI&#xff09;。AGI是一种能够理解、学习和执行任何人类可以完成的任务的智能。与此相对&#x…

《深入浅出多模态》(八)多模态经典模型:MiniGPT4

&#x1f389;AI学习星球推荐&#xff1a; GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方向综述、论文等成体系的学习资料&#xff0c;配有全面而有深度的专栏内容&#xff0c;包括不限于 前沿论文解读、…

【Qt】输入类控件QComboBox

目录 输入类控件QComboBox 例子&#xff1a;使用下拉框模拟点餐 例子&#xff1a;从文件中加载下拉框的选项 输入类控件QComboBox QComboBox表示下拉框 核心属性 属性说明 currentText 当前选中的⽂本 currentIndex 当前选中的条⽬下标. 从 0 开始计算. 如果当前没有条…

Deepin【2】:Deepin系统盘扩容

Deepin【2】&#xff1a;Deepin系统盘扩容 1、进入live系统1.1、live系统入步骤 2、连接网络3、新增系统仓库4、安装gparted应用5、使用gparted进行扩容操作5.1、观察当前分区5.2、压缩data分区5.3、Rootb分区合并空闲空间5.4、Rootb分区压缩空间5.5、Roota合并空闲空间5.6、核…