echarts,react hooks 组件化封装

Echart.jsx

  1. import React, {useCallback, useEffect, useRef} from 'react';
  2. import {object, number, array, oneOf, bool} from 'prop-types';
  3. import debounce from 'lodash.debounce';
  4. // 引入核心模块 echarts必须要的接口
  5. import * as echarts from 'echarts/core';
  6. // 必须引入渲染器 CanvasRenderer & SVGRenderer
  7. import {CanvasRenderer, SVGRenderer} from 'echarts/renderers';
  8. // const dpr = window.devicePixelRatio; // 设备分辨率
  9. const RenderEngine = {
  10. canvas: CanvasRenderer,
  11. svg: SVGRenderer
  12. }
  13. Echarts.propTypes = {
  14. options: object.isRequired,
  15. height: number,
  16. renderType: oneOf(['canvas', 'svg']),
  17. components: array,
  18. style: object,
  19. loading: bool,
  20. };
  21. Echarts.defaultProps = {
  22. height: 320,
  23. renderType: 'canvas',
  24. components: [],
  25. style: {},
  26. loading: false,
  27. };
  28. function Echarts(props) {
  29. const {renderType, options, style, height, components, loading} = props;
  30. const chartRef = useRef(null); // DOM节点
  31. const chartInstance = useRef(null); // Echart实例
  32. const isEmpty = !Object.keys(options).length; // options是否为空
  33. const handleResize = debounce(() => {
  34. const {current} = chartInstance;
  35. if (!current) return;
  36. current.resize({animation: {duration: 500}});
  37. }, 300);
  38. // 初始化图表配置项
  39. const renderChart = useCallback(() => {
  40. if(isEmpty) return
  41. const {current} = chartRef;
  42. if (!current) {
  43. return console.error('init echarts DOM error');
  44. }
  45. // 单例模式,获取 dom容器上的实例
  46. const render = echarts.getInstanceByDom(current);
  47. chartInstance.current = render ?? echarts.init(current, null, {
  48. renderer: renderType,
  49. });
  50. showLoading(chartInstance.current)
  51. chartInstance.current.setOption(options);
  52. }, [options, renderType, loading]);
  53. useEffect(init, []);
  54. // 注册必须的组件
  55. function init() {
  56. const MapRender = RenderEngine[renderType] || CanvasRenderer;
  57. // 必须在echarts.init之前使用
  58. echarts.use([MapRender, ...components]);
  59. // 监听 resize屏幕变化
  60. window.addEventListener('resize', handleResize);
  61. return () => {
  62. window.removeEventListener('resize', handleResize);
  63. };
  64. }
  65. useEffect(() => {
  66. renderChart();
  67. return () => {
  68. const {current} = chartInstance;
  69. if (!current) return;
  70. current.dispose();
  71. }
  72. }, [chartInstance, renderChart]);
  73. function showLoading(chartInstance) {
  74. if(!loading) {
  75. return chartInstance.hideLoading()
  76. }
  77. chartInstance.showLoading("default", {
  78. text: "加载中...",
  79. color: "rgb(244, 148, 148)",
  80. textColor: "rgb(112,112, 121)",
  81. maskColor: "rgba(255, 255, 255, 0.8)",
  82. zlevel: 0,
  83. showSpinner: true,
  84. });
  85. }
  86. if(!Object.keys(options).length) {
  87. return null
  88. }
  89. const attrs = {
  90. ref: chartRef,
  91. style: {
  92. height,
  93. ...style,
  94. }
  95. }
  96. return (
  97. <div {...attrs}/>
  98. );
  99. }
  100. export default Echarts;

LineChart

image.png
LineCart.jsx

  1. import React, {useEffect, useState} from 'react';
  2. import { array, bool } from 'prop-types';
  3. import { GridComponent } from 'echarts/components';
  4. import { LineChart } from 'echarts/charts';
  5. import { UniversalTransition } from 'echarts/features';
  6. import Echarts from '../Echarts'
  7. const OPTIONS = {
  8. xAxis: {
  9. type: 'category',
  10. boundaryGap: false,
  11. data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  12. },
  13. yAxis: {
  14. type: 'value',
  15. splitLine: { // 改为虚线网格
  16. show: true,
  17. lineStyle:{
  18. type:'dashed'
  19. }
  20. }
  21. },
  22. series: [
  23. {
  24. data: [150, 230, 224, 218, 135, 147, 260],
  25. type: 'line',
  26. smooth: true,
  27. }
  28. ],
  29. grid: {
  30. left: 32,
  31. top: 16,
  32. right: 16,
  33. bottom: 32,
  34. containLabel: false // 防止标签溢出
  35. }
  36. };
  37. Chart.propTypes = {
  38. loading: bool,
  39. };
  40. Chart.defaultProps = {
  41. loading: false,
  42. };
  43. function Chart({loading}) {
  44. const [options, setOptions] = useState({});
  45. useEffect(update, [loading]);
  46. function update() {
  47. setOptions(OPTIONS)
  48. }
  49. return (
  50. <Echarts
  51. // renderType='svg'
  52. options={options}
  53. components={[GridComponent, LineChart, UniversalTransition]}
  54. />
  55. );
  56. }
  57. export default Chart;

usage

  1. <LineChart />