How to add text inside a donut chart using Chart.js?

How to visualize text inside a donut chart, I use ChartJs .

+47
javascript
Jan 07 '14 at 8:14
source share
12 answers

You need to change the code: in chart.Doughnut.defaults

 labelFontFamily : "Arial", labelFontStyle : "normal", labelFontSize : 24, labelFontColor : "#666" 

and then in the drawPieSegments function

ctx.fillText(data[0].value + "%", width/2 - 20, width/2, 200);

See this click: https://github.com/nnnick/Chart.js/pull/35

here is the fiddle http://jsfiddle.net/mayankcpdixit/6xV78/ that implements the same.

+23
Mar 03 '14 at 6:41
source share

Here is a cleaned and combined example of the above solutions - responsive (try resizing the window), supports self-aligning animations, supports tooltips

https://jsfiddle.net/cmyker/u6rr5moq/

 Chart.types.Doughnut.extend({ name: "DoughnutTextInside", showTooltip: function() { this.chart.ctx.save(); Chart.types.Doughnut.prototype.showTooltip.apply(this, arguments); this.chart.ctx.restore(); }, draw: function() { Chart.types.Doughnut.prototype.draw.apply(this, arguments); var width = this.chart.width, height = this.chart.height; var fontSize = (height / 114).toFixed(2); this.chart.ctx.font = fontSize + "em Verdana"; this.chart.ctx.textBaseline = "middle"; var text = "82%", textX = Math.round((width - this.chart.ctx.measureText(text).width) / 2), textY = height / 2; this.chart.ctx.fillText(text, textX, textY); } }); var data = [{ value: 30, color: "#F7464A" }, { value: 50, color: "#E2EAE9" }, { value: 100, color: "#D4CCC5" }, { value: 40, color: "#949FB1" }, { value: 120, color: "#4D5360" }]; var DoughnutTextInsideChart = new Chart($('#myChart')[0].getContext('2d')).DoughnutTextInside(data, { responsive: true }); 
 <html> <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js"></script> <body> <canvas id="myChart"></canvas> </body> </html> 

UPDATE 06/17/16:

Same functionality, but for chart.js version 2:

https://jsfiddle.net/cmyker/ooxdL2vj/

 var data = { labels: [ "Red", "Blue", "Yellow" ], datasets: [ { data: [300, 50, 100], backgroundColor: [ "#FF6384", "#36A2EB", "#FFCE56" ], hoverBackgroundColor: [ "#FF6384", "#36A2EB", "#FFCE56" ] }] }; Chart.pluginService.register({ beforeDraw: function(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 = "75%", textX = Math.round((width - ctx.measureText(text).width) / 2), textY = height / 2; ctx.fillText(text, textX, textY); ctx.save(); } }); var chart = new Chart(document.getElementById('myChart'), { type: 'doughnut', data: data, options: { responsive: true, legend: { display: false } } }); 
 <script src="//cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.6/Chart.bundle.js"></script> <canvas id="myChart"></canvas> 
+34
Jan 22 '16 at 13:05
source share

None of the other answers resize text based on the amount of text and the size of the donut. Here is a small script that you can use to dynamically place any text in the middle, and it will automatically resize it. http://jsfiddle.net/nkzyx50o/

Donut with average dynamic text

The donut will accept any amount of text perfect for the donut. To avoid touching the edges, you can set the lateral overlay as a percentage of the diameter of the inside of the circle. If you do not install it, it will be 20. You can also specify the color, font, and text. The plugin will take care of the rest.

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

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 use the following options in the chart object

 options: { elements: { center: { text: 'Desktop', color: '#36A2EB', //Default black fontStyle: 'Helvetica', //Default Arial sidePadding: 15 //Default 20 (as a percentage) } } } 
+30
Mar 26 '17 at 7:49
source share

I would not modify the chart.js code to accomplish this, since it is pretty easy with regular CSS and HTML. Here is my solution:

HTML:

 <canvas id="productChart1" width="170"></canvas> <div class="donut-inner"> <h5>47 / 60 st</h5> <span>(30 / 25 st)</span> </div> 

CSS

 .donut-inner { margin-top: -100px; margin-bottom: 100px; } .donut-inner h5 { margin-bottom: 5px; margin-top: 0; } .donut-inner span { font-size: 12px; } 

The result is as follows:

enter image description here

+23
Aug 07 '14 at 13:34
source share

Base on @ rap-2-h answer, Here is the code for using the text on the donut chart on Chart.js for use on the control panel. It has a dynamic font size for a flexible option.

HTML:

 <div>text <canvas id="chart-area" width="300" height="300" style="border:1px solid"/><div> 

Script:

 var doughnutData = [ { value: 100, color:"#F7464A", highlight: "#FF5A5E", label: "Red" }, { value: 50, color: "#CCCCCC", highlight: "#5AD3D1", label: "Green" } ]; $(document).ready(function(){ var ctx = $('#chart-area').get(0).getContext("2d"); var myDoughnut = new Chart(ctx).Doughnut(doughnutData,{ animation:true, responsive: true, showTooltips: false, percentageInnerCutout : 70, segmentShowStroke : false, onAnimationComplete: function() { var canvasWidthvar = $('#chart-area').width(); var canvasHeight = $('#chart-area').height(); //this constant base on canvasHeight / 2.8em var constant = 114; var fontsize = (canvasHeight/constant).toFixed(2); ctx.font=fontsize +"em Verdana"; ctx.textBaseline="middle"; var total = 0; $.each(doughnutData,function() { total += parseInt(this.value,10); }); var tpercentage = ((doughnutData[0].value/total)*100).toFixed(2)+"%"; var textWidth = ctx.measureText(tpercentage).width; var txtPosx = Math.round((canvasWidthvar - textWidth)/2); ctx.fillText(tpercentage, txtPosx, canvasHeight/2); } }); }); 

Here's an example code.try to resize a window. http://jsbin.com/wapono/13/edit

+10
Sep 24 '14 at 10:48
source share

This also works at my end ...

 <div style="width: 100px; height: 100px; float: left; position: relative;"> <div style="width: 100%; height: 40px; position: absolute; top: 50%; left: 0; margin-top: -20px; line-height:19px; text-align: center; z-index: 999999999999999"> 99%<Br /> Total </div> <canvas id="chart-area" width="100" height="100" /> 

enter image description here

+9
Aug 21 '14 at 11:20
source share

This is based on the Cmyker update for Chart.js 2. (posted as yet another answer, as I cannot comment yet)

I had a problem with text alignment in Chrome when the legend is displayed, since the height of the chart does not include this, so it does not align correctly in the middle. This is fixed, taking this into account when calculating fontSize and textY.

I calculated the percentage inside the method, not the given value, since I have several of them on the page. It is assumed that your chart has only 2 values ​​(otherwise is it a percentage of?), And the first is the one you want to show the percentage on. I also have many other diagrams, so I check for type = donut. I use donuts to show percentages so that it works for me.

The color of the text seems a bit successful and missed, depending on what things are being done in, etc., so I ran into a problem when resizing text that would change color (between black and primary color in one case, as well as secondary color and white are different), so I "save" any existing fill style, draw text (in the color of the primary data), and then restore the old fill style. (Maintaining the old fill style doesn't seem necessary, but you never know.)

https://jsfiddle.net/g733tj8h/

 Chart.pluginService.register({ beforeDraw: function(chart) { var width = chart.chart.width, height = chart.chart.height, ctx = chart.chart.ctx, type = chart.config.type; if (type == 'doughnut') { var percent = Math.round((chart.config.data.datasets[0].data[0] * 100) / (chart.config.data.datasets[0].data[0] + chart.config.data.datasets[0].data[1])); var oldFill = ctx.fillStyle; var fontSize = ((height - chart.chartArea.top) / 100).toFixed(2); ctx.restore(); ctx.font = fontSize + "em sans-serif"; ctx.textBaseline = "middle" var text = percent + "%", textX = Math.round((width - ctx.measureText(text).width) / 2), textY = (height + chart.chartArea.top) / 2; ctx.fillStyle = chart.config.data.datasets[0].backgroundColor[0]; ctx.fillText(text, textX, textY); ctx.fillStyle = oldFill; ctx.save(); } } }); 

 var data = { labels: ["Red","Blue"], datasets: [ { data: [300, 50], backgroundColor: ["#FF6384","#36A2EB"], }] }; Chart.pluginService.register({ beforeDraw: function(chart) { var width = chart.chart.width, height = chart.chart.height, ctx = chart.chart.ctx, type = chart.config.type; if (type == 'doughnut') { var percent = Math.round((chart.config.data.datasets[0].data[0] * 100) / (chart.config.data.datasets[0].data[0] + chart.config.data.datasets[0].data[1])); var oldFill = ctx.fillStyle; var fontSize = ((height - chart.chartArea.top) / 100).toFixed(2); ctx.restore(); ctx.font = fontSize + "em sans-serif"; ctx.textBaseline = "middle" var text = percent + "%", textX = Math.round((width - ctx.measureText(text).width) / 2), textY = (height + chart.chartArea.top) / 2; ctx.fillStyle = chart.config.data.datasets[0].backgroundColor[0]; ctx.fillText(text, textX, textY); ctx.fillStyle = oldFill; ctx.save(); } } }); var myChart = new Chart(document.getElementById('myChart'), { type: 'doughnut', data: data, options: { responsive: true, legend: { display: true } } }); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.6/Chart.bundle.js"></script> <canvas id="myChart"></canvas> 
+8
Jul 21 '16 at 12:17
source share

You can also insert mayankcpdixit code in the onAnimationComplete option:

 // ... var myDoughnutChart = new Chart(ctx).Doughnut(data, { onAnimationComplete: function() { ctx.fillText(data[0].value + "%", 100 - 20, 100, 200); } }); 

The text will be shown after the animation.

+6
Jul 10 '14 at 8:37
source share

I am creating a demo with 7 JQuieryUI Slider and ChartJs (with dynamic text inside)

 Chart.types.Doughnut.extend({ name: "DoughnutTextInside", showTooltip: function() { this.chart.ctx.save(); Chart.types.Doughnut.prototype.showTooltip.apply(this, arguments); this.chart.ctx.restore(); }, draw: function() { Chart.types.Doughnut.prototype.draw.apply(this, arguments); var width = this.chart.width, height = this.chart.height; var fontSize = (height / 140).toFixed(2); this.chart.ctx.font = fontSize + "em Verdana"; this.chart.ctx.textBaseline = "middle"; var red = $( "#red" ).slider( "value" ), green = $( "#green" ).slider( "value" ), blue = $( "#blue" ).slider( "value" ), yellow = $( "#yellow" ).slider( "value" ), sienna = $( "#sienna" ).slider( "value" ), gold = $( "#gold" ).slider( "value" ), violet = $( "#violet" ).slider( "value" ); var text = (red+green+blue+yellow+sienna+gold+violet) + " minutes"; var textX = Math.round((width - this.chart.ctx.measureText(text).width) / 2); var textY = height / 2; this.chart.ctx.fillStyle = '#000000'; this.chart.ctx.fillText(text, textX, textY); } }); var ctx = $("#myChart").get(0).getContext("2d"); var myDoughnutChart = new Chart(ctx).DoughnutTextInside(data, { responsive: false }); 

DEMO IN JSFIDDLE

enter image description here

+5
Mar 15 '16 at 21:19
source share

@ rap-2-h and @Ztuons Ch answer do not allow the use of the showTooltips parameter, but you can create and overlay a second canvas object in a single chart rendering.

The important part is the styling required in divs and for the canvas object itself, so that they display on top of each other.

 var data = [ {value : 100, color : 'rgba(226,151,093,1)', highlight : 'rgba(226,151,093,0.75)', label : "Sector 1"}, {value : 100, color : 'rgba(214,113,088,1)', highlight : 'rgba(214,113,088,0.75)', label : "Sector 2"}, {value : 100, color : 'rgba(202,097,096,1)', highlight : 'rgba(202,097,096,0.75)', label : "Sector 3"} ] var options = { showTooltips : true }; var total = 0; for (i = 0; i < data.length; i++) { total = total + data[i].value; } var chartCtx = $("#canvas").get(0).getContext("2d"); var chart = new Chart(chartCtx).Doughnut(data, options); var textCtx = $("#text").get(0).getContext("2d"); textCtx.textAlign = "center"; textCtx.textBaseline = "middle"; textCtx.font = "30px sans-serif"; textCtx.fillText(total, 150, 150); 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js"></script> <html> <body> <div style="position: relative; width:300px; height:300px;"> <canvas id="text" style="z-index: 1; position: absolute; left: 0px; top: 0px;" height="300" width="300"></canvas> <canvas id="canvas" style="z-index: 2; position: absolute; left: 0px; top: 0px;" height="300" width="300"></canvas> </div> </body> </html> 

Here's jsfiddle: https://jsfiddle.net/68vxqyak/1/

+2
Jul 21 '15 at 8:09
source share

First of all, you need to choose Chart.js! I use it in one of my current projects, and I really like it - it works great.

Although labels / tooltips are not yet part of the library, you can take a look at these three stretch requests:

And, as Cracker0dks mentioned, Chart.js uses canvas for rendering, so you can simply implement your own tooltips by interacting directly with it.

Hope this helps.

0
Jan 07 '14 at 8:32
source share

@Cmyker, great solution for chart.js v2

One small improvement: it makes sense to check the corresponding canvas identifier, see the snippet below. Otherwise, text (i.e. 75%) is also displayed in the middle of other types of diagrams on the page.

  Chart.pluginService.register({ beforeDraw: function(chart) { if (chart.canvas.id === 'doghnutChart') { let width = chart.chart.width, height = chart.chart.outerRadius * 2, ctx = chart.chart.ctx; rewardImg.width = 40; rewardImg.height = 40; let imageX = Math.round((width - rewardImg.width) / 2), imageY = (height - rewardImg.height ) / 2; ctx.drawImage(rewardImg, imageX, imageY, 40, 40); ctx.save(); } } }); 

Since the legend (see http://www.chartjs.org/docs/latest/configuration/legend.html ) increases the height of the chart, the height value must be obtained by the radius.

0
Dec 29 '17 at 10:32
source share



All Articles