Ibe*_*nen 44 javascript svg label d3.js pie-chart
我是d3.js的新手,我正试图用它制作一个饼图.我只有一个问题:我不能在我的弧线外得到我的标签......标签是用arc.centroid定位的
arcs.append("svg:text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
Run Code Online (Sandbox Code Playgroud)
谁可以帮我这个?
nra*_*itz 63
我可以解决这个问题 - 用三角法:).
请参阅小提琴:http://jsfiddle.net/nrabinowitz/GQDUS/
基本上,调用arc.centroid(d)
返回一个[x,y]
数组.您可以使用毕达哥拉斯定理来计算斜边,斜边是从饼图中心到圆心的线的长度.然后,您可以使用计算x/h * desiredLabelRadius
并y/h * desiredLabelRadius
计算x,y
标签锚的期望值:
.attr("transform", function(d) {
var c = arc.centroid(d),
x = c[0],
y = c[1],
// pythagorean theorem for hypotenuse
h = Math.sqrt(x*x + y*y);
return "translate(" + (x/h * labelr) + ',' +
(y/h * labelr) + ")";
})
Run Code Online (Sandbox Code Playgroud)
这里唯一的缺点就是text-anchor: middle
不再是一个很好的选择 - 你最好text-anchor
根据我们所在的馅饼的哪一方面设置:
.attr("text-anchor", function(d) {
// are we past the center?
return (d.endAngle + d.startAngle)/2 > Math.PI ?
"end" : "start";
})
Run Code Online (Sandbox Code Playgroud)
cla*_*mk1 17
特别是对于饼图,该d3.layout.pie()
函数将使用a startAngle
和endAngle
属性格式化数据.半径可以是您想要的任何东西(您想要放置标签的中心距离多远).
将这些信息与几个三角函数相结合,可以确定标签的x和y坐标.
关于文本的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 ) ) +
")";
})
Run Code Online (Sandbox Code Playgroud)
((d.endAngle - d.startAngle) / 2) + d.startAngle
给出了我们以弧度表示的角度(θ). (radius - 12)
是我为文本位置选择的任意半径. -1 *
y轴反转(见下文). 使用的trig函数是:cos = adjacent / hypotenuse
和sin = opposite / hypotenuse
.但是我们需要考虑一些事情来使这些工作与我们的标签一起使用.
这让事情变得相当混乱,并且基本上具有交换sin
和交换的效果cos
.然后我们的trig函数变为: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";
}
})
Run Code Online (Sandbox Code Playgroud)
这将使标签从10点30分到1点30分,从4点30分到7点30分停在中间(它们在上面和下面),标签从1 :30点到4点半左边的锚(他们是在右边),标签从7点30分到10点30分停在右边(他们是到了剩下).
任何D3径向图都可以使用相同的公式,唯一的区别在于如何确定角度.
我希望这有助于任何人绊倒它!
Ibe*_*nen 15
谢谢!
我发现了一种解决这个问题的不同方法,但你的似乎更好:-)
我创建了一个半径更大的第二个弧,用它来定位我的标签.
///// Arc Labels /////
// Calculate position
var pos = d3.svg.arc().innerRadius(r + 20).outerRadius(r + 20);
// Place Labels
arcs.append("svg:text")
.attr("transform", function(d) { return "translate(" +
pos.centroid(d) + ")"; })
.attr("dy", 5)
.attr("text-anchor", "middle")
.attr("fill", function(d, i) { return colorL(i); }) //Colorarray Labels
.attr("display", function(d) { return d.value >= 2 ? null : "none"; })
.text(function(d, i) { return d.value.toFixed(0) + "%"});
Run Code Online (Sandbox Code Playgroud)
我不知道这是否有帮助,但我能够创建弧形,我将文本放在弧上和外面.在一种情况下,我将弧的大小放在弧内,我在弧上旋转文本以匹配弧的角度.在另一个地方,我将文本放在弧形之外,它只是水平的.代码位于:http://bl.ocks.org/2295263
我最好的,
坦率