Search code examples
javascriptreactjschartshighchartspie-chart

Need help in centering the data labels on the top of slice of pie chart in highchart


need help in centering the pie data labels on top of slices. I'm using React Highchart.

Currently the Chart looks like this.

Current PIE chart

Sample Code for label centering:

function redrawDatalabels() {
  var chart = this,
    cX = chart.series[0].center[0],
    cY = chart.series[0].center[1],
    shapeArgs,
    ang,
    posX,
    posY,
    bBox;

  Highchart.each(chart.series[0].data, function (point, i) {
    if (point.dataLabel) {
      bBox = point.dataLabel.getBBox();
      shapeArgs = point.shapeArgs;
      ang = (shapeArgs.end - shapeArgs.start) / 2 + shapeArgs.start;
      const labelPos = point.labelPosition.alignment === "right" ? 1 : -1;
      posX = cX + (shapeArgs.r / 2) * Math.cos(ang) + (labelPos * bBox.width) / 2;
      posY = cY + (shapeArgs.r / 2) * Math.sin(ang) - bBox.height / 2;
      point.dataLabel._pos.x = posX;
      point.dataLabel._pos.y = posY;
    }
  });
  chart.series[0].placeDataLabels();
}

CodeSandBox: https://codesandbox.io/s/hc-animate-9j72hn?file=/src/App.js


Solution

  • You can Center your labels on top of your chart slices, the main changes will be on the options.plotOptions.pie.dataLabels.distance property to control the distance of your labels.

    So the fixed code will be something like this :

    import Highcharts from "highcharts";
    import { each } from "lodash";
    import { PureComponent } from "react";
    import "./styles.css";
    
    function redrawDatalabels() {
      var chart = this,
        cX = chart.plotWidth / 2,
        cY = chart.plotHeight / 2,
        shapeArgs,
        ang,
        posX,
        posY,
        bBox;
    
      each(chart.series[0].data, function (point, i) {
        if (point.dataLabel) {
          bBox = point.dataLabel.getBBox();
          shapeArgs = point.shapeArgs;
          ang = (shapeArgs.end - shapeArgs.start) / 2 + shapeArgs.start;
          let labelPos = point.labelPosition.alignment === "right" ? 1 : -1;
          labelPos = (labelPos * bBox.width) / 2;
          posX = cX + (shapeArgs.r / 2) * Math.cos(ang) + labelPos;
          posY = cY + (shapeArgs.r / 2) * Math.sin(ang) - bBox.height / 2;
          point.dataLabel._pos.x = posX;
          point.dataLabel._pos.y = posY;
        }
      });
      chart.series[0].placeDataLabels();
    }
    
    
    const options = {
      chart: {
        animation: false,
        renderTo: "chart1",
        type: "pie",
      },
      legend: {
        enabled: true,
      },
      plotOptions: {
        chart: {
          animation: false,
          renderTo: "chart1",
          type: "pie",
          events: {
            load: redrawDatalabels,
            redraw: redrawDatalabels
          }
        },
        legend: {
          enabled: true
        },
        pie: {
          allowPointSelect: true,
          cursor: "pointer",
          dataLabels: {
            enabled: true,
            connectorWidth: 0,
            format: "{point.percentage:.1f}%",
            distance: -25, // Adjust the distance of labels from the cente
            style: {
              color:
                (Highcharts.theme && Highcharts.theme.contrastTextColor) || "black",
              textOutline: "none", 
            },
          },
          size: "80%",
          innerSize: "65%",
        },
      },
      series: [
        {
          type: "pie",
          name: "Browser share",
          data: [
            ["Firefox", 50],
            ["IE", 10],
            ["Chrome", 30],
            ["Safari", 5],
            ["Opera", 5],
          ],
        },
      ],
    };
    
    class App extends PureComponent {
      componentDidMount() {
        this.chart1 = Highcharts.chart(options);
      }
    
      render() {
        return (
          <div className="App">
            <div id="chart1" />
          </div>
        );
      }
    }
    
    export default App;
    
    

    I edited this code on your sandbox and it looks like this :

    enter image description here