Chart.js Donut with rounded edges and a center in the center

I am trying to create rounded corners similar to this article here , but in combination with the text in the center, so far I have the code below, but I don’t how to combine both ideas

Any help would be appreciated!

image looks like below, donut with text image:

2HSOd.png

and my code is as follows to create the text inside the donut.

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 Lato"; this.chart.ctx.textBaseline = "middle"; var text = "40%", textX = Math.round((width - this.chart.ctx.measureText(text).width) / 2), textY = height / 2; this.chart.ctx.fillText(text, textX, textY); } }); var data = [{ label: "Wins %", value: 120, color: "#2ecc71" }, { label: "Losses %", value: 240, color: "#dddddd" }, { value: 0, color: "#888888" }]; var DoughnutTextInsideChart = new Chart($('#myChart') [0].getContext('2d')).DoughnutTextInside(data, { responsive: true, segmentShowStroke: false, animationEasing: "easeInOutQuint", }); 
+3
source share
3 answers

With v2.1.3 you can use pluginService for this


Preview

enter image description here


Script

 // round corners Chart.pluginService.register({ afterUpdate: function (chart) { if (chart.config.options.elements.arc.roundedCornersFor !== undefined) { var arc = chart.getDatasetMeta(0).data[chart.config.options.elements.arc.roundedCornersFor]; arc.round = { x: (chart.chartArea.left + chart.chartArea.right) / 2, y: (chart.chartArea.top + chart.chartArea.bottom) / 2, radius: (chart.outerRadius + chart.innerRadius) / 2, thickness: (chart.outerRadius - chart.innerRadius) / 2 - 1, backgroundColor: arc._model.backgroundColor } } }, afterDraw: function (chart) { if (chart.config.options.elements.arc.roundedCornersFor !== undefined) { var ctx = chart.chart.ctx; var arc = chart.getDatasetMeta(0).data[chart.config.options.elements.arc.roundedCornersFor]; var startAngle = Math.PI / 2 - arc._view.startAngle; var endAngle = Math.PI / 2 - arc._view.endAngle; ctx.save(); ctx.translate(arc.round.x, arc.round.y); console.log(arc.round.startAngle) ctx.fillStyle = arc.round.backgroundColor; ctx.beginPath(); ctx.arc(arc.round.radius * Math.sin(startAngle), arc.round.radius * Math.cos(startAngle), arc.round.thickness, 0, 2 * Math.PI); ctx.arc(arc.round.radius * Math.sin(endAngle), arc.round.radius * Math.cos(endAngle), arc.round.thickness, 0, 2 * Math.PI); ctx.closePath(); ctx.fill(); ctx.restore(); } }, }); // write text plugin Chart.pluginService.register({ afterUpdate: function (chart) { if (chart.config.options.elements.center) { var helpers = Chart.helpers; var centerConfig = chart.config.options.elements.center; var globalConfig = Chart.defaults.global; var ctx = chart.chart.ctx; var fontStyle = helpers.getValueOrDefault(centerConfig.fontStyle, globalConfig.defaultFontStyle); var fontFamily = helpers.getValueOrDefault(centerConfig.fontFamily, globalConfig.defaultFontFamily); if (centerConfig.fontSize) var fontSize = centerConfig.fontSize; // figure out the best font size, if one is not specified else { ctx.save(); var fontSize = helpers.getValueOrDefault(centerConfig.minFontSize, 1); var maxFontSize = helpers.getValueOrDefault(centerConfig.maxFontSize, 256); var maxText = helpers.getValueOrDefault(centerConfig.maxText, centerConfig.text); do { ctx.font = helpers.fontString(fontSize, fontStyle, fontFamily); var textWidth = ctx.measureText(maxText).width; // check if it fits, is within configured limits and that we are not simply toggling back and forth if (textWidth < chart.innerRadius * 2 && fontSize < maxFontSize) fontSize += 1; else { // reverse last step fontSize -= 1; break; } } while (true) ctx.restore(); } // save properties chart.center = { font: helpers.fontString(fontSize, fontStyle, fontFamily), fillStyle: helpers.getValueOrDefault(centerConfig.fontColor, globalConfig.defaultFontColor) }; } }, afterDraw: function (chart) { if (chart.center) { var centerConfig = chart.config.options.elements.center; var ctx = chart.chart.ctx; ctx.save(); ctx.font = chart.center.font; ctx.fillStyle = chart.center.fillStyle; 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.fillText(centerConfig.text, centerX, centerY); ctx.restore(); } }, }) 

and then

  ... options: { elements: { arc: { roundedCornersFor: 0 }, center: { // the longest text that could appear in the center maxText: '100%', text: '67%', fontColor: '#FF6684', fontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", fontStyle: 'normal', // fontSize: 12, // if a fontSize is NOT specified, we will scale (within the below limits) maxText to take up the maximum space in the center // if these are not specified either, we default to 1 and 256 minFontSize: 1, maxFontSize: 256, } } } }; 

You can get rid of a little code if you do not want it to be common (for example, if you fix fontSize, if you fix the index for rounding, etc.)


Fiddle - http://jsfiddle.net/cd3fdoy9/

+17
source

I added a code snippet to change the center text when a legend is clicked.

 afterDraw: function (chart) { if (chart.center) { var ctx = chart.chart.ctx; var i,a,s; var n = chart; var total = 0; for(i=0,a=(n.data.datasets||[]).length;a>i;++i){ s = n.getDatasetMeta(i); var x; for(x=0; x<s.data.length; x++){ if (!s.data[x].hidden) total += n.data.datasets[i].data[x]; } } ctx.save(); ctx.font = chart.center.font; ctx.fillStyle = chart.center.fillStyle; 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.fillText(total, centerX, centerY); ctx.restore(); } } 

Fiddle - http://jsfiddle.net/cd3fdoy9/49/

0
source

Slightly modified code to handle the use of arc.borderWidth in the arc, if used.

 Chart.pluginService.register({ afterUpdate: function (chart) { if (chart.config.options.elements.arc.roundedCornersFor !== undefined) { var arc = chart.getDatasetMeta(0).data[chart.config.options.elements.arc.roundedCornersFor]; arc.round = { x: (chart.chartArea.left + chart.chartArea.right + chart.config.options.elements.arc.borderWidth) / 2, y: (chart.chartArea.top + chart.chartArea.bottom) / 2, radius: (chart.outerRadius + chart.innerRadius) / 2, thickness: (chart.outerRadius - chart.innerRadius - (chart.config.options.elements.arc.borderWidth /2)) / 2 -1, backgroundColor: arc._model.backgroundColor }; } }, afterDraw: function (chart) { if (chart.config.options.elements.arc.roundedCornersFor !== undefined) { var ctx = chart.chart.ctx; var arc = chart.getDatasetMeta(0).data[chart.config.options.elements.arc.roundedCornersFor]; var startAngle = Math.PI / 2 - arc._view.startAngle; var endAngle = Math.PI / 2 - arc._view.endAngle; ctx.save(); ctx.translate(arc.round.x, arc.round.y); ctx.fillStyle = arc.round.backgroundColor; ctx.beginPath(); ctx.arc(arc.round.radius * Math.sin(startAngle), arc.round.radius * Math.cos(startAngle), arc.round.thickness, 0, 2 * Math.PI); ctx.arc(arc.round.radius * Math.sin(endAngle), arc.round.radius * Math.cos(endAngle), arc.round.thickness, 0, 2 * Math.PI); ctx.closePath(); ctx.fill(); ctx.restore(); } } 

});

0
source

Source: https://habr.com/ru/post/1012760/


All Articles