1、根据代码可复用性,实现Echarts的基础组件封装,含自适应重复渲染,点击事件防抖
以下是组件代码
// 渲染echarts组件
import { chinaJSON } from '../../../common';
import * as echarts from 'echarts';
import React, { useEffect, useRef, memo } from 'react';
// 根据屏幕尺寸设置fontSize
export const setFontSize = () => {
const html = document.documentElement; // 获取html
let fontSize = '100px';
// 获取宽度
const width = html.clientWidth;
if (width < 1024) {
fontSize = '54px';
}
if (width >= 1366) {
fontSize = '95px';
}
if (width >= 1440) {
fontSize = '100px';
}
if (width >= 1920) {
fontSize = '110px';
}
html.style.fontSize = fontSize;
};
type Chart = {
title?: string;
xData?: string[];
seriesData?: number[];
option: any;
chartContainerId: string;
className?: string;
chartInstanceId?: string;
echartsClick?: Function;
resizeFlag?: boolean;
setSelectedLegend?: Function;
};
let chartInstance: any = null;
const EchartsRenderer: React.FC<Chart> = (props) => {
const {
option,
chartContainerId,
chartInstanceId,
echartsClick,
resizeFlag = false,
setSelectedLegend
} = props; //option 的值由父组件传入
const chartWrapper = useRef<any>(null); // 在React中,通过useRef来获取组件挂载的HTML元素,也就是ECharts官网文档中所提到的父容器。
useEffect(() => {
if (!option && Object.keys(option).length === 0) {
return;
}
if (!chartWrapper.current) {
return;
}
setFontSize();
const height = document.getElementById(chartContainerId)?.clientHeight; // 你也可以根据你的布局来自定义ECharts的宽高。
// 如果是地图组件,先注册地图json
if (['AssertMapBox'].includes(chartContainerId)) {
echarts.registerMap('china', chinaJSON);
}
chartWrapper.current.style.width = '100%';
chartWrapper.current.style.height = `${height}px`; //用到了响应式布局的理念,在父元素中寻找id为dora的元素,并设置ECharts父容器的高度为其高度
const chartInstance = echarts.init(chartWrapper.current, 'macarons'); //初始化ECharts
// window.addEventListener('resize', function () {
// chartInstance.resize();
// });
// 不merge配置,防止引用类型数据变化后,组件不更新
chartInstance.setOption(option, true);
// 图例点击事件
chartInstance.on('legendselectchanged', function (params) {
if (setSelectedLegend) {
setSelectedLegend(params);
}
});
const myObserver = new ResizeObserver((entry) => {
chartInstance.resize();
});
myObserver.observe(chartWrapper.current);
return () => {
// 销毁实例,销毁后实例无法再被使用。
chartInstance && chartInstance.dispose();
myObserver.disconnect();
// 添加要监听的元素,把echart的container div添加为监听对象
};
}, []);
useEffect(() => {
if (chartWrapper.current) {
chartInstance = echarts.init(chartWrapper.current, 'macarons'); //重新渲染ECharts
chartInstance.setOption(option, true);
//点击前解绑,防止点击事件触发多次
chartInstance.off('click');
chartInstance.on('click', echartsClick);
}
//每次当option变化时,再次setOptions
}, [option]);
return <div id={chartInstanceId} ref={chartWrapper} />;
};
export default memo(EchartsRenderer);
2、针对Echarts配置项做的封装处理,项目中多次用到一个类型的图表时可封装节省多余代码,可以根据自己项目需求做出修改(react-封装Echarts基础配置项-CSDN博客)
3、实际使用
setTotalMileag(
echartConfig('boxDiagram', {
...res,
yAxis: {
...res?.yaxis,
min: Math.floor(Math.min(...dataList)),
max: Math.ceil(Math.max(...dataList))
}
})
);
<Col span={12} style={{ height: '4.34rem' }}>
<SearchForm showEmpty={!totalMileag} cardTitle="SOH与总里程分布">
<div id="mileageDistribution" style={{ flex: 1 }}>
<EchartsRenderer
chartInstanceId="mileageDistribution"
option={totalMileag}
chartContainerId="mileageDistribution"
/>
</div>
</SearchForm>
</Col>