[Chartjs]-Text inside Doughnut chart using Chart.js and Angular2, Ionic2

4👍

This can be achieved by creating / registering a plugin before generating the chart and you could create the plugin in the following way …

Chart.plugins.register({
    beforeDraw: function(chart) {
        var data = chart.data.datasets[0].data;
        var sum = data.reduce(function(a, b) {
            return a + b;
        }, 0);
        var width = chart.chart.width,
            height = chart.chart.height,
            ctx = chart.chart.ctx;
        ctx.restore();
        var fontSize = (height / 10).toFixed(2);
        ctx.font = fontSize + "px Arial";
        ctx.textBaseline = "middle";
        var text = sum,
            textX = Math.round((width - ctx.measureText(text).width) / 2),
            textY = height / 2;
        ctx.fillText(text, textX, textY);
        ctx.save();
    }
});

ᴅᴇᴍᴏ

// register plugin
Chart.plugins.register({
    beforeDraw: function(chart) {
        var data = chart.data.datasets[0].data;
        var sum = data.reduce(function(a, b) {
            return a + b;
        }, 0);
        var width = chart.chart.width,
            height = chart.chart.height,
            ctx = chart.chart.ctx;
        ctx.restore();
        var fontSize = (height / 10).toFixed(2);
        ctx.font = fontSize + "px Arial";
        ctx.textBaseline = "middle";
        var text = sum,
            textX = Math.round((width - ctx.measureText(text).width) / 2),
            textY = height / 2;
        ctx.fillText(text, textX, textY);
        ctx.save();
    }
});

// generate chart
var ctx = document.getElementById('canvas').getContext('2d');
var myChart = new Chart(ctx, {
    type: 'doughnut',
    data: {
        labels: ["Red", "Blue", "Yellow"],
        datasets: [{
            data: [300, 50, 100],
            backgroundColor: ["#FF6384", "#36A2EB", "#FFCE56"],
            hoverBackgroundColor: ["#FF6384", "#36A2EB", "#FFCE56"]
        }]
    },
    options: {
        responsive: false,
        legend: {
            display: false
        }
    }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<canvas id="canvas"></canvas>

1👍

If you guys are trying to add legend.
You should change the height by using

height = (chart.chartArea.top + chart.chartArea.bottom) / 2
textY = height;

using the chartArea is more correct.
Otherwise your text would ignore the height of legend and be located in the wrong place.

0👍

For anybody who is using ng2-charts^2.4.2" the registration of the inline plugin can be done via the baseChart directive’s input attribute [plugins].

First you have to define a plugins property holding and array of plugins. (You could also register your official plugins there plugins = [ChartDataLabels, {/*inline plugin*/}] )

For correct label placement inside the doughnut chart you have to take into account the position of the legend, which could be above, below or at the left or right side. So I tweaked @GRUNT and @ginagigo123 answers into an ultimate answer that is based on the following calculations

let textX = Math.round(((chart.chartArea.left + chart.chartArea.right) - ctx.measureText(text).width) / 2),
let textY = Math.round((chart.chartArea.top + chart.chartArea.bottom) / 2);
  

compoonent.ts


  @ViewChild(BaseChartDirective, { static: true })
  chartNgWrapper: BaseChartDirective;

  plugins = [
    {
      beforeDraw: function (chart: any) {
        let data = chart.data.datasets[0].data;
        let sum = (data as number[]).reduce(function (a, b) {
          return a + b;
        }, 0);
        let width = chart.chartArea.left + chart.chartArea.right,
          height = chart.chartArea.top + chart.chartArea.bottom,
          ctx = chart.chart.ctx;
        ctx.restore();
        let fontSize = (height / 10).toFixed(2);
        ctx.font = fontSize + 'px Arial';
        ctx.textBaseline = 'middle';
        let text = sum,
          textX = Math.round((width - ctx.measureText(text).width) / 2),
          textY = height / 2;
        ctx.fillText(text, textX, textY);
        ctx.save();
      },
    },
  ];

In case you are making an app that can switch language writing mode, you have to get the current rtl (right-to-left) value from somewhere (mine is defined in the legend) and add or substract based on it:

   let textX = chart.legend.options.rtl
       ? Math.round((width + ctx.measureText(text).width) / 2)
       : Math.round((width - ctx.measureText(text).width) / 2),

If you are manipulation the writing direction via an html element’s dir attribute (<app-root dir="ltr">) you can also get the current language writing mode from chart.ctx.direction, in this case it returns 'rtl' or 'ltr' strings

component.html


<canvas
  baseChart
  #chart
  [datasets]="doughnutChartData"
  [chartType]="doughnutChartType"
  [labels]="doughnutChartLabels"
  [options]="options"
  [plugins]="plugins"
>
</canvas>

Leave a comment