title: trying to create a donut chart with labels inside the curve using d3.js
body: <p>I'm trying to figure out how I can fit the text inside the arc and auto-adjust the font size of labels to fit into the arc so that text-overflow doesn't happen.</p>
  <p>I'm using D3.js to create a shape and then I'm trying to put the text on the arc and my tweaking my value I'm getting the text inside of the donut shape.</p>
  <p>The problem is that the text is not starting from the appropriate position and I want the text to be centralized too.</p>
  <p>Below is the code I have been working with and the current output:</p>
  <p><a href="https://i.stack.imgur.com/8zgzL.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/8zgzL.png" alt="enter image description here" /></a></p>
  <pre><code>function wrap(text, width) {
    let lineNumbers = 1;
  
    text.each(function () {
      let text = d3.select(this),
        line = [],
        lineNumbers = 1,
        lineNumber = 0,
        words = text.text().split(/\s+/).reverse();
      words2 = text.text().split(/\s+/).reverse();
      console.log(&quot;text&quot;, text);
  
      while ((word = words.pop())) {
        line.push(word);
        current_line = line.join(&quot; &quot;);
        console.log(&quot;current_line&quot;, current_line.length);
        if (current_line.length &gt; width) {
          line.pop();
          current_line = line.join(&quot; &quot;);
          line = [word];
          lineNumbers += 1;
        }
      }
      console.log(&quot;lineNumbers&quot;, lineNumbers);
      append_line = [];
      (lineHeight = 1), // ems
        (x = text.attr(&quot;x&quot;)),
        (y = text.attr(&quot;y&quot;)),
        (dy = 1), //parseFloat(text.attr(&quot;dy&quot;)),
        (tspan = text
          .text(null)
          .append(&quot;tspan&quot;)
          .attr(&quot;x&quot;, x)
          .attr(&quot;y&quot;, y)
          .attr(&quot;dy&quot;, dy + &quot;em&quot;));
      while ((word = words2.pop())) {
        line = 0;
        append_line.push(word);
        tspan.text(append_line.join(&quot; &quot;));
        if (tspan.node().getComputedTextLength() &gt; width) {
          append_line.pop();
          line = 1;
          tspan.text(append_line.join(&quot; &quot;));
          append_line = [word];
          if (line == 0) {
            tspan = text
              .append(&quot;tspan&quot;)
              .attr(&quot;x&quot;, x)
              .attr(&quot;y&quot;, y)
              .attr(&quot;dy&quot;, ++lineNumber * lineHeight + dy + &quot;em&quot;)
              .attr(&quot;dx&quot;, -9 + &quot;em&quot;)
              .text(word);
          }
          if (line == 1) {
            tspan = text
              .append(&quot;tspan&quot;)
              .attr(&quot;x&quot;, x)
              .attr(&quot;y&quot;, y)
              .attr(&quot;dy&quot;, ++lineNumber * lineHeight + dy + &quot;em&quot;)
              .attr(&quot;dx&quot;, -10 + &quot;em&quot;)
              .text(word);
          }
        }
      }
    });
  }
  let screenWidth = window.innerWidth;
  
  let margin = { left: 20, top: 20, right: 20, bottom: 20 },
    width = Math.min(screenWidth, 500) - margin.left - margin.right,
    height = Math.min(screenWidth, 500) - margin.top - margin.bottom;
  
  let svg = d3
    .select(&quot;#chart&quot;)
    .append(&quot;svg&quot;)
    .attr(&quot;width&quot;, width + margin.left + margin.right)
    .attr(&quot;height&quot;, height + margin.top + margin.bottom)
    .append(&quot;g&quot;)
    .attr(&quot;class&quot;, &quot;wrapper&quot;)
    .attr(
      &quot;transform&quot;,
      &quot;translate(&quot; +
        (width / 2 + margin.left) +
        &quot;,&quot; +
        (height / 2 + margin.top) +
        &quot;)&quot;
    );
  
  //////////////////////////////////////////////////////////////
  ///////////////////// Data &amp;  Scales /////////////////////////
  //////////////////////////////////////////////////////////////
  
  //Some random data
  let donutData = [
    { name: &quot;Antelope sjvadknk saoindosa savasa slahslas sasas&quot;, value: 15 },
    { name: &quot;Bear fhfxhxfhxgxhg hgxhx&quot;, value: 9 },
    { name: &quot;Cheetah&quot;, value: 19 },
    { name: &quot;Dolphin&quot;, value: 12 },
    { name: &quot;Elephant&quot;, value: 14 },
    { name: &quot;Flamingo&quot;, value: 21 },
    { name: &quot;Giraffe&quot;, value: 18 },
    { name: &quot;Other&quot;, value: 8 },
  ];
  
  //Create a color scale
  let colorScale = d3.scale
    .linear()
    .domain([1, 3.5, 6])
    .range([&quot;#2c7bb6&quot;, &quot;#ffffbf&quot;, &quot;#d7191c&quot;])
    .interpolate(d3.interpolateHcl);
  
  //Create an arc function
  let arc = d3.svg
    .arc()
    .innerRadius((width * 0.75) / 2)
    .outerRadius((width * 0.75) / 2 + 30);
  
  //Turn the pie chart 90 degrees counter clockwise, so it starts at the left
  let pie = d3.layout
    .pie()
    .startAngle((-90 * Math.PI) / 180)
    .endAngle((-90 * Math.PI) / 180 + 2 * Math.PI)
    .value(function (d) {
      return d.value;
    })
    .padAngle(0.01)
    .sort(null);
  
  //////////////////////////////////////////////////////////////
  //////////////////// Create Donut Chart //////////////////////
  //////////////////////////////////////////////////////////////
  
  //Create the donut slices and also the invisible arcs for the text
  svg
    .selectAll(&quot;.donutArcs&quot;)
    .data(pie(donutData))
    .enter()
    .append(&quot;path&quot;)
    .attr(&quot;class&quot;, &quot;donutArcs&quot;)
    .attr(&quot;d&quot;, arc)
    .style(&quot;fill&quot;, function (d, i) {
      if (i === 7) return &quot;#CCCCCC&quot;;
      //Other
      else return colorScale(i);
    })
    .each(function (d, i) {
      //Search pattern for everything between the start and the first capital L
      let firstArcSection = /(^.+?)L/;
  
      //Grab everything up to the first Line statement
      let newArc = firstArcSection.exec(d3.select(this).attr(&quot;d&quot;))[1];
      //Replace all the comma's so that IE can handle it
      newArc = newArc.replace(/,/g, &quot; &quot;);
  
      //If the end angle lies beyond a quarter of a circle (90 degrees or pi/2)
      //flip the end and start position
      if (d.endAngle &gt; (90 * Math.PI) / 180) {
        let startLoc = /M(.*?)A/, //Everything between the first capital M and first capital A
          middleLoc = /A(.*?)0 0 1/, //Everything between the first capital A and 0 0 1
          endLoc = /0 0 1 (.*?)$/; //Everything between the first 0 0 1 and the end of the string (denoted by $)
        //Flip the direction of the arc by switching the start en end point (and sweep flag)
        //of those elements that are below the horizontal line
        let newStart = endLoc.exec(newArc)[1];
        let newEnd = startLoc.exec(newArc)[1];
        let middleSec = middleLoc.exec(newArc)[1];
  
        //Build up the new arc notation, set the sweep-flag to 0
        newArc = &quot;M&quot; + newStart + &quot;A&quot; + middleSec + &quot;0 0 0 &quot; + newEnd;
      } //if
  
      //Create a new invisible arc that the text can flow along
      svg
        .append(&quot;path&quot;)
        .attr(&quot;class&quot;, &quot;hiddenDonutArcs&quot;)
        .attr(&quot;id&quot;, &quot;donutArc&quot; + i)
        .attr(&quot;d&quot;, newArc)
        .style(&quot;fill&quot;, &quot;none&quot;);
    });
  
  //Append the label names on the outside
  svg
    .selectAll(&quot;.donutText&quot;)
    .data(pie(donutData))
    .enter()
    .append(&quot;text&quot;)
    .attr(&quot;class&quot;, &quot;donutText&quot;)
    //Move the labels below the arcs for those slices with an end angle greater than 90 degrees
    .attr(&quot;dy&quot;, 20)
    .append(&quot;textPath&quot;)
    .attr(&quot;startOffset&quot;, &quot;50%&quot;)
    .style(&quot;text-anchor&quot;, &quot;middle&quot;)
    .attr(&quot;xlink:href&quot;, function (d, i) {
      return &quot;#donutArc&quot; + i;
    })
    .attr(&quot;font-size&quot;, function (d, i) {
      return 10;
    })
    .text(function (d) {
      return d.data.name;
    })
    .call(wrap, 100);
  
  </code></pre>
  <p>Any help is will be great and thanks in advance :)</p>