javascript - Hur man lägger till text inuti en donutdiagram med Chart.js?
Hur man renderar text inuti donutdiagrammet, jag använder ChartJs.
Svar #1
Ingen av de andra svaren ändrar textstorleken baserat på mängden text och storleken på degen. Här är ett litet skript som du kan använda för att dynamiskt placera valfri mängd text i mitten, och det kommer automatiskt att ändra storleken på den.
Exempel: http://jsfiddle.net/kdvuxbtj/
Den tar vilken mängd text som helst i en munkstorlek perfekt för munken. För att undvika att röra vid kanterna kan du ställa in en sidopadding som en procentandel av diametern på insidan av cirkeln. Om du inte ställer in det, blir standardvärdet 20. Du kan också ställa in färgen, typsnittet och texten. Tillägget tar hand om resten.
Plugin-koden kommer att starta med en bas teckenstorlek på 30px. Därefter kommer den att kontrollera textens bredd och jämföra den med cirkelns radie och ändra storlek baserat på förhållandet mellan cirkel/textbredd.
Det har en standardminsta teckenstorlek på 20px. Om texten skulle överskrida gränserna vid den minsta teckenstorleken, kommer den att bryta texten. Standard radavstånd när texten bryts är 25px, men du kan ändra det. Om du ställer in standardminsta teckenstorlek på falsk, kommer texten att bli oändligt liten och kommer inte att brytas.
Det har också en standard maximal teckenstorlek på 75px ifall det inte finns tillräckligt med text och bokstäverna skulle bli för stora.
Detta är plugin-koden
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 maxFontSize = centerConfig.maxFontSize || 75;
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, maxFontSize);
var minFontSize = centerConfig.minFontSize;
var lineHeight = centerConfig.lineHeight || 25;
var wrapText = false;
if (minFontSize === undefined) {
minFontSize = 20;
}
if (minFontSize && fontSizeToUse < minFontSize) {
fontSizeToUse = minFontSize;
wrapText = true;
}
// 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;
if (!wrapText) {
ctx.fillText(txt, centerX, centerY);
return;
}
var words = txt.split(' ');
var line = '';
var lines = [];
// Break words up into multiple lines if necessary
for (var n = 0; n < words.length; n++) {
var testLine = line + words[n] + ' ';
var metrics = ctx.measureText(testLine);
var testWidth = metrics.width;
if (testWidth > elementWidth && n > 0) {
lines.push(line);
line = words[n] + ' ';
} else {
line = testLine;
}
}
// Move the center up depending on line height and number of lines
centerY -= (lines.length / 2) * lineHeight;
for (var n = 0; n < lines.length; n++) {
ctx.fillText(lines[n], centerX, centerY);
centerY += lineHeight;
}
//Draw text in center
ctx.fillText(line, centerX, centerY);
}
}
});
Och du använder följande alternativ i ditt diagramobjekt
options: {
elements: {
center: {
text: 'Red is 2/3 the total numbers',
color: '#FF6384', // Default is #000000
fontStyle: 'Arial', // Default is Arial
sidePadding: 20, // Default is 20 (as a percentage)
minFontSize: 20, // Default is 20 (in px), set to false and text will not wrap.
lineHeight: 25 // Default is 25 (in px), used for when text wraps
}
}
}
Beröm till @Jenna Sloan för hjälp med matematiken som användes i denna lösning.
Svar #2
Här är ett rensat och kombinerat exempel på ovanstående lösningar - responsivt (försök att ändra fönstrets storlek), stöder självjusterande animationer, stöder verktygstips
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>UPPDATERING 17.06.16:
Samma funktionalitet men för 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>Svar #3
Jag skulle undvika att ändra chart.js-koden för att uppnå detta, eftersom det är ganska enkelt med vanlig CSS och HTML. Här är min lösning:
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;
}
Utdata ser ut så här:
Svar #4
Du måste ändra koden som: i chart.Doughnut.defaults
labelFontFamily : "Arial",
labelFontStyle : "normal",
labelFontSize : 24,
labelFontColor : "#666"
och sedan i funktionen drawPieSegments
ctx.fillText(data[0].value + "%", width/2 - 20, width/2, 200);
Se denna pull: https://github.com/nnnick/Chart.js/pull/35
här är en fiddle http://jsfiddle.net/mayankcpdixit/6xV78/ som implementerar samma sak.
Svar #5
Detta fungerar också på min sida...
<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" />
</div>
Svar #6
Du kan använda CSS med relativ/absolut positionering om du vill att det ska vara responsivt. Dessutom kan det enkelt hantera flera rader.
https://jsfiddle.net/mgyp0jkk/
<div class="relative">
<canvas id="myChart"></canvas>
<div class="absolute-center text-center">
<p>Some text</p>
<p>Some text</p>
</div>
</div>
Svar #7
Baserat på @rap-2-hs svar, här är koden för att använda text på en doughnut-diagram på Chart.js för användning i en dashboard liknande. Den har dynamisk teckenstorlek för responsiva alternativ.
HTML :
<div>text
<canvas id="chart-area" width="300" height="300" style="border:1px solid"/><div>
Skript :
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);
}
});
});
Här är exempel koden. Försök ändra storleken på fönstret. http://jsbin.com/wapono/13/edit


