React+Echarts实现数据排名+自动滚动+Y轴自定义toolTip文字提示

1、效果

2、环境准备

1、react18

2、antd 4+

 3、代码实现

原理:自动滚动通过创建定时器动态更新echar的dataZoom属性startValue、endValue,自定义tooltip通过监听echar的鼠标移入移出事件,判断tooltTip元素的显隐以及位置。

1、导入所需组件:在你的代码文件中导入所需的组件

import ReactECharts from 'echarts-for-react';

2、创建一个定时器,处理当前图表滚动至第几个数据,用于实现自动滚动

 // 开启定时器const initialScroll = (dataLen: number, myChart: any) => {const option = myChart.getOption();// 只有当大于10条数据的时候 才会看起来滚动let time = setInterval(() => {if (data.length <= 8) {return;}if (option?.dataZoom[0].endValue >= dataLen - 1) {option.dataZoom[0].endValue = 7;option.dataZoom[0].startValue = 0;} else {option.dataZoom[0].endValue = option.dataZoom[0].endValue + 1;option.dataZoom[0].startValue = option.dataZoom[0].startValue + 1;}myChart.setOption(option);myChart.setOption({dataZoom: [{type: 'slider',startValue: option.dataZoom[0].startValue,endValue: option.dataZoom[0].endValue,},],});}, Number(rollTime));timer = time;};

3、在useEffect中添加自动滚动的定时器

  useEffect(() => {const myChart = chartRef?.current?.getEchartsInstance();let chartDom = chartRef.current?.getEchartsInstance()?.getDom();if (data.length > 8) {initialScroll(data.length, myChart);// 鼠标离开开启定时器chartDom?.addEventListener('mouseout', () => {if (timer) return;initialScroll(data.length, myChart);});}return () => {clearInterval(timer);timer = null;};}, [data]); // 检测数组内变量 如果为空 则监控全局

4、配置echars的属性,核心要配置dataZoom,控制数据从第几个开始展示,从第几个结束

export const getOption = (result) => {return {tooltip: {...},},grid: {...},xAxis: [{...},],yAxis: [{triggerEvent: true,data: result.map((item) => item.projectName),axisLabel: {...formatter: (value) => {const valueNew =value.length > 4 ? `${value.slice(0, 4)}...` : value;const index = result.findIndex((item) => item.projectName === value,);if (index < 3) {return `{icon${index + 1}|${index + 1}} {a|${valueNew}}`;} else {return `{icon0|${index + 1}} {a|${valueNew}}`;}}}],dataZoom: [{yAxisIndex: [0, 1], // 这里是从X轴的0刻度开始show: false, // 是否显示滑动条,不影响使用type: 'slider', // 这个 dataZoom 组件是 slider 型 dataZoom 组件startValue: 0, // 从头开始。endValue: 7, // 展示到第几个。},],};
};

4、echarts Y轴的title超出会显示省略,但是看不全体验不好,于是给Y轴加了一个自定义的tooltTip,翻看的echarts所有属性,纵向坐标系,Y轴没有相关属性定义tooltTip

  <ReactEChartsref={chartRef}option={getOption(data)}className={clsx(['h-full w-full'])}style={{ width: '100%', height: '100%' }}/><div className="axis-tip"> </div>

于是在echarts同层节点添加一个toolTip节点,<div className="axis-tip"> </div> 就是ReactECharts的同层节点,通过监听echartsDom的鼠标移入移出控制toolTip的显示位置以及是否显示

  useEffect(() => {const myChart = chartRef?.current?.getEchartsInstance();let chartDom = chartRef.current?.getEchartsInstance()?.getDom();// 移入chartDom?.addEventListener('mouseover', () => {clearInterval(timer);timer = undefined;removeAxisTip();});// yAxis鼠标移入监听myChart?.on?.('mouseover', 'yAxis.category', function (e: any) {let axisTip: any = document.querySelector('.axis-tip');if (axisTip) {axisTip.innerText = e.value;axisTip.style.left = (Number(e?.event?.event?.screenX) || 0) + 'px';axisTip.style.top = (Number(e?.event?.event?.screenY) || 0) + 'px';axisTip.style.display = 'block';}});return () => {myChart?.off('mouseover', () => {});chartDom?.removeEventListener('mouseout', () => {});chartDom?.removeEventListener('mouseover', () => {});timer = null;};}, [data]); // 检测数组内变量 如果为空 则监控全局

 5、完整代码如下:

/*** 收集完成率排名 图表*/
import clsx from 'clsx';
import ReactECharts from 'echarts-for-react';
import { useEffect, useRef } from 'react';
import '../index.less';
import { getOption } from './constants';interface ProjectBarConfig {data: any;rollTime?: number;
}const LineECharts = (props: ProjectBarConfig) => {const { rollTime = 5000, data } = props;const chartRef = useRef<ReactECharts>(null);let timer: any = null;// 开启定时器const initialScroll = (dataLen: number, myChart: any) => {const option = myChart.getOption();// 只有当大于10条数据的时候 才会看起来滚动let time = setInterval(() => {if (data.length <= 8) {return;}if (option?.dataZoom[0].endValue >= dataLen - 1) {option.dataZoom[0].endValue = 7;option.dataZoom[0].startValue = 0;} else {option.dataZoom[0].endValue = option.dataZoom[0].endValue + 1;option.dataZoom[0].startValue = option.dataZoom[0].startValue + 1;}myChart.setOption(option);myChart.setOption({dataZoom: [{type: 'slider',startValue: option.dataZoom[0].startValue,endValue: option.dataZoom[0].endValue,},],});}, Number(rollTime));timer = time;};// 移除y轴tipconst removeAxisTip = () => {let axisTip: any = document.querySelector('.axis-tip');if (axisTip) {axisTip.innerText = '';axisTip.style.display = 'none';}};useEffect(() => {const myChart = chartRef?.current?.getEchartsInstance();let chartDom = chartRef.current?.getEchartsInstance()?.getDom();if (data.length > 8) {initialScroll(data.length, myChart);// 鼠标离开开启定时器chartDom?.addEventListener('mouseout', () => {if (timer) return;initialScroll(data.length, myChart);});}// 移入chartDom?.addEventListener('mouseover', () => {clearInterval(timer);timer = undefined;removeAxisTip();});// yAxis鼠标移入监听myChart?.on?.('mouseover', 'yAxis.category', function (e: any) {let axisTip: any = document.querySelector('.axis-tip');if (axisTip) {axisTip.innerText = e.value;axisTip.style.left = (Number(e?.event?.event?.screenX) || 0) + 'px';axisTip.style.top = (Number(e?.event?.event?.screenY) || 0) + 'px';axisTip.style.display = 'block';}});// });return () => {clearInterval(timer);myChart?.off('mouseover', () => {});chartDom?.removeEventListener('mouseout', () => {});chartDom?.removeEventListener('mouseover', () => {});timer = null;};}, [data]); // 检测数组内变量 如果为空 则监控全局const heightRate = Math.min((data.length || 1) / 8, 1) * 100;return (<divclassName={clsx(['w-full h-full', 'flex flex-row'])}onMouseLeave={() => {removeAxisTip();}}><divclassName={clsx(['flex-auto', 'h-full'])}style={{height: `${heightRate}%`,maxHeight: '100%',minHeight: '20%',}}><ReactEChartsref={chartRef}option={getOption(data)}className={clsx(['h-full w-full'])}style={{ width: '100%', height: '100%' }}/><div className="axis-tip"> </div></div></div>);
};export default LineECharts;

 echar属性配置:

const ranKIconList = ['data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyOCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDI4IDIwIiBmaWxsPSJub25lIj4NCiAgPHBhdGggZD0iTTAgMEgyMEwyOCAxMC41TDIwIDIwSDBWMFoiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl8yNDIxM183MDA4KSIvPg0KICA8ZGVmcz4NCiAgICA8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MF9saW5lYXJfMjQyMTNfNzAwOCIgeDE9IjE0IiB5MT0iMCIgeDI9IjE0IiB5Mj0iMjAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4NCiAgICAgIDxzdG9wIHN0b3AtY29sb3I9IiNGRkQxMkUiLz4NCiAgICAgIDxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI0ZGQjgwMCIvPg0KICAgIDwvbGluZWFyR3JhZGllbnQ+DQogIDwvZGVmcz4NCjwvc3ZnPg==','data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyOCIgaGVpZ2h0PSIyMSIgdmlld0JveD0iMCAwIDI4IDIxIiBmaWxsPSJub25lIj4NCiAgPHBhdGggZD0iTTAgMC4yODU2NDVIMjBMMjggMTAuNzg1NkwyMCAyMC4yODU2SDBWMC4yODU2NDVaIiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXJfMjQyMTNfNzAxMSkiLz4NCiAgPGRlZnM+DQogICAgPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzI0MjEzXzcwMTEiIHgxPSIxNCIgeTE9IjAuMjg1NjQ1IiB4Mj0iMTQiIHkyPSIyMC4yODU2IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+DQogICAgICA8c3RvcCBzdG9wLWNvbG9yPSIjQThDRkYwIi8+DQogICAgICA8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM4N0I4RTEiLz4NCiAgICA8L2xpbmVhckdyYWRpZW50Pg0KICA8L2RlZnM+DQo8L3N2Zz4=','data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyOCIgaGVpZ2h0PSIyMSIgdmlld0JveD0iMCAwIDI4IDIxIiBmaWxsPSJub25lIj4NCiAgPHBhdGggZD0iTTAgMC41NzEyODlIMjBMMjggMTEuMDcxM0wyMCAyMC41NzEzSDBWMC41NzEyODlaIiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXJfMjQyMTNfNzAxNCkiLz4NCiAgPGRlZnM+DQogICAgPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzI0MjEzXzcwMTQiIHgxPSIxNCIgeTE9IjAuNTcxMjg5IiB4Mj0iMTQiIHkyPSIyMC41NzEzIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+DQogICAgICA8c3RvcCBzdG9wLWNvbG9yPSIjRkFDNjgxIi8+DQogICAgICA8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNGNTkzMzgiLz4NCiAgICA8L2xpbmVhckdyYWRpZW50Pg0KICA8L2RlZnM+DQo8L3N2Zz4=','data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyOCIgaGVpZ2h0PSIyMSIgdmlld0JveD0iMCAwIDI4IDIxIiBmaWxsPSJub25lIj4NCiAgPHBhdGggZD0iTTAgMC44NTY5MzRIMjBMMjggMTEuMzU2OUwyMCAyMC44NTY5SDBWMC44NTY5MzRaIiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXJfMjQyMTNfNzAxNykiLz4NCiAgPGRlZnM+DQogICAgPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzI0MjEzXzcwMTciIHgxPSIxNCIgeTE9IjAuODU2OTM0IiB4Mj0iMTQiIHkyPSIyMC44NTY5IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+DQogICAgICA8c3RvcCBzdG9wLWNvbG9yPSIjMEM0MjdDIi8+DQogICAgICA8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMwODM1NjYiLz4NCiAgICA8L2xpbmVhckdyYWRpZW50Pg0KICA8L2RlZnM+DQo8L3N2Zz4=',
];
// 配置调色板
export const colorPalette = [['#2EF2FF', '#2EB3FF'],['#FFD12E', '#FFB82E'],['#8EED15', '#00CF61'],['#CFCFCF', '#999'],['#FF7D54', '#FF2E2E'],['#00F3E5', '#00D4D6'],
].map(([startColor, endColor]) => ({type: 'linear',x: 0,y: 0,x2: 0,y2: 1,colorStops: [{offset: 0,color: startColor, // 0% 处的颜色},{offset: 1,color: endColor, // 100% 处的颜色},],global: false, // 缺省为 false
}));export const getOption = (result) => {return {//   color: '2379FF',//   backgroundColor: '#000416',color: colorPalette,tooltip: {show: true,trigger: 'axis',padding: [8, 15],backgroundColor: 'rgba(1, 15, 29, 80%)',fontWeight: 700,borderColor: 'rgba(46, 179, 255, 50%)',textStyle: {color: 'rgba(255, 255, 255, 1)',},},legend: {show: false,},grid: {left: '100',right: '52',top: '0',bottom: '4',},xAxis: [{splitLine: {show: false,},type: 'value',show: false,axisLine: {show: false,},},],yAxis: [{triggerEvent: true,splitLine: {show: false,},axisLine: {show: false,},// type: 'category',axisTick: {show: false,},inverse: true,// offset: 10,data: result.map((item) => item.projectName),axisLabel: {color: '#fff',fontSize: 12,// marginLeft: 12,overflow: 'truncate',ellipsis: '...',margin: 110,align: 'left',formatter: (value) => {const valueNew =value.length > 4 ? `${value.slice(0, 4)}...` : value;const index = result.findIndex((item) => item.projectName === value,);if (index < 3) {return `{icon${index + 1}|${index + 1}} {a|${valueNew}}`;} else {return `{icon0|${index + 1}} {a|${valueNew}}`;}},rich: {icon0: {width: 28,height: 18,fontSize: 12,align: 'center',verticalAlign: 'middle',color: '#fff',padding: [3, 4], //[上, 右, 下, 左]fontWeight: 400,backgroundColor: {image: ranKIconList[3],},},icon1: {width: 28,height: 18,fontSize: 12,align: 'center',verticalAlign: 'middle',padding: [3, 4], //[上, 右, 下, 左]backgroundColor: {image: ranKIconList[0],},},icon2: {fontSize: 12,align: 'center',verticalAlign: 'middle',padding: [3, 4], //[上, 右, 下, 左]width: 28,height: 18,backgroundColor: {// image: bg,image: ranKIconList[1],},},icon3: {width: 28,height: 18,fontSize: 12,verticalAlign: 'middle',padding: [3, 4], //[上, 右, 下, 左]align: 'center',backgroundColor: {image: ranKIconList[2],},},a: {fontSize: '12px',color: '#B8D3F1',align: 'center',},z: {width: 6,height: 6,},},},},],series: [{type: 'bar',label: {show: true,position: 'right',// distance: 0,textStyle: {fontSize: 12,color: '#2EB3FF', // 值文字颜色},formatter: (value) => {return `{a|${value?.data}%}`;},rich: {a: {fontSize: 12,fontWeight: 500,color: '#2EB3FF', // 值文字颜色fontStyle: 'normal',fontFamily: 'Arial',padding: [0, 8, 0, 8], //[上, 右, 下, 左]},b: {fontSize: 14,},},},itemStyle: {normal: {fontWeight: 400,// color: function(params) {//   return barShadowColor[params.dataIndex]// },opacity: 0.8,},},barWidth: 8,data: result.map((item) => item.value),// barGap:2,z: 2,},{name: '背景',type: 'bar',tooltip: { show: false },barWidth: 12,barHeight: 20,barGap: '-100%',// z: -1},],dataZoom: [{yAxisIndex: [0, 1], // 这里是从X轴的0刻度开始show: false, // 是否显示滑动条,不影响使用type: 'slider', // 这个 dataZoom 组件是 slider 型 dataZoom 组件startValue: 0, // 从头开始。endValue: 7, // 展示到第几个。},],};
};

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

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

相关文章

【考研数学】选汤家凤1800 还是 张宇1000❓关键看这一点

考研备考&#xff0c;如果没有准备好&#xff0c;真的不要随便开始&#xff0c;因为已经有人开始后悔了&#xff01; 特别是关于考研数学&#xff0c;很多人都不知道该如何刷题&#xff0c;如何选资料&#xff0c;下面我就分享一下我的经验&#xff1a; 关于考研做题&#xf…

RobotFramework报错都是因为什么

1、参数问题FAILKeyword common. Bpm Ui Query Delete Data expected 44 arguments,got 3. 这种报错的意思是&#xff0c;应该有4个参数&#xff0c;实际只展示了3个参数 找对应的解决方案一 可能是入参的时候数量不一致 解决方案二&#xff1a; 对应的参数中间有空格 …

机器学习 | 一文看懂SVM算法从原理到实现全解析

目录 初识SVM算法 SVM算法原理 SVM损失函数 SVM的核方法 数字识别器(实操) 初识SVM算法 支持向量机&#xff08;Support Vector Machine&#xff0c;SVM&#xff09;是一种经典的监督学习算法&#xff0c;用于解决二分类和多分类问题。其核心思想是通过在特征空间中找到一…

Java小区物业管理系统

技术架构&#xff1a; springboot mybatis thymeleaf Mysql5.7 有需要该项目的小伙伴可以私信我你的Q。 功能描述&#xff1a; 控制台、数据库、楼栋管理、单元管理、房屋管理、车位管理、缴费类型、缴费管理、公告管理、维修管理、投诉管理、用户管理 效果图&#xff…

【Linux】环境基础开发工具的使用之gdb详解(三)

前言&#xff1a;上一篇文章中我们讲解了Linux下的gcc与g的使用&#xff0c;今天我们将进一步的学习gdb与makefile来帮我们更好的理解与使用基础开发工具。 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏分类:Linux的深度刨析 &#x1f448; …

【C生万物】C语言分支和循环语句

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ &#x1f64f;小杨水平有…

最好的方式来预测未来是去创造它。

在辅导企业的过程中&#xff0c;对于「建设性的冲突」持开放态度&#xff0c;这背后反映了一种深刻的系统思考和变革管理的理念。在许多传统工作环境中&#xff0c;「和谐」往往被高度重视&#xff0c;但这种表面的和谐有时会掩盖问题的真相&#xff0c;阻碍组织的深层次变革和…

顺序表、链表相关OJ题(2)

创作不易&#xff0c;友友们给个三连吧&#xff01;&#xff01; 一、旋转数组&#xff08;力扣&#xff09; 经典算法OJ题&#xff1a;旋转数组 思路1&#xff1a;每次挪动1位&#xff0c;右旋k次 时间复杂度&#xff1a;o(N^2) 右旋最好情况&#xff1a;k是n的倍数…

【力扣】快乐数,哈希集合+快慢指针+数学

快乐数原题地址 方法一&#xff1a;哈希集合 定义函数getNext(n)&#xff0c;返回n的所有位的平方和。一直执行ngetNext(n)&#xff0c;最终只有2种可能&#xff1a; n停留在1。无限循环且不为1。 证明&#xff1a;情况1是存在的&#xff0c;如力扣的示例一&#xff1a; 接…

P1808 单词分类

P1808 单词分类 题目描述 Oliver 为了学好英语决定苦背单词&#xff0c;但很快他发现要直接记住杂乱无章的单词非常困难&#xff0c;他决定对单词进行分类。 两个单词可以分为一类当且仅当组成这两个单词的各个字母的数量均相等。 例如 AABAC&#xff0c;它和 CBAAA 就可以…

DAY14之二叉树理论基础及递归遍历和迭代遍历

理论基础 满二叉树 满二叉树&#xff1a;如果一棵二叉树只有度为0的结点和度为2的结点&#xff0c;并且度为0的结点在同一层上&#xff0c;则这棵二叉树为满二叉树。 如图所示&#xff1a; 这棵二叉树为满二叉树&#xff0c;也可以说深度为k&#xff0c;有2^k-1个节点的二叉…

2024年微信公众号链接爬取

通过输入&#xff08;或文件导入&#xff09;公众号名称&#xff0c;即可爬取该公众号所有历史文章。 通过公众号官方网站调用API&#xff0c;打开开发者工具后发现有 打开后发现有搜索结果的fakeid&#xff0c;这是每个公众号的标识。 点击某公众号后出现 这是具体公众号文章…