irpas技术客

React echarts封装_樊小书生

网络 5010

做大屏的时候经常会遇到 echarts 展示,下面展示在 React (^18.2.0) 中对 echarts (^5.4.0) 的简单封装。

文章首发于https://blog.fxss.work/react/echarts封装.html,样例查看

echarts 封装使用 props 说明 参数说明类型可选值默认值opts初始化传入的 opts https://echarts.apache.org/zh/api.html#echarts.initObject-{renderer: 'svg'}options配置项,对应 https://echarts.apache.org/zh/option.html#titleObject-{}seriesDataseries 数据配置内容https://echarts.apache.org/zh/option.html#series,数据变更自动更新Array-[]intervalTime自动切换的时间跨度,指自动切换 高亮 + tooltip 展示,例子Number-1500autoPlay是否自动播放,指的是是否自动添加切换 高亮 + tooltip 展示Boolean-trueisAddOn是否自动添加鼠标上移事件,切换 高亮 + tooltip 展示的时候,鼠标再移动到其他需要高亮显示上时,自动停止切换动画,鼠标移开自动继续播放Boolean-trueonRefref实例使用,在父组件中const echartsRef = React.createRef();...<EchartsModule onRef={echartsRef} />---className添加样式String-''
方法 方法名说明参数echartsInstance返回 echarts 实例,如果功能不满足,自己定义-echartsPlayecharts开启动画,对外开放,可手动调用clear = false, seriesIndex = 0, dataIndex = -1clear: 是否立即开始动画,并清除上个定时器,开启下个定时器,默认为 false;seriesIndex: series 中的第几项数据,默认为 0;dataIndex: series[seriesIndex].data 中的第几项,默认为 -1echartsPauseecharts关闭动画,对外开放,可手动调用-
使用

如下演示 echarts 封装使用:

可以将如下代码拷贝到项目运行,更方便查看效果

import { Button, Typography, theme } from "antd"; import React from "react"; import EchartsModule from "../../components/EchartsModule"; const { Title } = Typography; const { useToken } = theme; const PageDemo = () => { const { token } = useToken(); const { colorText, colorBgContainer, colorBorder } = token; const echartsRef = React.createRef(); const options = { textStyle: { color: colorText, }, title: { text: '饼图程序调用高亮示例', left: 'center', textStyle: { color: colorText, }, }, tooltip: { trigger: 'item', formatter: '{a} <br/>{b} : {c} ({d}%)', confine: true, className: 'echart-tooltip-zIndex', backgroundColor: colorBgContainer, borderColor: colorBorder, textStyle: { color: colorText, }, }, legend: { orient: 'vertical', left: 'left', data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎'], textStyle: { color: colorText, }, } } const seriesData = [ { name: '访问来源', type: 'pie', radius: '55%', center: ['50%', '60%'], lable: { textStyle: { color: colorText, }, }, data: [ { value: 335, name: '直接访问' }, { value: 310, name: '邮件营销' }, { value: 234, name: '联盟广告' }, { value: 135, name: '视频广告' }, { value: 1548, name: '搜索引擎' } ], emphasis: { itemStyle: { shadowBlur: 10, shadowOffsetX: 0, } } } ] const changeDate = () => { echartsRef.current.echartsPlay(true, 0, -1) } const changeDate1 = () => { echartsRef.current.echartsPause() } const changeDate2 = () => { const echartsInstance = echartsRef.current.echartsInstance() echartsInstance.clear() echartsInstance.dispose() } return ( <div> <Title level={3}>6、通过 ref 调用开始结束动画,使用 ref 调用的好处是可以指定在第几项开始动画</Title> <div> <Button onClick={changeDate}>开始动画</Button> <Button className="ml-2" onClick={changeDate1}>结束动画</Button> <Button className="ml-2" onClick={changeDate2}>获取实例,销毁echarts</Button> </div> <div className="w-full h-80"> <EchartsModule onRef={echartsRef} options={options} seriesData={seriesData}></EchartsModule> </div> </div> ); }; export default PageDemo; 代码封装 import { useEffect, useImperativeHandle, useRef } from "react"; import * as echarts from 'echarts'; import { useDeepCompareEffect, useMount, useSize, useUnmount, useUpdateEffect } from "ahooks"; import classNames from 'classnames'; const EchartsModule = ({ // https://echarts.apache.org/zh/api.html#echarts.init // 初始化传入的 opts opts = { renderer: 'svg' }, // 配置项 options = {}, // 数据集合 seriesData = [], // 自动切换的时间跨度 intervalTime = 1500, // 是否自动播放 autoPlay = true, // 是否自动添加鼠标上移事件 isAddOn = true, onRef, className = '' }) => { const echartsRef = useRef(null); let myChart = useRef(null); let echartsOptions = useRef({}); let myChartEventTime = useRef(null); let currentSeriesIndex = useRef(0); let currentDataIndex = useRef(-1); let timer = useRef(intervalTime); // 是否调用过 echartsPlay let isEchartsPlay = useRef(false); // echarts初始化 function init() { destroyEchart() //判断是否有echart实例,如果有,先销毁 myChart.current = echarts.init(echartsRef.current, null, opts) update() if (isAddOn) { addEventFn() } } // 绑定事件 function addEventFn() { // 鼠标移上查看的时候,暂停动画 myChart.current.on('mouseover', 'series', event => { // 取消之前高亮的图形 myChart.current.dispatchAction({ type: 'downplay', seriesIndex: currentSeriesIndex.current, dataIndex: currentDataIndex.current }) echartsPause() }) // 鼠标移出的时候打开动画 myChart.current.on('mouseout', 'series', event => { // 自动播放 或者 调用过 echartsPlay if (autoPlay || isEchartsPlay.current) echartsPlay(true, event.seriesIndex, event.dataIndex - 1) }) } // 移除事件 function removeEventFn() { myChart.current.off('mouseover') myChart.current.off('mouseout') } // 数据更新 function update() { // 逻辑处理组件options参数 const curOptions = { ...options, series: seriesData // other options here ... } echartsOptions.current = curOptions // 调用ECharts组件setOption更新 myChart.current.setOption(curOptions, true) if (curOptions.series.length && autoPlay) { myChart.current.dispatchAction({ type: 'highlight', seriesIndex: currentSeriesIndex.current, dataIndex: currentDataIndex.current }) // 显示 tooltip myChart.current.dispatchAction({ type: 'showTip', seriesIndex: currentSeriesIndex.current, dataIndex: currentDataIndex.current }) echartsPlay(false, currentSeriesIndex.current, currentDataIndex.current <= seriesData[currentSeriesIndex.current].data.length - 1 ? currentDataIndex.current : -1) } } // 销毁echarts function destroyEchart() { if (myChart.current) { if (isAddOn) { removeEventFn() } if (typeof myChart.current.clear === 'function') myChart.current.clear() if (typeof myChart.current.dispose === 'function') myChart.current.dispose() myChart.current = null } } /** * echarts开启动画,可手动调用 * clear: 是否立即开始动画,并清除上个定时器,开启下个定时器,默认为 false * seriesIndex: series 中的第几项数据,默认为 0 * dataIndex: series[seriesIndex].data 中的第几项,默认为 -1 */ function echartsPlay(clear = false, seriesIndex = 0, dataIndex = -1) { if (clear) { echartsPause() } isEchartsPlay.current = true currentSeriesIndex.current = seriesIndex currentDataIndex.current = dataIndex if (!myChartEventTime.current) { echartsEventPlay(seriesIndex) } } function echartsTimeout(seriesIndex = 0) { myChartEventTime.current = setTimeout(() => { echartsEventPlay(seriesIndex) }, timer.current) } function echartsEventPlay(seriesIndex = 0) { const dataLen = echartsOptions.current.series[seriesIndex].data.length if (myChart.current && myChart.current.dispatchAction) { // 取消之前高亮的图形 myChart.current.dispatchAction({ type: 'downplay', seriesIndex, dataIndex: currentDataIndex.current }) currentDataIndex.current = (currentDataIndex.current + 1) % dataLen // 高亮当前图形 myChart.current.dispatchAction({ type: 'highlight', seriesIndex, dataIndex: currentDataIndex.current }) // 显示 tooltip myChart.current.dispatchAction({ type: 'showTip', seriesIndex, dataIndex: currentDataIndex.current }) } echartsTimeout(seriesIndex) } // echarts关闭动画,可手动调用 function echartsPause() { if (myChart.current && myChart.current.dispatchAction) { // 取消之前高亮的图形 myChart.current.dispatchAction({ type: 'downplay', seriesIndex: currentSeriesIndex.current, dataIndex: currentDataIndex.current }) // 取消显示 tooltip myChart.current.dispatchAction({ type: 'hideTip' }) } if (myChartEventTime.current) { clearTimeout(myChartEventTime.current) myChartEventTime.current = null } } // 重置大小 const echartsResize = () => { if (myChart.current) myChart.current.resize() } useMount(() => { init() }) useUnmount(() => { echartsPause() destroyEchart() }) useDeepCompareEffect(() => { update() }, [seriesData]) useUpdateEffect(() => { if (autoPlay) { echartsPlay(false, currentSeriesIndex.current, currentDataIndex.current) } else { echartsPause() } }, [autoPlay]) useUpdateEffect(() => { timer.current = intervalTime }, [intervalTime]) useUpdateEffect(() => { if (isAddOn) { addEventFn() } else { removeEventFn() } }, [isAddOn]) const size = useSize(echartsRef) useEffect(() => { echartsResize() }, [size]) useImperativeHandle(onRef, () => { return { echartsInstance: () => myChart.current, echartsPlay, echartsPause } }); return ( <div ref={echartsRef} className={classNames('w-full h-full', className)}></div> ); }; export default EchartsModule;


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #React #echarts封装 #做大屏的时候经常会遇到 #echarts #展示下面展示在 #1820 #中对