D3.js 在rect svg中添加文本,并将其附加到圆环图中的圆弧

D3.js 在rect svg中添加文本,并将其附加到圆环图中的圆弧,d3.js,donut-chart,D3.js,Donut Chart,我想在甜甜圈图表中为每个弧添加标签。我通过获取每个弧的质心并添加来添加,但不知何故,它并没有添加到正确的位置。我想不出来,所以我需要一些帮助。我已经在代码笔中添加了代码。链接是。 我的甜甜圈应该是这样的 示例代码是: svg.selectAll(".dataText") .data(data_ready) .enter() .each(function (d) { var centroid = arc.centroid(d); d3.select(this)

我想在甜甜圈图表中为每个弧添加标签。我通过获取每个弧的质心并添加来添加,但不知何故,它并没有添加到正确的位置。我想不出来,所以我需要一些帮助。我已经在代码笔中添加了代码。链接是。 我的甜甜圈应该是这样的

示例代码是:

svg.selectAll(".dataText")
.data(data_ready)
.enter()
.each(function (d) {
  var centroid = arc.centroid(d);
  d3.select(this)
    .append('rect')
    .attr("class", "dataBG_" + d.data.value.label)
    .attr('x', (centroid[0]) - 28)
    .attr('y', (centroid[1]) - 5)
    .attr('rx', '10px')
    .attr('ry', '10px')
    .attr("width", 50)
    .attr("height", 20)
    .style('fill', d.data.value.color)
    .style("opacity", 1.0);
  d3.select(this)
    .append('text')
    .attr("class", "dataText_" + d.data.value.label)
    .style('fill', 'white')
    .style("font-size", "11px")
    .attr("dx", (centroid[0]) - 7)
    .attr("dy", centroid[1] + 7)
    .text(Math.round((d.data.value.value)) + "%");
});

提前感谢。

codepen上的“坏”状态与所需状态之间的区别在于,在您不喜欢的状态中,取质心,然后将文本置于其中心。粗圆弧的质心是从一个线段端点到另一个线段端点的圆弧中点。这大概是形状的“重心”,如果它有一些有限的厚度,并且是一个物理物体。我认为这不是你想要的。你想要的是外弧的中点。没有函数来生成它,但它很容易计算。此外,我认为您希望对文本定位点位于图表左侧的圆弧和位于图表右侧的圆弧进行不同的对齐。我将复制并修改您的代码,并添加注释

// for some reason I couldn't get Math.Pi to work in d3.js, so
// I'm just going to calculate it once here in the one-shot setup
var piValue = Math.acos(-1);
// also, I'm noting the inner radius here and calculating the
// the outer radius (this is similar to what you do in codepen.)
var innerRadius = 40
var thickness = 30
var outerRadius = innerRadius + thickness

svg.selectAll(".dataText")
.data(data_ready)
.enter()
.each(function (d) {
  // I'm renaming "centroid" to "anchor - just a    
  // point that relates to where you want to put
  // the label, regardless of what it means geometrically.

  // no more call to arc.centroid
  // var centroid = arc.centroid(d);

  // calculate the angle halfway between startAngle and
  // endAngle. We can just average them because the convention
  // seems to be that angles always increase, even if you
  // if you pass the 2*pi/0 angle, and that endAngle
  // is always greater than startAngle. I subtract piValue
  // before dividing by 2 because in "real" trigonometry, the
  // convention is that a ray that points in the 0 valued
  // angles are measured against the positive x-axis, which
  // is angle 0. In D3.pie conventions, the 0-angle points upward
  // along the y-axis. Subtracting pi/2 to all angles before
  // doing any trigonometry fixes that, because x and y
  // are handled normally.

  var bisectAngle = (d.startAngle + d.endAngle - piValue) / 2.0
  var anchor = [ outerRadius * Math.cos(bisectAngle), outerRadius * Math.sin(bisectAngle) ];

  d3.select(this)
    .append('rect')
    .attr("class", "dataBG_" + d.data.value.label)

    // now if you stopped and didn't change anything more, you'd
    // have something kind of close to what you want, but to get
    // it closer, you want the labels to "swing out" from the 
    // from the circle - to the left on the left half of the
    // the chart and to the right on the right half. So, I'm
    // replacing your code with fixed offsets to code that is
    // sensitive to which side we're on. You probably also want
    // to replace the constants with something related to the 
    // the dynamic size of the label background, but I leave
    // that as an "exercise for the reader".

    // .attr('x', anchor[0] - 28)
    // .attr('y', anchor[1] - 5)

    .attr('x', anchor[0] < 0 ? anchor[0] - 48 : anchor[0] - 2)
    .attr('y', anchor[1] - 10

    .attr('rx', '10px')
    .attr('ry', '10px')
    .attr("width", 50)
    .attr("height", 20)
    .style('fill', d.data.value.color)
    .style("opacity", 1.0);
  d3.select(this)
    .append('text')
    .attr("class", "dataText_" + d.data.value.label)
    .style('fill', 'white')
    .style("font-size", "11px")

    // changing the text centering code to match the box
    // box-centering code above. Again, rather than constants,
    // you're probably going to want something a that
    // that adjusts to the size of the background box

    // .attr("dx", anchor[0] - 7)
    // .attr("dy", anchor[1] + 7)

    .attr("dx", anchor[0] < 0 ? anchor[0] - 28 : anchor[0] + 14)
    .attr("dy", anchor[1] + 4)
    .text(Math.round((d.data.value.value)) + "%");
});
//由于某种原因,我无法让Math.Pi在d3.js中工作,所以
//我只想在这里计算一次,在一次性设置中
var piValue=Math.acos(-1);
//另外,我在这里记下了内半径,并计算了
//外半径(这类似于您在codepen中所做的操作。)
var内半径=40
var厚度=30
var outerRadius=内半径+厚度
svg.selectAll(“.dataText”)
.数据(数据准备就绪)
.输入()
.每个功能(d){
//我将“质心”重命名为“锚-只是一个
//与你想放在哪里有关的一点
//标签,无论其几何意义如何。
//不再调用arc.centroid
//var形心=弧形心(d);
//计算startAngle和
//endAngle,我们可以求平均值,因为惯例
//似乎角度总是在增加,即使你
//如果你通过2*pi/0的角度,那么这个端点角度
//总是大于startAngle。我减去piValue
//在除以2之前,因为在“实”三角中
//约定是指指向0的光线
//角度是相对于正x轴测量的,正x轴
//角度为0。在D3.0中,0角指向上
//沿y轴。将pi/2减去之前的所有角度
//做任何三角学都可以解决这个问题,因为x和y
//处理正常。
var平分角=(d.startAngle+d.endAngle-piValue)/2.0
var anchor=[outerRadius*Math.cos(平分角),outerRadius*Math.sin(平分角)];
d3.选择(本)
.append('rect')
.attr(“类”、“数据包”+d.data.value.label)
//如果你停下来不做任何改变,你会
//有一种接近你想要的东西,但是得到
//如果离得更近,您希望标签从
//从圆到左半部分的左边
//图表和右半部分的右边。所以,我
//用固定偏移量替换代码
//对我们站在哪一边很敏感。你可能也想
//将常量替换为与
//标签背景的动态大小,但我离开
//这是一个“读者练习”。
//.attr('x',锚点[0]-28)
//.attr('y',锚点[1]-5)
.attr('x',锚点[0]<0?锚点[0]-48:锚点[0]-2)
.attr('y',锚点[1]-10
.attr('rx','10px')
.attr('ry','10px')
.attr(“宽度”,50)
.attr(“高度”,20)
.style('fill',d.data.value.color)
.样式(“不透明度”,1.0);
d3.选择(本)
.append('文本')
.attr(“类”、“数据文本”+d.data.value.label)
.style('填充','白色')
.style(“字体大小”,“11px”)
//更改文本居中代码以匹配框
//上面的方框居中代码。同样,不是常量,
//你可能会想要一个
//将根据背景框的大小进行调整
//.attr(“dx”,锚点[0]-7)
//.attr(“dy”,锚[1]+7)
.attr(“dx”,锚点[0]<0?锚点[0]-28:锚点[0]+14)
.attr(“dy”,锚[1]+4)
.text(Math.round((d.data.value.value))+“%”;
});

我在你的codepen示例上测试了这段代码。如果我影响了你的示例,我向大家道歉-我不熟悉codepen,也不知道协作规则。这只是一个建议,通过一些调整可以提高效率,但我想让它保持平行,以明确我在更改什么,并hy.希望这能给你一些好主意。

我不太清楚你到底在追求什么,因为你发送的代码笔在底层数据方面看起来不同。你是想让标签位于半径的边缘吗?或者,你是想让标签实现碰撞检测吗?我想我是想弄清楚e您这边的优先级是多少。我正在尝试在半径边缘和质心添加标签。@scrollexThanks简要解释一下。这非常有用@cycollins@Max…你是在用“简短”来讽刺我吗?:-)我有一个倾向于做出非常冗长的回答。我只是试图用我想读的方式来解决这些问题。回答的黄金法则。上面我说的厚弧形质心是不正确的。考虑一个由“线”构成的圆弧。“-具有线性密度的东西。该物体的重心将位于沿径向轴的凹面内。对于厚弧,我必须做积分,但为了得到它的直觉,随着角度的减小,弧更接近于四边形,对于四边形,质心是中心。随着角度的增加,它看起来更像导线,所以质心沿着半径向中心移动,可能是i的内部