数据可视化开发的时候,经常会用到饼图pie,那么轴标签一般必不可少,如何使用了像echarts等库,自带解决方案。

可是我们不一定会用库,像d3提供了很多基础svg绘制能力,label就需要自己绘制,这个时候就需要处理label防重叠。

网上相关的答案比较少,也都不智能,数据一旦异常聚集就会出现问题。

经过思考,下面给出一种比较容易实现,效果还不错的方案。

仔细想想,我们的难点在哪里。其实把饼图中心店为坐标原点,分割成数学上的四个象限的话,对于 第四个象限是很好做防重叠处理的,在第四个象限的数据,我们只需要按照顺序,判断下一个label的坐标y是否覆盖了前一个lable的y坐标,如果覆盖了,那么把当前lable的坐标往上移即可。

看下伪代码:

// 假如我们已经有了一组包含第四象限lable的group数据
/**
* 辅助迭代函数
* @param prev
* @param item
* @param i
*/
function handlePos(prev: GroupItem, item: GroupItem, i: number) {
    if (i > 0) {
      const { y: prevY } = prev.pointEnd;
      const { y } = item.pointEnd;
      const disY = y - prevY;
      const isPositiveY =
        item.quadrant === Quadrant.One || item.quadrant === Quadrant.Four;
      if (
        Math.abs(disY) < labelDy ||
        (isPositiveY && disY >= 0) ||
        (!isPositiveY && disY <= 0)
      ) {
        if (isPositiveY) {
          const tempY = (prevY < y ? prevY : y) - labelDy;
          item.pointEnd.y = tempY;
        } else {
          const tempY = (prevY < y ? y : prevY) + labelDy;
          item.pointEnd.y = tempY;
        }
      }
    }
    return item;
}
group.map((item, i) => {
    return handlePos(group[i - 1], item, i);
});

这个处理完毕的label在第四象限内就 都是不重叠的了。

那么仔细想想 第一二三象限 和 第四象限的处理区别,我们会发现,在方向上第二象限和第四象限是一样的。难点是第一象限 和 第三象限我们需要对数据进行reverse反转处理,计算label坐标,完成之后再reverse反转回去进行绘制,不理解的认真思考一下。
下面是参考代码:

// 分割成四个象限数据
let groups: GroupItem[][] = new Array(4).fill(null);
labels.forEach((item) => {
const group = groups[item.quadrant] || [];
groups[item.quadrant] = group;
group.push(item);
});
groups = groups.map((group, index) => {
    if (!group) return group;
    if (index === Quadrant.Four || index === Quadrant.Two) {
      group.map((item, i) => {
        return handlePos(group[i - 1], item, i);
      });
    } else {
      group = group
        .reverse()
        .map((item, i) => {
          return handlePos(group[i - 1], item, i);
        })
        .reverse();
    }
    return group;
});

donglegend
910 声望82 粉丝

长安的风何时才能吹到边梁?


引用和评论

0 条评论