echarts环形图中间和外围都展示label的实现方案

906 阅读2分钟

echarts环形图,官方示例label的position为'outside'|'inside'|'inner'|'center',即环绕图形展示|展示在图形内部|在圆环图内部展示,然而,在需求中,环形图我们可能会需要满足label环绕展示的同时,中间也展示。如下图1所示,本文介绍两种方式实现如下效果:

image.png

图1

完整代码见:codesandbox.io/p/sandbox/v…

方法一:使用position:'outside'和position:'center'叠加两层图形

思考:position:'outside'可以满足label环绕图形展示,而position:'center'可以满足label在中心位置展示,既要环绕图形展示,又要在中间展示,我们为何不可把两种方式叠加起来呢? 于是,echarts的配置项写成了下面这样:

  const option = {
    tooltip: {
      trigger: "item",
    },
    legend: {
      top: "5%",
      left: "center",
    },
    series: [
      {
        name: "Access From",
        type: "pie",
        radius: ["40%", "70%"],
        avoidLabelOverlap: false,
        label: {
          show: true,
        },
        emphasis: {
          label: {
            show: true,
            fontSize: 30,
            fontWeight: "bold",
          },
        },
        labelLine: {
          show: false,
        },
        data: [
          { value: 1048, name: "Search" },
          { value: 735, name: "Direct" },
          { value: 580, name: "Email" },
          { value: 484, name: "Union" },
          { value: 300, name: "Video" },
        ],
      },
      {
        name: "Access From",
        type: "pie",
        radius: ["40%", "70%"],
        avoidLabelOverlap: false,
        label: {
          show: true,
          position: "center",
        },
        emphasis: {
          label: {
            show: true,
            fontSize: 30,
            fontWeight: "bold",
          },
        },
        labelLine: {
          show: false,
        },
        data: [
          { value: 1048, name: "Search" },
          { value: 735, name: "Direct" },
          { value: 580, name: "Email" },
          { value: 484, name: "Union" },
          { value: 300, name: "Video" },
        ],
      },
    ],
  };

于是,我们得到如下图2效果:

image.png

图2

看着好像没啥问题,hover一下呢?诶,我们发现如图3:*中间部分居然出现了label的重叠*

image.png

图3

这是怎么回事呢?首先,我们目前是两层图形叠加,position:'center'的图形处在series中的最后一条,那么它在最上层展示,鼠标进入时,展示它的hover效果:即emphasis中所配置的label样式。即图3中加粗放大的'Email'。同时,position:'center'时,label展示时,默认会展示出最大面积的占比name,即:小字search。由此,出现了重叠效果。既然如此,那我们label设置不展示,再设置个默认的highlight,鼠标hover切换highlight不就行了吗?代码如下:
 const option = {
    ...
    series: [
      ...,
      {
        ...
        label: {
          show: false,
          position: "center",
        },
        ...
      },
    ],
  };

  myChart.setOption(option);
  function setHighLight(seriesIndex, dataIndex) {
    myChart.dispatchAction({
      type: "downplay",
      seriesIndex: [0, 1],
      dataIndex: [0, 1, 2, 3, 4],
    });
    myChart.dispatchAction({
      type: "highlight",
      seriesIndex: seriesIndex,
      dataIndex: dataIndex,
    });
  }
  // 设置高亮默认值
  setHighLight(1, 0);
  
  myChart.on("mouseover", ({ dataIndex }) => {
    setHighLight(1, dataIndex);
  });
  
  const resizeFn = () => {
    myChart.resize();
  };
  window.addEventListener("resize", resizeFn);
  this.$on("hook:beforeDestroy", () => {
    myChart.off("mouseover");
    echarts.dispose(chartDom);
    window.removeEventListener("resize", resizeFn);
  });

大功告成看下效果图4:

image.png

图4

方法二:使用position:'outside'结合title实现

思考:使用title定位到圆环中间,通过hover切换样式实现。如果图本身有展示title的需求,可以使用subTitle实现,代码如下:

const chartDom = document.getElementById("chartTwo");
const myChart = echarts.init(chartDom);
const option = {
    title: {
      text: "Search",
      left: "center",
      top: "middle",
      fontSize: 30,
      fontWeight: "bold",
    },
    ...
    series: [
      {
        name: "Access From",
        type: "pie",
        radius: ["40%", "70%"],
        avoidLabelOverlap: false,
        label: {
          show: true,
        },
        emphasis: {
          label: {
            show: true,
            // fontSize: 30,
            // fontWeight: "bold",
          },
        },
        labelLine: {
          show: false,
        },
        data: [
          { value: 1048, name: "Search" },
          { value: 735, name: "Direct" },
          { value: 580, name: "Email" },
          { value: 484, name: "Union" },
          { value: 300, name: "Video" },
        ],
      },
    ],
    };

    myChart.setOption(option);
    function setHighLight(seriesIndex, dataIndex) {
    myChart.dispatchAction({
      type: "downplay",
      seriesIndex: [0],
      dataIndex: [0, 1, 2, 3, 4],
    });
    myChart.dispatchAction({
      type: "highlight",
      seriesIndex: seriesIndex,
      dataIndex: dataIndex,
    });
    }
    setHighLight(0, 0);
    myChart.on("mouseover", ({ data, seriesIndex, dataIndex }) => {
        myChart.setOption({
          title: {
            text: data.name,
          },
        });
        setHighLight(seriesIndex, dataIndex);
    });
    const resizeFn = () => {
        myChart.resize();
    };
    window.addEventListener("resize", resizeFn);
    this.$on("hook:beforeDestroy", () => {
        myChart.off("mouseover");
        echarts.dispose(chartDom);
        window.removeEventListener("resize", resizeFn);
    });

效果图5:

image.png

图5