Add text inside the Doughnut chart of the React-Chartjs-2 box to react
Asked Answered
N

7

14

I created a Donut chart, which works correctly but now I need to show the number 45 in the center of this, for example.

Where should I indicate the text to be displayed and the coordinates? In the options of the chart?

I'm using react component

class DoughnutChart extends React.Component {

  render() {
    const data = {
      datasets: [{
      data: [],
      backgroundColor: [
        '#999',
        '#eee'
      ]
    }],
     text: '45'
  };
    return (
       <Doughnut data={data} />
    );
  }
};

export default DoughnutChart;

EDIT

I found this plugin, but I cann't find how it applies to the react component

//Plugin for center text
Chart.pluginService.register({
  beforeDraw: function(chart) {
    var width = chart.chart.width,
    height = chart.chart.height,
    ctx = chart.chart.ctx;
    ctx.restore();
    var fontSize = (height / 160).toFixed(2);
    ctx.font = fontSize + "em sans-serif";
    ctx.textBaseline = "top";
    var text = "Foo-bar",
    textX = Math.round((width - ctx.measureText(text).width) / 2),
    textY = height / 2;
    ctx.fillText(text, textX, textY);
    ctx.save();
  }
});

Thanks for your help.

Norby answered 30/10, 2018 at 16:12 Comment(0)
C
14

I tried this and it worked

import { Doughnut } from "react-chartjs-2";

function DoughnutChart() {

 const data = {...}

 const options = {...}

 const plugins = [{
     beforeDraw: function(chart) {
      var width = chart.width,
          height = chart.height,
          ctx = chart.ctx;
          ctx.restore();
          var fontSize = (height / 160).toFixed(2);
          ctx.font = fontSize + "em sans-serif";
          ctx.textBaseline = "top";
          var text = "Foo-bar",
          textX = Math.round((width - ctx.measureText(text).width) / 2),
          textY = height / 2;
          ctx.fillText(text, textX, textY);
          ctx.save();
     } 
   }]



  return (
   
        <Doughnut 
          type="doughnut" 
          data={data} 
          options{options} 
          plugins={plugins} 
         />
  );
}

export default DoughnutChart;
Coffeecolored answered 25/5, 2021 at 11:58 Comment(2)
I don't know why but your answer fixed text pixilation issue.Luhe
The only thing missing in this answer is id. Please do add id: "xyz", above your beforeDraw function.Trademark
R
3

I don't believe React Chart JS has this option available. However, there are custom plugins out there that allow you to insert custom data labels inside of your doughnut charts. Please refer to this documentation on how to accomplish that.

ChartJS Plugin Datalabels

Russellrusset answered 30/10, 2018 at 16:38 Comment(2)
Thank you very much, but I have read about this library and I think it is not possible either. Because I need the value inside the chart.Norby
I found a plugin that can do this. I just edited my question, could You see it again please?Norby
A
2

From what I've seen from react-chartjs-2 it only has these properties:

data: (PropTypes.object | PropTypes.func).isRequired,
width: PropTypes.number,
height: PropTypes.number,
id: PropTypes.string,
legend: PropTypes.object,
options: PropTypes.object,
redraw: PropTypes.bool,
getDatasetAtEvent: PropTypes.func,
getElementAtEvent: PropTypes.func,
getElementsAtEvent: PropTypes.func
onElementsClick: PropTypes.func, // alias for getElementsAtEvent (backward compatibility)

Non of them seem to be text you can pass in to show your number in the middle. You can maybe use the legend prop and manipulate the object created for the legend to move it with css or have another div inside your render that displays the number and then style that to be inside the chart.

Another way you may be able to do it is by wrapping the Doughnut component in a div with another child inside that div that contains the text, like so:

    return( 
    <div className='wrapper'> 
        <div className='chart-number'>{this.state.text}</div>
        <Doughnut data={data} />
    </div>)

in your css then you will have to figure out how to position the chart-number div in the middle of the wrapper div, which will contain the chart.

If you are just starting to use this library, maybe look for a different one that suits your needs so you don't have to code around it!

Hope this helps :)

EDIT 1:

From what I see, you probably need to connect the Chart.pluginService.register code to your graph object somehow which is the <Doughnut /> component, then it will do the calculation before the redraw.

Adnopoz answered 30/10, 2018 at 16:33 Comment(1)
Thanks for your answer, it can be useful. I found a plugin that can do this. I just edited my question, could You see it again please?Norby
V
2

Here is a simple solution:

Step 01: add this options in your options

options: {
        centerText: {
            display: true,
            text: `90%`
        }
      .....
      .....

Step 02: Create a new method drawInnerText

drawInnerText = (chart) => {

    var width = chart.chart.width,
        height = chart.chart.height,
        ctx = chart.chart.ctx;

    ctx.restore();
    var fontSize = (height / 114).toFixed(2);
    ctx.font = fontSize + "em sans-serif";
    ctx.textBaseline = "middle";

    var text = chart.config.options.centerText.text,
        textX = Math.round((width - ctx.measureText(text).width) / 2),
        textY = height / 2;

    ctx.fillText(text, textX, textY);
    ctx.save();
}

Step 03: Invoke drawInnerText

componentWillMount() {
        Chart.Chart.pluginService.register({
            beforeDraw: function (chart) {                    
                if (chart.config.options.centerText.display !== null &&
                    typeof chart.config.options.centerText.display !== 'undefined' &&
                    chart.config.options.centerText.display) {
                    this.drawInnerText(chart);
                }
            },
        });
    }
Virtues answered 15/8, 2019 at 0:53 Comment(0)
B
2
function DoughnutChart({ data = {} }) {
 return (
   <Doughnut
     data={format(dataObj)}
     plugins={[
      {
        beforeDraw(chart) {
         const { width } = chart;
         const { height } = chart;
         const { ctx } = chart;
         ctx.restore();
         const fontSize = (height / 160).toFixed(2);
         ctx.font = `${fontSize}em sans-serif`;
         ctx.textBaseline = 'top';
         const { text } = "23";
         const textX = Math.round((width - ctx.measureText(text).width) / 2);
         const textY = height / 2;
         ctx.fillText(text, textX, textY);
         ctx.save();
       },
     },
   ]}
 />);

}

Blooper answered 15/7, 2021 at 5:27 Comment(1)
This part is wrong const { text } = "23"; Actually it should be like this: const text = "bla bla"Scotsman
R
0

I tried Jays Answer before but nowadays it doesnt work anymore. You need to specify an id inside the plugins array.

 const plugins = [{
 id : 'here comes your id for the specific plugin',
 beforeDraw: function(chart) {
  var width = chart.width,
      height = chart.height,
      ctx = chart.ctx;
      ctx.restore();
      var fontSize = (height / 160).toFixed(2);
      ctx.font = fontSize + "em sans-serif";
      ctx.textBaseline = "top";
      var text = "Foo-bar",
      textX = Math.round((width - ctx.measureText(text).width) / 2),
      textY = height / 2;
      ctx.fillText(text, textX, textY);
      ctx.save();
 } 

}]

Recompense answered 22/7, 2022 at 9:47 Comment(0)
M
0

I have tried Jay answer and at first it did not work so I had to make some updates to it and now it is working.

const plugins = {[
{
  id:"Id here",
  beforeDraw:function(chart:any) {
    let ctx = chart.ctx;
    let xAxis = chart.scales.x;
    let yAxis = chart.scales.y;
    let maxValue = Math.max(...chart.data.datasets[0].data);
    let minValue = Math.min(...chart.data.datasets[0].data);
    ctx.save();
    ctx.textAlign = 'center';
    ctx.font = '14px Roboto';
    ctx.fillStyle = 'blue';
    ctx.textAlign = 'left';
    ctx.fillText('Text1 = ', xAxis.left , yAxis.top + 15);
    ctx.fillText('Text2 = ', xAxis.left , yAxis.top + 40);
    ctx.fillText(maxValue + '°C', xAxis.left + 200, yAxis.top + 15);
    ctx.fillText(minValue + '°C', xAxis.left + 200, yAxis.top + 40);
    ctx.restore();
 },

}, ]}

Meany answered 5/9, 2022 at 7:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.