chartjs / Chart.js

Simple HTML5 Charts using the <canvas> tag
https://www.chartjs.org/
MIT License
64.75k stars 11.92k forks source link

Label inside donut chart #78

Closed jomarmen closed 5 years ago

jomarmen commented 11 years ago

Hi,

I would like to be able to add a label inside a donut chart like this charts

lnDId

Thks

leoding86 commented 8 years ago

@Gabweb Maybe change for (var val of dataset.data) { total += val; } to for (var val of dataset.data) { total += parseFloat(val); } will be better. To avoid the data in dataset is string type.

esflores commented 8 years ago

@potatopeelings there's a way to change the plugin to accept html instead?

bf2016 commented 8 years ago

We want to show Doughnut Chart on each post of this wp website Black Friday coupons - but label should be in sidebar of chart.Trying so much.

dyorgio commented 7 years ago

@potatopeelings replacing afterDraw by beforeDraw avoid tooltip draw problems (hidden by center element)

emn178 commented 7 years ago

Hi, I implemented a plugin for showing percentage, value or label in pie or doughnut chart. https://github.com/emn178/Chart.PieceLabel.js It should be helpful.

tkruu commented 7 years ago

@dannysindra I applied your code and it worked but is it possible to use other variable names to replace 'ctx'? The whole chart stops working when I replace 'ctx' to another variable name. I can't only use 'ctx' because I need to put more than 6 charts into 1 page.

dannysindra commented 7 years ago

Hi @tkruu , I am not sure what is the problem. Maybe you could take a look at @Gabweb 's example above? He displayed two charts in 1 page successfully with two different configs.

andresaleite commented 7 years ago

I need only dynamically change the internal label. Can you do this on chartJs without using Jquery?

Preciso apenas alterar o label interno com dados dinâmicos, tem como fazer isso no chartJs sem uso de Jquery? (em português)

keithpickering commented 7 years ago

Any way to get labels outside of the chart? See https://github.com/chartjs/Chart.js/issues/1761

douwevdijk commented 7 years ago

I am also looking for a solution on #1761

AlonsoCauich commented 7 years ago

Help. I would like to display a percentage label for each segment in half pie/doughnut chart and display in the center the total sum of all segments like:

Take a look at the Code Current : https://jsfiddle.net/AlonsoCauich01/1y9spu7b/

quiero este

AlonsoCauich commented 7 years ago

I probably didn't explain myself well. Take a look at the image. I want the total value to change when a label is removed as show in the images, right now the total value stays the same when i remove a value.

https://jsfiddle.net/AlonsoCauich01/1y9spu7b/2/

mira

shpwebhost commented 7 years ago

@bf2016 You can disable label from chart.js and make label with css as like in this picture. If you want to show label inside donut then use the trailing comments.We have try as it is as you required in backend of our website smarthostingprice. On special requests we can show you how we have do it. nivce

scorgn commented 7 years ago

Here is a small script that will do it! http://jsfiddle.net/nkzyx50o/

image

It will take any amount of text in the doughnut sized perfect for the doughnut. To avoid touching the edges you can set a side-padding as a percentage of the diameter of the inside of the circle. If you don't set it, it will default to 20. You also the color, the font, and the text. The plugin takes care of the rest.

This code is partially based off of the code @potatopeelings provided however does not use a loop to continue resizing the text/redrawing, and only uses the beforeDraw function.

The plugin code will start with a base font size of 30px. From there it will check the width of the text and compare it against the radius of the circle and resize it based off the circle/text width ratio.

This is the plugin code

 Chart.pluginService.register({
  beforeDraw: function (chart) {
    if (chart.config.options.elements.center) {
      //Get ctx from string
      var ctx = chart.chart.ctx;

      //Get options from the center object in options
      var centerConfig = chart.config.options.elements.center;
      var fontStyle = centerConfig.fontStyle || 'Arial';
      var txt = centerConfig.text;
      var color = centerConfig.color || '#000';
      var sidePadding = centerConfig.sidePadding || 20;
      var sidePaddingCalculated = (sidePadding/100) * (chart.innerRadius * 2)
      //Start with a base font of 30px
      ctx.font = "30px " + fontStyle;

      //Get the width of the string and also the width of the element minus 10 to give it 5px side padding
      var stringWidth = ctx.measureText(txt).width;
      var elementWidth = (chart.innerRadius * 2) - sidePaddingCalculated;

      // Find out how much the font can grow in width.
      var widthRatio = elementWidth / stringWidth;
      var newFontSize = Math.floor(30 * widthRatio);
      var elementHeight = (chart.innerRadius * 2);

      // Pick a new font size so it will not be larger than the height of label.
      var fontSizeToUse = Math.min(newFontSize, elementHeight);

      //Set font settings to draw it correctly.
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      var centerX = ((chart.chartArea.left + chart.chartArea.right) / 2);
      var centerY = ((chart.chartArea.top + chart.chartArea.bottom) / 2);
      ctx.font = fontSizeToUse+"px " + fontStyle;
      ctx.fillStyle = color;

      //Draw text in center
      ctx.fillText(txt, centerX, centerY);
    }
  }
});

And you will use the following options in your chart object.

options: {
  elements: {
      center: {
      text: 'Desktop',
      color: '#36A2EB', //Default black
      fontStyle: 'Helvetica', //Default Arial
      sidePadding: 15 //Default 20 (as a percentage)
    }
  }
}
damonvjanis commented 7 years ago

@ShawnCorrigan this is exactly the fix needed to solve the original issue (from 2013) that @jomarmen was asking about.

Thank you for breaking out the plugin from the options in your comment, that was very helpful in understanding how to implement it. This worked perfectly for me, very much appreciated!

alrms commented 7 years ago

How to implement something like this? untitled

I edited the plugin but it's not absolutely correct: Chart.pluginService.register({ afterDraw(chart) { if (chart.center) { const centerConfig = chart.config.options.elements.center; const ctx = chart.chart.ctx; ctx.save(); ctx.font = chart.center.font; ctx.fillStyle = chart.center.fillStyle; ctx.textAlign = 'center'; ctx.textBaseline = 'top'; const centerX = (chart.chartArea.left + chart.chartArea.right); const centerY = (chart.chartArea.top + chart.chartArea.bottom); ctx.fillText(centerConfig.text, centerX, centerY); ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; const centerXnumb = (chart.chartArea.left + chart.chartArea.right) / 2; const centerYnumb = (chart.chartArea.top + chart.chartArea.bottom) / 2.4; ctx.fillText(centerConfig.textNumber, centerXnumb, centerYnumb); ctx.restore(); } } });

It is displayed something like this: cxzcxzczx The options is: elements: { center: { textNumber: ${sectorsCounter}, text: intl.formatMessage({ id: 'pie.sectors' }), fontColor: '#656566', fontFamily: 'EurobankSans', fontStyle: 'normal', minFontSize: 25, maxFontSize: 25, } },

dhniels commented 7 years ago

I added the center label easily with an absolute positioned HTML element, though having this feature natively to ChartJS would be cool. What brought me here and what I'm really pining for is something like @dannysindra 's example of having percentage labels (or even just having the tooltips always on) inside each area of the chart. I've tried implementing it in our Angular app but am having trouble. A built in solution to do this seems like a no-brainer. Add my voice to that feature request!

dhniels commented 7 years ago

@emn178 just tried your solution and its working! you are awesome!

MatthewSwarbrick commented 7 years ago

to get this working I extended the draw function for Chart,Tooltip with the following:

    if (this._chart.options.tooltips.displayPercentage) {
        var activeChart = this._chart;
    var cx = activeChart.width / 2;
    var cy = activeChart.chartArea.top + ((activeChart.height - activeChart.chartArea.top) / 2);
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.font = '28px Arial';
    ctx.fillStyle = "#63666A";

    var total = _.sum(activeChart.data.datasets[0].data);
    var percent = 100 * activeChart.data.datasets[0].data[vm.dataPoints[0].index] / total;
    ctx.fillText(Math.round(percent) + "%", cx, cy);
    }

You can now add on the options for tooltip whether to display percentage or not, and it'll appear in the center when hovering. The sum calculation is using lodash, this could be a simple function

Ashnarya commented 7 years ago

Hi, I've tried all the possibilities to make tooltip visible always. But nothing works. Kindly help to fix this, The data is passed as a string which is fetched from database.

var ctx2 = document.getElementById("PieChart2"); var options = { title: { display: true, maintainAspectRatio: true, responsive: false, text: 'Predicted risks from Data' }, events: [], animation: { duration: 0, onComplete: function () { var self = this;

          var elementsArray = [];
          Chart.helpers.each(self.data.datasets, function (dataset, datasetIndex) {
              Chart.helpers.each(dataset.metaData, function (element, index) {
                  var tooltip = new Chart.Tooltip({
                      _chart: self.chart,
                      _chartInstance: self,
                      _data: self.data,
                      _options: self.options,
                      _active: [element]
                  }, self);

                  tooltip.update();
                  tooltip.transition(Chart.helpers.easingEffects.linear).draw();
              }, self);
          }, self);
        }
      }
};
    var scatterChart = new Chart(ctx2, {
        type: 'pie',
        data: {
            labels: [${piePlot2.age}],
            datasets: [{
                backgroundColor: [

                    "#ff6969",
                    "#ffb4b4",
                    "red",
                    "#ff2d2d"

                  ],
                data: [<c:out value='${piePlot2.result}'/>]
            }]
        }
    });

image

When hovering, it is displays the data. But i want it be appeared always. Any help!

Thanks in Advance!

pachos7 commented 7 years ago

+1

Nothenn commented 7 years ago

Any news on whether this is being still being worked on or planned for a release as I noticed it has been added and removed to milestones multiples times.

sadikyalcin commented 7 years ago

@ShawnCorrigan that is excellent as it's responsive.

Edit: actually found an issue with this. Destroy / re adding the chart - the text keeps on adding on and get's blurry.

iratierana commented 6 years ago

Any of this solutions is working on my code, can someone help me?

Here is the HTML code: `

        </div>`

and javascript code: var confi2 = { type: 'doughnut', data: { datasets: [{ data: [ "33.33333", "33.33333", "33.33333", ], backgroundColor: [ "#FFFFFF", "#009688", "#FFFFFF", ], }, { data: [ "64", "36", ], backgroundColor: [ "#F41616", "#FFFFFF", ], },{ data: [ "111", ], backgroundColor: [ "#948F8F", ], }] }, options: { responsive: true, } }; var ctx = document.getElementById("chart-area").getContext("2d"); window.myDoughnut = new Chart(ctx, confi2);

Thank you on advise

abhinav1602 commented 6 years ago

Here is what worked for me. Thanks to google and such a great community out there. 😄 : CLOSED

//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();
  }
});

So what it actually does is, it takes the height, width of the chart and then places the desired text at half the height and width of your chart. You don't have to worry about the responsiveness and changing size(handled similarly) of the chart. Its completely dynamic this way.

gabarreto commented 6 years ago

I have almost no experience with JavaScript, and I need to put a FontAwesome icon inside the doughnut chart. It would be a chart to show the temperature, and the thermometer icon should be in it's middle. Could anyone help me?

fernandocode commented 6 years ago

@gabarreto Here is not the best place to ask questions about implementation. I recommend creating a question in StackOveflow with the tag chart.js.

gbrits commented 6 years ago

To expand on the plugin provided by @abhinav1602 to center text, I did the following to show percentage on my doughnut charts:

// Just copy and paste this bit above your chart inits. It will only apply to doughnuts.
Chart.pluginService.register({
  beforeDraw: function(chart) {
    if(chart.chart.chart.config.type=='doughnut'){
      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";
      // Ensure your first data is the percentage data in your dataset
      var chart_percent = chart.chart.chart.data.datasets[0].data[0];
      chart_percent = chart_percent || 0;
      var text = chart_percent+'%',
      textX = Math.round((width - ctx.measureText(text).width) / 2),
      textY = height / 2;
      ctx.fillText(text, textX, textY);
      ctx.save();
    }
  }
});

An example of my usage:

this.doughnutChart1 = new Chart(this.doughnutCanvas1.nativeElement, {
  type: 'doughnut',
  data: {
    datasets: [{
        // So this donut is 75% as per the first data item (will reflect with the txt plugin)
        data: [75,25],
        borderWidth: 0,
        backgroundColor: [
            '#67bebf',
            '#caced5',
        ],
        hoverBackgroundColor: [
            "#67bebf",
            "#caced5",
        ]
    }]
  },
  options: {
    cutoutPercentage: 90
  }
});
ciprianciurea commented 6 years ago

I've added a new plugin that allows to display multiple lines of text in the center of the doughnut on Github: chartjs-plugin-doughnutlabel if that helps. See the Demo. image

natibs commented 6 years ago

To place the text in the center, you need to consider the size of the font size. another fix for the solution of gbrits. in the textY `object:

textY = (height / 2) - (fontSize * 16 / 2)

simonbrunel commented 5 years ago

I'm going to close this issue since many solutions exist now and maintainers decided to not add it to the core package. I think the best approach is to use a plugin such as chartjs-plugin-doughnutlabel (thanks @ciprianciurea) and at some point, the datalabels plugin may also offer a (limited) way to center labels.

@ciprianciurea feel free to open a PR adding it to the docs.

DevOpsBandhala commented 2 years ago

Below the code work for me, but in the centre text (100%) appearing in another chart in same page !.

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 = "100%",
                          textX = Math.round((width - ctx.measureText(text).width) / 2),
                          textY = height / 2;
                          ctx.fillText(text, textX, textY);
                          ctx.save();
                        }
                      });
mesqueeb commented 7 months ago

Does anyone have an updated plugin for center doughnut labels for chartJS v4?

stockiNail commented 7 months ago

Does anyone have an updated plugin for center doughnut labels for chartJS v4?

AFAIK there isn't. There is a pending PR in chartjs-plugin-annotation for that: https://github.com/chartjs/chartjs-plugin-annotation/pull/825

Kinqdos commented 2 months ago

Can you please reopen this issue? Seems like no one cares about the plugin.