echarts饼图如何在指引线上增加一个圆点?

如何使用echarts在饼图的指引线上增加一个自定义圆点呢?

示例效果如下image.png

我实现的效果一:image.png

效果一配置代码:

const option = {
    series: [
      {
        name: "下月应收件保费占比最高的产品",
        type: "pie",
        radius: ["43%", "73.4%"],
        center: ["50%", "50%"],
        hoverAnimation: false,
        labelLine: {
          normal: {
            length: fontSize(12),
            length2: fontSize(40),
            lineStyle: {
              color: "rgba(255, 255, 255, 0.65)",
              cap: "round",
            },
          },
        },
        label: {
          overflow: "truncate",
          formatter: (params) => {
            const value = showData[params.dataIndex].value;
            let name = params.name;
            return `{name|${name}}{icon| ●}\n{spaceLine|}\n{value|${numDivFo(
              showPercent(value)
            )}}`;
          },
          padding: [fontSize(8), -fontSize(4), fontSize(0), -fontSize(4)],
          rich: {
            icon: {
              fontSize: fontSize(18),
              color: "auto",
            },
            name: {
              fontSize: fontSize(14),
              fontWeight: 400,
              // padding: [0, 10, 0, 4],
              color: "#fff",
              title: "1223245",
            },
            spaceLine: {
              fontSize: fontSize(8),
            },
            value: {
              fontSize: fontSize(18),
              fontWeight: 600,
              padding: [0, 0, 0, 0],
              color: "#fff",
            },
          },
        },
        data: calcData,
      }
    ]
}

可以看到圆点不会总是贴着指引线,而是总是处在文字右侧,显然不是设计想要的效果。

我实现的效果二:
image.png
效果二配置代码:

const option = {
    series: [
      {
        name: "下月应收件保费占比最高的产品",
        type: "pie",
        radius: ["43%", "73.4%"],
        center: ["50%", "50%"],
        hoverAnimation: false,
        avoidLabelOverlap: false,
        labelLine: {
          normal: {
            length: fontSize(12),
            length2: fontSize(40),
            lineStyle: {
              color: "rgba(255, 255, 255, 0.65)",
              cap: "round",
            },
          },
        },
        label: {
          overflow: "truncate",
          formatter: (params) => {
            const value = showData[params.dataIndex].value;
            let name = params.name;
            return `{name|${name}}\n{spaceLine|}\n{value|${numDivFo(
              showPercent(value)
            )}}`;
          },
          padding: [fontSize(8), -fontSize(4), fontSize(0), -fontSize(4)],
          rich: {
            icon: {
              fontSize: fontSize(18),
              color: "auto",
            },
            name: {
              fontSize: fontSize(14),
              fontWeight: 400,
              // padding: [0, 10, 0, 4],
              color: "#fff",
              title: "1223245",
            },
            spaceLine: {
              fontSize: fontSize(8),
            },
            value: {
              fontSize: fontSize(18),
              fontWeight: 600,
              padding: [0, 0, 0, 0],
              color: "#fff",
            },
          },
        },
        data: calcData,
      },
      {
        name: "下月应收件保费占比最高的产品",
        type: "pie",
        silent: true, // 取消高亮
        radius: ["43%", "73.4%"],
        center: ["50%", "50%"],
        hoverAnimation: false,
        avoidLabelOverlap: false,
        labelLine: {
          show: false,
          normal: {
            length: fontSize(12),
            length2: fontSize(40),
            lineStyle: {
              color: "rgba(255, 255, 255, 0)",
            },
          },
        },
        label: {
          normal: {
            formatter: (params) => {
              return "{icon|●}";
            },
            padding: [0, -fontSize(18), fontSize(20), -fontSize(18)],
            rich: {
              icon: {
                fontSize: fontSize(18),
                color: "auto",
              },
            },
          },
        },
        data: calcData,
        z: -1,
      },
    ],
}

可以看到效果二也不理想,效果二是用两个pie拼凑出来的,但是因为pie1文字拥挤导致触发了鼠标hover才显示文字的效果,但是pie2的圆点并不会触发这个效果,导致单独出现一个圆点而没有文字。


以上就是我目前做到的程度,我看到echarts有提供自定义画图表的接口,但是从零开始画未免也太费时间了,我的想法是能不能继承现有的饼图类,然后在实现自己的饼图类再去实例化呢?貌似官方没有这类的接口。

阅读 1.7k
avatarAI BotBETA

确实,ECharts 目前并没有直接提供一个简单的接口来在饼图的指引线上增加一个自定义的圆点。但是,你可以尝试通过扩展 ECharts 的现有功能或使用自定义系列 (custom series) 来实现这个需求。

使用自定义系列 (custom series)

自定义系列允许你使用 HTML Canvas 或 SVG 来绘制图形,这给了你很大的灵活性。你可以通过计算每个扇区的角度和位置,然后在正确的位置绘制一个圆点。

下面是一个使用自定义系列来绘制饼图并在每个扇区上添加圆点的基本示例:

const option = {
  series: [{
    type: 'custom',
    renderItem: function (params, api) {
      // 计算扇区的角度和位置
      const startAngle = api.value(0);
      const endAngle = api.value(1);
      const centerX = api.coord([api.width / 2, api.height / 2])[0];
      const centerY = api.coord([api.width / 2, api.height / 2])[1];
      const radius = Math.min(api.width / 2, api.height / 2) * 0.8;

      // 计算圆点的位置
      const pointX = centerX + radius * Math.cos((startAngle + endAngle) / 2);
      const pointY = centerY + radius * Math.sin((startAngle + endAngle) / 2);

      // 使用 Canvas API 绘制圆点
      return {
        type: 'circle',
        shape: {
          cx: pointX,
          cy: pointY,
          r: 5, // 圆点的大小
        },
        style: {
          fill: 'red', // 圆点的颜色
        },
        zlevel: 1, // 设置 z-level,确保圆点显示在标签上方
      };
    },
    data: [
      // 你的数据,例如:[{value: 335}, {value: 310}, {value: 234}]
    ],
  }],
};

继承现有的饼图类

虽然 ECharts 没有直接提供继承现有图表的接口,但你可以尝试查看 ECharts 的源代码,了解它是如何绘制饼图的,然后基于这个逻辑添加自己的代码来绘制圆点。这需要对 ECharts 的内部实现有深入的了解,并且可能需要一些 JavaScript 的高级知识,如原型链和继承。

总结

使用自定义系列可能是更直接和灵活的方法,但它需要你对 Canvas 或 SVG 绘图有一定的了解。如果你对 ECharts 的内部实现非常熟悉,并且想要更深入地定制图表,那么继承现有的饼图类可能是一个更好的选择。不过,请注意,这两种方法都可能需要你花费一些时间来学习和实验。

1 个回答

兄弟你的代码实在跑不出来,给你精简了一些,其他的属性你自己再配置。

    let echartData = [
      {
        name: 'A类',
        value: '3720'
      },
      {
        name: 'B类',
        value: '2920'
      },
      {
        name: 'C类',
        value: '2200'
      },
      {
        name: 'D类',
        value: '1420'
      },
      {
        name: 'E类',
        value: '3200'
      },
      {
        name: 'F类',
        value: '2420'
      },
      {
        name: 'G类',
        value: '2200'
      },
      {
        name: 'H类',
        value: '1420'
      },
      {
        name: 'I类',
        value: '3200'
      },
      {
        name: 'J类',
        value: '2420'
      }
    ];
    option = {
      series: [
        {
          name: '下月应收件保费占比最高的产品',
          type: 'pie',
          radius: ['43%', '73.4%'],
          center: ['50%', '50%'],
          hoverAnimation: false,
          data: echartData,
          label: {
            normal: {
              formatter: (params) => {
                return (
                  '{icon|●}{name|' + params.name + '}\n{value|' + params.value + '}'
                );
              },
              // padding: [0 , -100, 25, -100],
              rich: {
                icon: {
                  fontSize: 16,
                  color: 'inherit'
                },
                name: {
                  fontSize: 18,
                  padding: [0, 0, 0, 10],
                  color: '#000'
                },
                value: {
                  fontSize: 14,
                  fontWeight: 'bolder',
                  padding: [10, 0, 0, 20],
                  color: 'inherit'
                  // color: '#333333'
                }
              }
            }
          }
        }
      ]
    };
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题