特别是对于饼图,d3.layout.pie() 函数将使用startAngle 和endAngle 属性格式化数据。半径可以是您想要的任何值(距离您希望放置标签的中心多远)。
将这些信息与一对 trigonometric functions 结合起来,您可以确定标签的 x 和 y 坐标。
考虑一下gist/block。
关于文本的 x/y 定位,神奇之处在于这一行(为便于阅读而格式化):
.attr("transform", function(d) {
return "translate(" +
( (radius - 12) * Math.sin( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) ) +
", " +
( -1 * (radius - 12) * Math.cos( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) ) +
")";
})
-
((d.endAngle - d.startAngle) / 2) + d.startAngle 以弧度表示我们的角度(θ)。
-
(radius - 12) 是我为文本位置选择的任意半径。
-
-1 * y 轴反转(见下文)。
使用的三角函数是:cos = adjacent / hypotenuse 和 sin = opposite / hypotenuse。但是我们需要考虑一些事情才能使这些与我们的标签一起使用。
- 0 角在 12 点钟方向。
- 角度仍沿顺时针方向增加。
- y 轴与标准笛卡尔坐标系相反。正 y 是 6 点钟方向 - 向下。
- 正 x 仍在 3 点钟方向 - 右。
这有点搞砸了,基本上有交换sin和cos的效果。然后我们的三角函数变为:sin = adjacent / hypotenuse 和 cos = opposite / hypotenuse。
用sin(radians) = x / r 和cos(radians) = y / r 替换变量名。经过一些代数运算后,我们可以分别根据 x 和 y 得到两个函数 r * sin(radians) = x 和 r * cos(radians) = y。从那里,只需将它们插入到 transform/translate 属性中。
这会将标签放在正确的位置,让它们看起来很漂亮,你需要一些这样的样式逻辑:
.style("text-anchor", function(d) {
var rads = ((d.endAngle - d.startAngle) / 2) + d.startAngle;
if ( (rads > 7 * Math.PI / 4 && rads < Math.PI / 4) || (rads > 3 * Math.PI / 4 && rads < 5 * Math.PI / 4) ) {
return "middle";
} else if (rads >= Math.PI / 4 && rads <= 3 * Math.PI / 4) {
return "start";
} else if (rads >= 5 * Math.PI / 4 && rads <= 7 * Math.PI / 4) {
return "end";
} else {
return "middle";
}
})
这将使从 10:30 到 1:30 和从 4:30 到 7:30 的标签锚定在中间(它们在上方和下方),从 1:30 点到 4:30 点的标签在左边(它们在右边),从 7:30 到 10:30 点的标签在右边(它们都在左边)。
相同的公式可用于任何 D3 径向图,唯一的区别是如何确定角度。
我希望这可以帮助任何偶然发现它的人!