7

我正在使用 d3.js 创建一个带有外部标签的圆环图。使用基于每个饼图的质心的三角函数,我定位标签。

g.append("g")
        .attr("class", "percentage")
        .append("text")
            .attr("transform", function(d)
                { 
                    var c = arc.centroid(d);
                    var x = c[0];
                    var y = c[1];
                    var h = Math.sqrt(x*x + y*y);
                    return "translate(" + (x/h * obj.labelRadius) +  ',' + (y/h * obj.labelRadius) +  ")"; 
                }
            ) 
            .attr("dy", ".4em")
            .attr("text-anchor", function(d) 
                {
                    return (d.endAngle + d.startAngle)/2 > Math.PI ? "end" : "start";
                }
            )
            .text(function(d) { return d.data.percentage+"%"; });

我最终要完成的是重新排列饼图边缘之外的标签,以防止重叠。

在此处输入图像描述

我尝试解决问题的方法之一是定义设置的“锚点”,标签可以放置在其中,保证它们不会重叠。问题是将质心映射到锚点并在切片和标签之间保留一些视觉对应感(当切片很薄时特别困难)。

在此处输入图像描述

上图显示了锚点的可能位置(所示切片的质心)。有了这些位置,就不可能有重叠。

使问题更加复杂的是,当标签(它们是水平的)靠近饼图的顶部或底部时,它们比位于饼图的右侧或左侧时更容易重叠。

关于如何解决这个问题的任何想法?

[编辑] 根据 meetamit 的建议,我实施了以下操作:

.attr("dy", function(d)
{
    var c = arc.centroid(d);
        var x = c[0];
        var y = c[1];
        var h = Math.sqrt(x*x + y*y);
        var dy = y/h * obj.labelRadius; 
    dy=dy*fontSizeParam*.14/heightParam);
    return (dy)+"em";
})

它有点帮助,并为标签提供了一些空间,但仍在寻找一种涵盖所有情况的解决方案......

4

2 回答 2

1

你不能创建两条弧线吗?一个用于图表,一个用于标签?

// first arc used for drawing the pie chart
var arc = d3.svg.arc()
  .outerRadius(radius - 10)
  .innerRadius(0);

// label attached to first arc
g.append("text")
  .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
  .attr("dy", ".35em")
  .style("text-anchor", "middle")
  .text(function(d) { return d.data.age; });

// second arc for labels
var arc2 = d3.svg.arc()
  .outerRadius(radius + 20)
  .innerRadius(radius + 20);

// label attached to second arc
g.append("text")
  .attr("transform", function(d) { return "translate(" + arc2.centroid(d) + ")"; })
  .attr("dy", ".35em")
  .style("text-anchor", "middle")
  .text(function(d) { return d.data.age; });
于 2013-10-23T21:12:41.500 回答
1

程序员 John Williams 提出了一个很好的、实用的基于d3.js的解决方案:

https://www.safaribooksonline.com/blog/2014/03/11/solving-d3-label-placement-constraint-relaxing/

它应该适用于具有合理限制的情况,例如上面讨论的最多 12 个标签。文章中还提到了更高级的算法,但这种简单的方法实际上可能会在与足够的标签内容约束一起使用时,给出比其他方法产生的视觉外观更有序的结果。

于 2015-08-25T09:38:56.027 回答