Echarts饼图引导线、标签左侧左对齐,右侧右对齐

1,279 阅读3分钟

饼图实现如下ui效果代码备份:

image.png image.png

UI1实现

image.png

关键点:

  1. 标签格式自定义,引导线上为百分比,引导线下为数据名
  2. 标签百分比文本颜色与饼图玫瑰瓣颜色一致
  3. 引导线第一段长度固定,第二段长度不确定(需要延伸至饼图Canvas边缘)
  4. 左侧引导线、标签文字左对齐,右侧引导线、标签文字右对齐
useEffect(() => {
    if(!visitorStayTime.length) return;
    let chart = echarts.init(document.getElementById('visitor-stay-time-chart'));
    const color = ['#65E4E9', '#6FA8FF', '#3A74C9', '#9F74DD', '#C7CB42'];
    let option = {
      color: color,
      legend: {
        show: false
      },
      series: [
        {
          type: 'pie',
          radius: ['35%', '55%'],
          center: ['50%', '50%'],
          roseType: 'area',
          itemStyle: {
            borderRadius: 0
          },
          label: {
            alignTo: 'edge',
            // 标签内容自定义,formatter与rich配合实现1、2两点
            formatter: function (params) {
              const arr = ['zero', 'one', 'two', 'three', 'four']
              return '{' + arr[params.dataIndex] + '|' + params.value + '%}\n{name|' + params.name + '}'
            },
            edgeDistance: 10,
            lineHeight: 16,
            // 标签百分比文本颜色与饼图玫瑰瓣颜色一致
            rich: {
              zero: {
                fontSize: '30px',
                color: color[0],
                padding: [0, 0, 15, 0]
              },
              one: {
                fontSize: '30px',
                color: color[1],
                padding: [0, 0, 15, 0]
              },
              two: {
                fontSize: '30px',
                color: color[2],
                padding: [0, 0, 15, 0]
              },
              three: {
                fontSize: '30px',
                color: color[3],
                padding: [0, 0, 15, 0]
              },
              four: {
                fontSize: '30px',
                color: color[4],
                padding: [0, 0, 15, 0]
              },
              name: {
                fontSize: 14,
                color: '#fff',
                padding: [5, 0, 0, 0]
              }
            }
          },
          // 引导线第一段长度固定,第二段长度设置为0,引导线终点位置由labelLayout中points[2][0]确定
          labelLine: {
            length: 15, 
            length2: 0,
            maxSurfaceAngle: 80
          },
          labelLayout: function (params) {
            // 左侧引导线、标签文字左对齐,右侧引导线、标签文字右对齐
            const isLeft = params.labelRect.x < chart.getWidth() / 2;
            const points = params.labelLinePoints;
            // Update the end point.
            points[2][0] = isLeft
              ? params.labelRect.x
              : params.labelRect.x + params.labelRect.width;
            return {
              // 更新引导线点
              labelLinePoints: points
            };
          },
          data: visitorStayTime
        }
      ]
    };
    chart.setOption(option);
  }, [visitorStayTime])

UI2实现

image.png

关键点:

  1. 标签格式自定义,引导线上为数据值
  2. 标签文本颜色与饼图玫瑰瓣颜色一致
  3. 引导线第一段长度固定,第二段长度不确定(需要延伸至饼图Canvas边缘)
  4. 一个chart,一个legend,两个饼图
  5. 当一个chart,两个饼图时,在两个饼图内都实现左侧引导线、标签文字左对齐,右侧引导线、标签文字右对齐
useEffect(() => {
    if (!alarmEventStatisticsPerMonth.length || !alarmEventStatisticsPerYear.length) return;
    let chart = echarts.init(document.getElementById('build-warn-chart'));
    const COLORS = ['#C7CB42', '#65E4E9', '#6FA8FF', '#9F74DD', '#6FA8FF']
    let option = {
      color: COLORS,
      tooltip: {
        trigger: 'item',
        formatter: '{a} <br/>{b} : {c} ({d}%)'
      },
      legend: {
        itemWidth: 8,
        itemHeight: 8,
        icon: 'circle',
        textStyle: {
          color: '#fff',
          width: 140,
          height: 14,
          padding: [0, 0, 0, 5]
        },
        left: 'center',
        bottom: 0
      },
      grid: {
        left: '3%',
        right: '4%',
        top: '1%',
        bottom: '3%'
      },
      series: [
        {
          name: '月度统计',
          type: 'pie',
          radius: [20, 50],
          center: ['25%', '40%'],
          roseType: 'radius',
          label: {
            alignTo: 'edge',
            // 标签内容自定义,formatter与rich配合实现1、2两点
            formatter: function (params) {
              const arr = ['zero', 'one', 'two', 'three', 'four']
              return '{' + arr[params.dataIndex] + '|' + params.value + '}'
            },
            edgeDistance: 10,
            lineHeight: 16,
            // 标签文本颜色与饼图玫瑰瓣颜色一致
            rich: {
              zero: {
                fontSize: '20px',
                color: COLORS[0],
                padding: [0, 0, 20, 0]
              },
              one: {
                fontSize: '20px',
                color: COLORS[1],
                padding: [0, 0, 20, 0]
              },
              two: {
                fontSize: '20px',
                color: COLORS[2],
                padding: [0, 0, 20, 0]
              },
              three: {
                fontSize: '20px',
                color: COLORS[3],
                padding: [0, 0, 20, 0]
              },
              four: {
                fontSize: '20px',
                color: COLORS[4],
                padding: [0, 0, 20, 0]
              }
            }
          },
          // 引导线第一段长度固定,第二段长度设置为0,引导线终点位置由labelLayout中points[2][0]确定
          labelLine: {
            length: 15,
            length2: 0,
            maxSurfaceAngle: 80
          },
          labelLayout: function (params) {
            const isLeft = params.labelRect.x < chart.getWidth() / 2;
            // 左侧饼图自定义引导线
            const points = params.labelLinePoints;
            // Update the end point.
            points[2][0] = isLeft
              ? params.labelRect.x 
              : params.labelRect.x - chart.getWidth() / 2;
            // 左侧饼图修改标签位置
            let x = isLeft
              ? params.labelRect.x 
              : params.labelRect.x - chart.getWidth() / 2;
            return {
              labelLinePoints: points,
              x: x
            };
          },
          data: alarmEventStatisticsPerMonth
        },
        {
          name: '年度统计',
          type: 'pie',
          radius: [20, 50],
          center: ['75%', '40%'],
          roseType: 'radius',
          label: {
            alignTo: 'edge',
            formatter: function (params) {
              const arr = ['zero', 'one', 'two', 'three', 'four']
              return '{' + arr[params.dataIndex] + '|' + params.value + '}'
            },
            edgeDistance: 10,
            lineHeight: 16,
            rich: {
              zero: {
                fontSize: '20px',
                color: COLORS[0],
                padding: [0, 0, 20, 0]
              },
              one: {
                fontSize: '20px',
                color: COLORS[1],
                padding: [0, 0, 20, 0]
              },
              two: {
                fontSize: '20px',
                color: COLORS[2],
                padding: [0, 0, 20, 0]
              },
              three: {
                fontSize: '20px',
                color: COLORS[3],
                padding: [0, 0, 20, 0]
              },
              four: {
                fontSize: '20px',
                color: COLORS[4],
                padding: [0, 0, 20, 0]
              }
            }
          },
          labelLine: {
            length: 15,
            length2: 0,
            maxSurfaceAngle: 80
          },
          labelLayout: function (params) {
            const isLeft = params.labelRect.x < chart.getWidth() / 2;
            // 右侧饼图自定义引导线
            const points = params.labelLinePoints;
            // Update the end point.
            points[2][0] = isLeft
              ? params.labelRect.x + chart.getWidth() / 2
              : params.labelRect.x + params.labelRect.width;
            // 右侧饼图修改标签位置
            let x = isLeft
              ? params.labelRect.x + chart.getWidth() / 2
              : params.labelRect.x + params.labelRect.width;
            return {
              labelLinePoints: points,
              x: x
            };
          },
          data: alarmEventStatisticsPerYear
        }
      ]
    };
    chart.setOption(option);
  }, [alarmEventStatisticsPerMonth, alarmEventStatisticsPerYear])