ECharts usage and common errors in React+Antd

Recently, I started to use ECharts to make charts in the project. I still encountered a lot of pitfalls in using EChart in React+Antd. I hope that recording the solution can help everyone. Due to the first use, there is a lot of room for code optimization. I hope everyone can help me with it. Thanks~

final effect

1. Realize the linkage of two pie chart data by clicking on the point on the line chart.
2. Deal with the problem that the ECharts pie chart data is 0 or the pie chart disappears when it is empty

Insert picture description here
Insert picture description here
Insert picture description here

How to use ECharts in React

1. Add div in render

<div id='echartLine' style={
    
    {
    
     width: '100%', height: 300, margin: '24px 0' }} />
<div id='pieTotal' style={
    
    {
    
     width: '100%', height: 300, margin: '24px 0' }} />
<div id='pieReject' style={
    
    {
    
     width: '100%', height: 300, margin: '24px 0' }} />

2. Init the ECharts chart

	// 饼图初始option
	const initPieOption = {
    
    
	  // tooltip: {
    
    
	  //   show: false,
	  // },
	  dataset: {
    
    
	    dimensions: ['desc', 'type', 'value'],
	    source: [{
    
     desc: '', type: '', value: 1 }], // 当无数据时,给饼图个初始数据
	  },
	  grid: {
    
    
	    left: '3%',
	    right: '3%',
	    bottom: '0%',
	    containLabel: true,
	  },
	  series: [
	    {
    
     type: 'pie',
	      radius: ['75%', '45%'],
	      stillShowZeroSum: false,
	      itemStyle: {
    
    
	        color: '#e7e7e7',
	      },
	      label: {
    
    
	        normal: {
    
    
	          show: true,
	          position: 'center',
	          formatter: function () {
    
    
	            var result = ''
	            result = '暂无数据'
	
	            return result
	          },
	          textStyle: {
    
    
	            fontSize: 16,
	            color: '#e2e2e2',
	          },
	        },
	      },
	    },
	  ],
	}
  // 初始化图表
  initChart = () => {
    
    
    // const { trendList } = this.state

    // 折线图
    var lineChart = echarts.init(document.getElementById('echartLine'))
    // 建议将ECharts图表实例进行储存,而不是每次数据变化都进行实例初始化
    this.setState({
    
     lineChart })
    lineChart.setOption({
    
    
      title: {
    
    
        text: '趋势',
      },
      tooltip: {
    
    
        trigger: 'axis',
        axisPointer: {
    
    
          type: 'cross',
        },
      },
      legend: {
    
    
        formatter: function (name) {
    
    
          switch (name) {
    
    
            case 'total':
              return '总量 ' + name
            case 'passCount':
              return '通过量 ' + name
            case 'rejectCount':
              return '拒绝量 ' + name
          }
        },
      },
      dataset: {
    
    
        // 这里指定了维度名的顺序,从而可以利用默认的维度到坐标轴的映射。
        // 如果不指定 dimensions,也可以通过指定 series.encode 完成映射,参见后文。
        dimensions: ['date', 'total', 'passCount', 'rejectCount'],
        source: [],
      },
      xAxis: {
    
     type: 'category' },
      yAxis: {
    
    
        type: 'value',
      },
      grid: {
    
    
        left: '3%',
        right: '6%',
        bottom: '0%',
        containLabel: true,
      },
      series: [
        {
    
     type: 'line' },
        {
    
     type: 'line' },
        {
    
     type: 'line' },
      ],
    })
    // 饼图总量
    var pieChartTotal = echarts.init(document.getElementById('pieTotal'))
    this.setState({
    
     pieChartTotal })

    // 饼图拒绝量
    var pieChartReject = echarts.init(document.getElementById('pieReject'))
    this.setState({
    
     pieChartReject })

	// 使图表自适应div大小,防止图表溢出
    window.addEventListener('resize', function () {
    
    
      lineChart.resize()
      pieChartTotal.resize()
      pieChartReject.resize()
    })
  }

3. Re-render the chart when the data changes

 // 获取趋势图
  fetchBaseTrend = async () => {
    
    
    const res = await api.getBaseTrend()
    this.setState({
    
    
      trendList: res,
    }, () => {
    
    
      // 获取到数据后再去调用渲染图表函数
      this.generateChart()
    })
  }
  generateChart = () => {
    
    
    const {
    
     trendList, lineChart, pieChartTotal, pieChartReject } = this.state

    lineChart.setOption({
    
    
      dataset: {
    
    
        // 这里指定了维度名的顺序,从而可以利用默认的维度到坐标轴的映射。
        // 如果不指定 dimensions,也可以通过指定 series.encode 完成映射,参见后文。
        dimensions: ['date', 'total', 'passCount', 'rejectCount'],
        source: trendList,
      },
    })
	// 由于我对饼图无数据做了处理,所以每次setOption之前都要先执行clear(),防止之前setOption内的灰色背景属性仍生效
    pieChartTotal.clear()
    pieChartReject.clear()

	// 默认用数据加载第一条渲染饼图,可能存在无数据情况,因此需要判断
    pieChartTotal.setOption(trendList[0] && !!trendList[0].totalRatio.length ? this.PieOption('total') : initPieOption)
    pieChartReject.setOption(trendList[0] && !!trendList[0].rejectRatio.length ? this.PieOption('reject') : initPieOption)
 }

4. How to click the line chart to render the pie chart

There is a lot of room for optimization of this part of the code, but I have changed it for a long time and haven’t found a better way. I hope everyone can help me with comments. Thanks~

  generateChart = () => {
    
    
  
    lineChart.on('click', function (event) {
    
    
      pieChartTotal.clear()

      pieChartTotal.setOption(event.data && !!event.data.totalRatio.length ? {
    
    
        dataset: {
    
    
          // 这里指定了维度名的顺序,从而可以利用默认的维度到坐标轴的映射。
          // 如果不指定 dimensions,也可以通过指定 series.encode 完成映射,参见后文。
          dimensions: ['desc', 'type', 'value'],
          source: event.data && event.data.totalRatio,
        },
        legend: {
    
    
          orient: 'vertical',
          left: 70,
        },
        tooltip: {
    
    
          trigger: 'item',
          formatter: function (params) {
    
    
            var result = ''
            result = params.name + ' : ' + params.data.value + ' ( ' + params.percent + '% )'

            return result
          },
        },
        series: [
          {
    
     type: 'pie',
            radius: ['75%', '50%'],
            label: {
    
    
              normal: {
    
    
                show: true,
                position: 'center',
                color: '#4c4a4a',
                formatter: function (data) {
    
    
                  var result = ''
                  result = event.name + '\n' + '总量' + ' ' + event.data.total

                  return result
                },
                textStyle: {
    
    
                  fontSize: 16,
                  color: '#00c0ef',
                },
              },
            },
          },
        ],
      } : initPieOption)
      pieChartReject.clear()
      pieChartReject.setOption(event.data.rejectRatio && !!event.data.rejectRatio.length ? {
    
    
        dataset: {
    
    
          // 这里指定了维度名的顺序,从而可以利用默认的维度到坐标轴的映射。
          // 如果不指定 dimensions,也可以通过指定 series.encode 完成映射,参见后文。
          dimensions: ['desc', 'type', 'value'],
          source: event.data && event.data.rejectRatio,
        },
        legend: {
    
    
          orient: 'vertical',
          right: 70,
        },
        series: [
          {
    
     type: 'pie',
            radius: ['75%', '45%'],
            label: {
    
    
              normal: {
    
    
                show: true,
                position: 'center',
                color: '#4c4a4a',
                formatter: function (data) {
    
    
                  var result = ''
                  result = event.name + '\n' + '拒绝量' + ' ' + event.data.rejectCount

                  return result
                },
                textStyle: {
    
    
                  fontSize: 16,
                  color: '#00c0ef',
                },
              },
            },
          },
        ],
      } : initPieOption)
    })
  }

4. TrendList data structure

[{
    
    
	"date": "2020-03-23",
	"total": 52,
	"passCount": 51,
	"rejectCount": 1,
	"totalRatio": [{
    
    
		"type": "text",
		"desc": "文本",
		"value": 27
	}, {
    
    
		"type": "picture",
		"desc": "图片",
		"value": 25
	}],
	"rejectRatio": [{
    
    
		"type": "picture",
		"desc": "图片",
		"value": 1
	}]
}, {
    
    
	"date": "2020-03-24",
	"total": 25,
	"passCount": 18,
	"rejectCount": 7,
	"totalRatio": [{
    
    
		"type": "picture",
		"desc": "图片",
		"value": 15
	}, {
    
    
		"type": "text",
		"desc": "文本",
		"value": 10
	}],
	"rejectRatio": [{
    
    
		"type": "picture",
		"desc": "图片",
		"value": 7
	}]
}]

ECharts FAQ

Problem: Error: Component series.pie not exists. Load it first.
Reason: No pie component is introduced.
Solution:

import 'echarts/lib/chart/pie'

Problem: ECharts3 removes noDataLoadingOption. When there is no data, it displays no data in the container. After switching, the chart cannot be displayed.
Solution:

  1. Determine whether the data has a value, and process it if there is no value
  2. Clear the option of the instance in setOption
  3. Extract the ECharts instance, don't create it every time
  4. The specific code can be seen in the above code block, if you are not sure, you can ask me privately
	// 默认用数据加载第一条渲染饼图,可能存在无数据情况,因此需要判断
    pieChartTotal.setOption(trendList[0] && !!trendList[0].totalRatio.length ? this.PieOption('total') : initPieOption)

Problem: Label formatter format content, need to wrap.
Reason: label is based on canvas, does not support html, only supports wrapping\nSolve
:

formatter: function (data) {
    
    
	var result = ''
	result = event.name + '\n' + '总量' + ' ' + event.data.total

	return result
},

Problem: The chart overflows the div and cannot be resolved adaptively
:

   window.addEventListener('resize', function () {
    
    
      lineChart.resize()
    })

Problem: The click event is bound multiple times, causing the callback to be triggered multiple times
.

  myChart.off('click')// 防止累计触发
  myChart.on('click', function (event) {
    
    
     const url = reportTypesMap[item.key]['url']

     if (!url) return false
     const href = window.location.href.split('#')[0]
     window.open(`${
      
      href}#${
      
      url}?time=${
      
      event.name}`)
   })

Guess you like

Origin blog.csdn.net/zn740395858/article/details/105181685