likes
comments
collection
share

在React中使用Echarts5

作者站长头像
站长
· 阅读数 4

安装依赖包

首先我们安装echarts依赖包:

npm i echarts
// 或者
yarn add echarts
// 或者
pnpm i echarts

这里我使用pnpm进行安装:

在React中使用Echarts5

在项目中集成

之后,我们在 src/utils 目录中创建 echartsConfig.ts 文件,这里以柱状图饼状图为例:

// echartsConfig.ts
import { use } from 'echarts/core'
import { BarChart, PieChart } from 'echarts/charts'
import { GridComponent, LegendComponent } from 'echarts/components'
import { CanvasRenderer } from 'echarts/renderers'

import type { ComposeOption } from 'echarts/core'
import type { BarSeriesOption, PieSeriesOption } from 'echarts/charts'
import type {
  GridComponentOption,
  TitleComponentOption,
  TooltipComponentOption,
  LegendComponentOption
} from 'echarts/components'

export type BarECOption = ComposeOption<
  BarSeriesOption | TitleComponentOption | TooltipComponentOption | GridComponentOption
>

export type PieECOption = ComposeOption<
  PieSeriesOption | TitleComponentOption | TooltipComponentOption | GridComponentOption | LegendComponentOption
>

export const initEcharts = () => {
  use([GridComponent, LegendComponent, BarChart, PieChart, CanvasRenderer])
}

上述代码中,首先导入了 ECharts 库的模块与类型

模块:

  • use 函数:来自 echarts/core,用于注册 ECharts 组件和渲染器。
  • BarChart:来自 echarts/charts,柱状图组件。
  • GridComponent:来自 echarts/components,表示网格(Grid)组件,用于在图表中划分坐标轴区域。
  • CanvasRenderer:来自 echarts/renderers,表示基于 HTML5 Canvas 的渲染器,用于绘制图表。

类型:

  • ComposeOption: 来自 echarts/core,用于表示可以组合多个 ECharts 组件选项的通用类型。
  • BarSeriesOption:来自 echarts/charts,表示柱状图系列的配置选项。
  • GridComponentOptionTitleComponentOptionTooltipComponentOption:来自 echarts/components,表示网格标题提示框组件的配置选项。

BarECOption类型,继承自 ComposeOption 类型,并将 BarSeriesOptionTitleComponentOptionTooltipComponentOptionGridComponentOption 类型以联合类型的形式传入。

这意味着一个 BarECOption 类型的变量可以包含以上四个组件选项中的任意一个或多个组合。这个类型为创建包含柱状图标题提示框网格ECharts 配置项提供了类型约束。

当然,你也可以不自己组装BarECOption类型,而直接使用官方的 EChartsOption,从 echarts/types/dist/shared.d.ts 包中导入:

import { EChartsOption } from 'echarts/types/dist/shared.d.ts'

initEcharts 函数,没有参数且无返回值。作用是向 ECharts 注册所需组件(网格、柱状图)和渲染器(CanvasRenderer)。

我们会在 main.tsx 文件中通过调用 initEcharts 函数,确保后续创建 ECharts 实例时能够使用这些已注册的组件和渲染器来绘制图表。

在React中使用Echarts5

封装渲染hook

src/hooks 目录中创建 useECharts.ts 文件,该文件的代码如下:

// useECharts.ts
import * as echarts from 'echarts'
import { useEffect, useRef } from 'react'

/**
 * 使用React Hook来初始化并管理ECharts实例。
 *
 * @returns {Object} 返回一个包含chartRef和chartInstanceRef的对象。
 *                   chartRef是HTMLDivElement的引用,用于挂载ECharts实例;
 *                   chartInstanceRef是ECharts实例的引用,用于调用如`setOption`等方法更新图表配置与数据。
 */
export const useECharts = () => {
  // 用于存储ECharts图表容器的引用
  const chartRef = useRef<HTMLDivElement>(null)
  // 用于存储ECharts实例的引用
  const chartInstanceRef = useRef<echarts.ECharts>()

  // 当组件挂载到DOM上时,初始化ECharts实例,并在窗口大小改变时调整图表大小
  useEffect(() => {
    if (chartRef.current) {
      // 初始化ECharts实例
      chartInstanceRef.current = echarts.init(chartRef.current)
      const handleResize = () => {
        // 窗口大小改变时调整图表大小
        chartInstanceRef.current?.resize()
      }
      // 监听窗口大小改变事件
      window.addEventListener('resize', handleResize)
      // 组件卸载时,移除窗口大小改变的事件监听并销毁ECharts实例
      return () => {
        window.removeEventListener('resize', handleResize)
        chartInstanceRef.current?.dispose()
      }
    }
  }, [])

  // 返回包含chartRef和chartInstanceRef的对象
  return { chartRef, chartInstanceRef }
}

useECharts 主要功能是封装ECharts图表的创建、管理和销毁过程。这个Hook遵循React Hooks的设计原则,使得在React组件中使用ECharts图表变得更加便捷和易于维护。

它返回一个对象,其中包含 chartRefchartInstanceRef 两个属性。chartRefHTMLDivElement 的引用,用于挂载ECharts实例;chartInstanceRef 是ECharts实例 的引用,用于调用如 setOption 等方法更新图表配置与数据。当组件挂载到DOM上时,该Hook会初始化ECharts实例,并在窗口大小改变时调整图表大小。组件卸载时,会移除窗口大小改变的事件监听销毁ECharts实例

封装组件

src/components/Echarts 目录中创建 BarChart.tsx 文件,该文件的代码是:

import { useECharts } from '@/hooks/useECharts.ts'
import { useEffect } from 'react'
import { BarECOption } from '@/utils/echartsConfig.ts'
import { CallbackDataParams } from 'echarts/types/dist/shared.d.ts'
import { format, graphic } from 'echarts/core'

interface BarChartProps {
  // 柱状图系列的数据
  seriesData: number[]
  // 柱状图X轴的数据
  xAxisData: string[]
  // 图表高度
  height?: number
  // tooltip显示的单位,默认:元
  unit?: string
}

export const BarChart = ({ seriesData, xAxisData, height = 400, unit = '元' }: BarChartProps) => {
  const { chartRef: barRef, chartInstanceRef: barChart } = useECharts()

  useEffect(() => {
    barChart.current?.setOption({
      tooltip: {
        trigger: 'axis',
        axisPointer: {
          type: 'shadow'
        },
        formatter: (params: CallbackDataParams[]) => {
          // if (Array.isArray(params) && params.length > 0) {
          const firstItem = params[0]
          return `${firstItem.name}<br/> ${firstItem.marker} <strong>${format.addCommas(firstItem.value as number)} ${unit}</strong>`
          // }
          // return ''
        }
      },
      grid: {
        top: '15%',
        right: '3%',
        left: '5%',
        bottom: '12%'
      },
      xAxis: [
        {
          type: 'category',
          data: xAxisData,
          axisLine: {
            lineStyle: {
              color: '#dedede'
            }
          },
          axisLabel: {
            margin: 10,
            color: '#999',
            fontSize: 14
          }
        }
      ],
      yAxis: [
        {
          axisLabel: {
            formatter: '{value}',
            color: '#999'
          },
          axisLine: {
            show: true,
            lineStyle: {
              color: '#dedede'
            }
          },
          splitLine: {
            lineStyle: {
              color: '#eee'
            }
          }
        }
      ],
      series: [
        {
          type: 'bar',
          data: seriesData,
          barWidth: '20px',
          itemStyle: {
            color: new graphic.LinearGradient(
              0,
              0,
              0,
              1,
              [
                {
                  offset: 0,
                  color: '#8bc8ff' // 0% 处的颜色
                },
                {
                  offset: 1,
                  color: '#1990ff' // 100% 处的颜色
                }
              ],
              false
            ),
            borderRadius: [30, 30, 0, 0],
            shadowColor: 'rgba(0,160,221,0)',
            shadowBlur: 2
          },
          emphasis: {
            // 鼠标悬浮时,条形的样式指定
            focus: 'series',
            itemStyle: {
              shadowBlur: 2,
              shadowColor: '#1990ff' // 添加阴影效果
            }
          },
          label: {
            show: true,
            lineHeight: 30,
            width: 80,
            height: 30,
            backgroundColor: 'rgba(25, 145, 255,.1)',
            borderRadius: 200,
            position: ['-8', '-60'],
            distance: 1,
            // formatter: ['    {d|●}', ' {a|{c}}     \n', '     {b|}'].join(''),
            formatter: function (params) {
              // 使用 ECharts 的 formatNumber 方法格式化数值
              const formattedNumber = format.addCommas(params.value as number)
              // 构造富文本标签字符串
              return [
                '    {d|●}',
                `    {a|${formattedNumber}}     \n`, // 使用格式化后的数值
                '     {b|}'
              ].join('')
            },
            rich: {
              d: {
                color: '#1890ff'
              },
              a: {
                color: '#1890ff',
                align: 'center'
              },
              b: {
                width: 1,
                height: 30,
                borderWidth: 1,
                borderColor: '#e8f4ff',
                align: 'left'
              }
            }
          }
        }
      ]
    } as BarECOption)
  }, [barChart, seriesData, unit, xAxisData])

  return <div style={{ height: `${height}px` }} ref={barRef}></div>
}

关于ECharts代码不详细介绍,有兴趣的读者可以阅读官方文档

之后在页面中调用 BarChart 组件

import { BarChart } from '@/components/Echarts/BarChart.tsx'

const KanBan = () => {
  return (
    <div className='container-background'>
      <BarChart
        xAxisData={['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']}
        seriesData={[30012, 45012, 77012, 20312, 25512, 18812, 15612, 300123, 450123, 770123, 203123, 255123]}
      />
    </div>
  )
}
export default KanBan

效果如下:

在React中使用Echarts5

其中要注意的是 format.addCommas()的作用是增加千位分隔符

在React中使用Echarts5