José Carlos
José Carlos

Reputation: 2922

D3.js: misplaced labels

I'm newbie with d3.js and I'm trying to create a half donut chart and put labels in the middle of each arc.

I have made a developmen with CodeSandbox which works fine. The labels are placed correctly but when I bring that code to the code of my web application. The code is exactly the same. These labels are misplaced and I don't know why :(

The only difference between both codes is that the code of the first screen cap is inside a "Col" of Bootstrap and the second not as you can see in the CodeSandBox.

Here you can see a screencap of the half donut chart in my web application:

enter image description here

As you can see the labels of each arch and the labels of the right legend are misplaced when the same code in CodeSandbox works fine placing all the labels in the right place. As you can see in this screencap:

enter image description here

Why happen that? How can I make that labels would be placed right in both developments?

You can see all the code of my Half Donut Chart in this CodeSandoox

Edit Half Donut Chart

Edit I:

I have created a trace in my code to know the values depending of the web browser.

Here is the code where I center the labels to the arcs:

//We center the text inside the arc
arcs
  .append("svg:text")
  .attr("transform", function(d) {
    var textWidth = getTextWidth(
      (d.value.toFixed(2) + "%").toString(),
      "Roboto"
    );
    console.log(
      "d.value: " +
        d.value +
        " textWidth: " +
        textWidth +
        " arc.centroid(d)[0]: " +
        arc.centroid(d)[0]
    );
    return (
      "translate(" +
      (arc.centroid(d)[0] - textWidth) +
      "," +
      arc.centroid(d)[1] +
      ")"
    );
  })
  .attr("class", "label-half-donut")
  .attr("dy", ".35em")
  .attr("text-anchor", function(d) {
    // are we past the center?
    return (d.endAngle + d.startAngle) / 2 > Math.PI ? "end" : "start";
  })
  .text(function(d) {
    return d.value.toFixed(2) + "%";
  });

You can find all the code in CodeSandBox button.

The code of CodeSandBox I run it with Chrome and I've got this graphic

enter image description here

And the values returned in Chrome are:

d.value: 13.13 textWidth: 33.916015625 arc.centroid(d)[0]: -86.00117936328948

The tags which build the arc is this:

<g class="slice">
    <path fill="#17A2B8" d="M-124.99275003141527,-1.3462687637091173A125,125,0,0,1,-116.9896333088247,-44.02755612416768L-47.07429579530035,-16.85261627690394A50,50,0,0,0,-49.98187231803007,-1.3462687637091153Z"></path>
    <text transform="translate(-119.91719498828948,-16.12597743156403)" class="label-half-donut" dy=".35em" text-anchor="start">13.13%</text>
</g>

When I run the same code in my website with Firefox I've got this graphic:

enter image description here

The values returned are:

d.value: 13.13 textWidth: 38.150001525878906 arc.centroid(d)[0]: -86.00117936328948

And the tag which build the arc is:

<g class="slice">
    <path fill="#17A2B8" d="M-124.99275003141527,-1.3462687637091173A125,125,0,0,1,-116.9896333088247,-44.02755612416768L-47.07429579530035,-16.85261627690394A50,50,0,0,0,-49.98187231803007,-1.3462687637091153Z"></path>
    <text transform="translate(-124.15118088916839,-16.12597743156403)" class="label-half-donut" dy=".35em" text-anchor="start">13.13%</text>
</g>

The difference between both are that textWidth returned for the same value "13.13" returns different values and the x of translate function are differents because is calculated using this value.

How is that possible? Am I doing something wrong?

Edit II:

After the solution proposed by @Coola. This works for Firefox but not for Chrome :(

Firefox

enter image description here

Chrome

enter image description here

The value of textWidth is still different depending if I'm using Firefox or Chrome.

Firefox

d.value: 13.13 textWidth: 38.150001525878906 arc.centroid(d)[0]     -86.00117936328948
d.value: 59.7 textWidth: 38.150001525878906 arc.centroid(d)[0]: -33.49019847517988 
d.value: 23.88 textWidth: 38.150001525878906 arc.centroid(d)[0]: 59.22461768695275 
d.value: 17.91 textWidth: 38.150001525878906 arc.centroid(d)[0]: 84.79723004914864

Chrome

d.value: 13.13 textWidth: 33.916015625 arc.centroid(d)[0]: -86.00117936328948
d.value: 59.7 textWidth: 33.916015625 arc.centroid(d)[0]: -33.49019847517988
d.value: 23.88 textWidth: 33.916015625 arc.centroid(d)[0]: 59.22461768695275
d.value: 17.91 textWidth: 33.916015625 arc.centroid(d)[0]: 84.79723004914864

Upvotes: 0

Views: 93

Answers (1)

Coola
Coola

Reputation: 3142

Your translate for your text was not being calculated properly. Your x value on the transform should be arc.centroid(d)[0] - textWidth / 2.

So your transform should be like:

      .attr("transform", function(d) {
        var textWidth = getTextWidth(
          (d.value.toFixed(2) + "%").toString(),
          "Roboto"
        );
        console.log(
          "d.value: " +
            d.value +
            " textWidth: " +
            textWidth +
            " arc.centroid(d)[0]: " +
            arc.centroid(d)[0]
        );
        let x = arc.centroid(d)[0] - textWidth / 2;
        let y = arc.centroid(d)[1];
        return "translate(" + x + "," + y + ")";
      })

The working codesandbox is here.

Firefox Developer Edition v75.0b:

Screenshot of Firefox Codesandbox

Chrome v80.0.3987.149: enter image description here

Update

After discussion with the OP, they still had the problem in their workspace. We investigated a bit more and discovered that the issue was caused by inherited styles for the font-family, while the calculation of the textWidth was being done for Roboto font-family. To fix this we added the style as .style("font-family", "'Roboto', sans-serif") to the label text. This fixed the issue and the working codesandbox is here.

Upvotes: 1

Related Questions