弧外标签(饼图)d3.js

我是d3.js的新手,我试图做一个饼图,我只有一个问题:我不能在我的弧线之外得到我的标签…标签的位置是arc.centroid

arcs.append("svg:text") .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; }) .attr("text-anchor", "middle") 

谁能帮助我呢?

我可以解决这个问题 – 与三angular:)。

看小提琴: http : //jsfiddle.net/nrabinowitz/GQDUS/

基本上,调用arc.centroid(d)返回一个[x,y]数组。 你可以使用毕达哥拉斯定理来计算斜边,它是从饼图中心到弧心的线的长度。 然后,您可以使用计算x/h * desiredLabelRadiusy/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) + ")"; }) 

这里唯一的缺点是, text-anchor: middle不是一个好的select了 – 基于我们所在的馅饼的哪一侧,设置text-anchor会更好:

 .attr("text-anchor", function(d) { // are we past the center? return (d.endAngle + d.startAngle)/2 > Math.PI ? "end" : "start"; }) 

谢谢!

我发现了一个不同的方式来解决这个问题,但你似乎更好:-)

我创build了一个更大半径的第二个弧,并用它来定位我的标签。

 ///// 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) + "%"}); 

特别是对于饼图, d3.layout.pie()函数将使用startAngleendAngle属性格式化数据。 半径可以是任何你想要的(离你想要放置标签的中心有多远)。

将这些信息与几何三angular函数结合,可以确定标签的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 ) ) + ")"; }) 
  • ((d.endAngle - d.startAngle) / 2) + d.startAngle以弧度给出了我们的angular度(theta)。
  • (radius - 12)是我为文本位置select的任意半径。
  • -1 * y轴被反转(见下文)。

使用的三angular函数是: cos = adjacent / hypotenusesin = opposite / hypotenuse 。 但是我们需要考虑一些事情,以使这些与我们的标签一起工作。

  1. 0angular在12点。
  2. angular度依然沿顺时针方向增加。
  3. y轴与标准笛卡尔坐标系相反。 正y是朝着6点钟的方向。
  4. 正x仍然在3点 – 右。

这个东西很麻烦,基本上有交换sincos的效果。 我们的三angular函数然后变成: sin = adjacent / hypotenusecos = opposite / hypotenuse

用variables名代替我们有sin(radians) = x / rcos(radians) = y / r 。 经过一些代数运算后,我们可以用x和y分别得到两个函数r * sin(radians) = xr * 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径向图都可以使用相同的公式,唯一不同的是你如何确定angular度。

我希望这有助于任何人绊倒它!

我不知道这是否有帮助,但是我可以创build弧线,将文本放置在弧线上,并在其外部。 在一种情况下,我将弧的大小放置在弧内,我将弧上的文本旋转以匹配弧的angular度。 另一方面,我把文本放在弧的外面,它只是水平的。 该代码位于: http : //bl.ocks.org/2295263

我最好的,

坦率

下面的CoffeeScript为我工作,让标签仍然在饼形片内,但朝着外边:

 attr 'transform', (d) -> radius = width / 2 # radius of whole pie chart d.innerRadius = radius * 0.5 d.outerRadius = radius * 1.5 'translate(' + arc.centroid(d) + ')' 

该函数计算饼图的饼图的中心点。 我添加一个函数来获得弧的中心点。 下面是基于我的新function的图像。 请参阅链接: https : //github.com/mbostock/d3/issues/1124

这是我很满意的低成本答案。 它把所有的标签水平推出(这是我有额外的空间):

 g.append("text") .attr("transform", function(d) { var pos = arc.centroid(d); return "translate(" + (pos[0] + (.5 - (pos[0] < 0)) * radius) + "," + (pos[1]*2) + ")"; }) .attr("dy", ".35em") .style("text-anchor", function(d) { return arc.centroid(d)[0] > 0 ? "start" : "end"; }) .text(function(d) { return d.label; }); 

所以,如果你想用一个非常漂亮的传说,而不是随机的文字在附近。 我发现了一个很好的标签解决scheme。 如何使用D3js将图例添加到饼图? 以及如何集中饼图?

是的,宝贝,这是SOHCAHTOA

 function coordinates_on_circle(hyp, angle){ var radian= angle * Math.PI / 180 //trig uses radians return { x: Math.cos(radian) * hyp, //adj = cos(r) * hyp y: Math.sin(radian) * hyp //opp = sin(r) * hyp } } var radius=100 var angle=45 coordinates_on_circle(radius, angle) 

我通过在饼图外部绘制百分比来达到同样的效果,这里是代码http://bl.ocks.org/farazshuja/e2cb52828c080ba85da5458e2304a61f

 g.append("text") .attr("transform", function(d) { var _d = arc.centroid(d); _d[0] *= 2.2; //multiply by a constant factor _d[1] *= 2.2; //multiply by a constant factor return "translate(" + _d + ")"; }) .attr("dy", ".50em") .style("text-anchor", "middle") .text(function(d) { if(d.data.percentage < 8) { return ''; } return d.data.percentage + '%'; });