Calculating SVG donut slice label position server

2019-08-18 08:02发布

How can I calculate a slice text label to be positioned directly in the center of a slice in an svg donut chart?

I have an svg donut chart that is generated server side. I have the slices of the chart correctly implemented but I'm having some trouble figuring out the math to place each individual slice label inside the center of it's respective slice. The label will be the percentage of the slice it occupies.

This is a slimmed down version of the svg.

<svg width="100%" height="100%" viewBox="0 0 42 42">
  <circle cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="#d2d3d4" stroke-width="3" />
  <circle
    cx="21"
    cy="21"
    r="15.91549430918954"
    fill="transparent"
    stroke="#b1c94e"
    stroke-width="3"
    stroke-dasharray="25 75"
    stroke-dashoffset="25"
  />
  <!-- How do I calculate x and y so the text is in the center of the above slice. -->
  <text x="80%" y="30%" font-size="6" text-anchor="middle">25%</text>
</svg>

Here's a jsfiddle of the svg. https://jsfiddle.net/xgyzvnka/

标签: math svg
1条回答
时光不老,我们不散
2楼-- · 2019-08-18 08:35

This is how I would do it. Please change the value of the perc. Please read the comments in my code.

let r = 16;//circles radius
let perc = .15//percentage
//the angle used to draw the circle
let angle = 2*Math.PI * perc;
// the circle's circumference
let totalLength = base.getTotalLength();
//the length of the dash 
let length_perc = totalLength * perc;
//the length of the gap
let difference = totalLength * (1 - perc);

test.setAttributeNS(null,"stroke-dasharray",length_perc+", "+difference);
//rotate backwards 90degs. The center of rotation is the center of the circle; 21,21
test.setAttributeNS(null,"transform","rotate(-90,21,21)");

//the point where to draw the circle
let textPoint = {x:21 + r * Math.cos((angle - Math.PI)/2),
                 y:21 + r * Math.sin((angle - Math.PI)/2)}
text.setAttributeNS(null,"x",textPoint.x);
text.setAttributeNS(null,"y",textPoint.y);
//the text
text.textContent = perc * 100 + "%";
text{text-anchor:middle; dominant-baseline:middle;}
svg{width:90vh;}
<svg viewBox="0 0 42 42">
  <circle id="base" cx="21" cy="21" r="16" fill="transparent" stroke="#d2d3d4" stroke-width="3" />
  <circle id="test"
    cx="21"
    cy="21"
    r="16"
    fill="transparent"
    stroke="#b1c94e"
    stroke-width="3"
  />

  <text id="text"  font-size="6" text-anchor="middle"> </text>
</svg>

查看更多
登录 后发表回答