Réponses:
Vous devez modifier le code comme: dans chart.Doughnut.defaults
labelFontFamily : "Arial",
labelFontStyle : "normal",
labelFontSize : 24,
labelFontColor : "#666"
puis en fonction drawPieSegments
ctx.fillText(data[0].value + "%", width/2 - 20, width/2, 200);
Voir ce pull: https://github.com/nnnick/Chart.js/pull/35
voici un violon http://jsfiddle.net/mayankcpdixit/6xV78/ implémentant le même.
Aucune des autres réponses ne redimensionne le texte en fonction de la quantité de texte et de la taille du beignet. Voici un petit script que vous pouvez utiliser pour placer dynamiquement n'importe quelle quantité de texte au milieu, et il le redimensionnera automatiquement.
Exemple: http://jsfiddle.net/kdvuxbtj/
Il faudra n'importe quelle quantité de texte dans la taille du beignet parfaite pour le beignet. Pour éviter de toucher les bords, vous pouvez définir un rembourrage latéral comme un pourcentage du diamètre de l'intérieur du cercle. Si vous ne le définissez pas, la valeur par défaut est 20. Vous avez également la couleur, la police et le texte. Le plugin s'occupe du reste.
Le code du plugin commencera avec une taille de police de base de 30px. De là, il vérifiera la largeur du texte et le comparera au rayon du cercle et le redimensionnera en fonction du rapport de largeur du cercle / texte.
Il a une taille de police minimale par défaut de 20 px. Si le texte dépasse les limites à la taille de police minimale, il encapsulera le texte. La hauteur de ligne par défaut lors de l'habillage du texte est de 25 px, mais vous pouvez la modifier. Si vous définissez la taille de police minimale par défaut sur false, le texte deviendra infiniment petit et ne sera pas enveloppé.
Il a également une taille de police maximale par défaut de 75px au cas où il n'y aurait pas assez de texte et que le lettrage serait trop grand.
Ceci est le code du plugin
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);
}
}
});
Et vous utilisez les options suivantes dans votre objet graphique
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
}
}
}
Merci à @Jenna Sloan pour l'aide avec les mathématiques utilisées dans cette solution.
Voici un exemple nettoyé et combiné des solutions ci-dessus - réactif (essayez de redimensionner la fenêtre), prend en charge l'auto-alignement de l'animation, prend en charge les info-bulles
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>
MISE À JOUR 17.06.16:
Même fonctionnalité mais pour la version 2 de chart.js:
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>
Uncaught TypeError: Cannot read property 'extend' of undefined
des idées?
J'éviterais de modifier le code chart.js pour ce faire, car c'est assez facile avec du CSS et du HTML classiques. Voici ma 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;
}
La sortie ressemble à ceci:
Cela fonctionne aussi de mon côté ...
<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>
Base sur la réponse @ rap-2-h, voici le code pour utiliser le texte sur un graphique en anneau sur Chart.js pour une utilisation dans un tableau de bord comme. Il a une taille de police dynamique pour une option réactive.
HTML:
<div>text
<canvas id="chart-area" width="300" height="300" style="border:1px solid"/><div>
Scénario:
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);
}
});
});
Voici l'exemple de code.try pour redimensionner la fenêtre. http://jsbin.com/wapono/13/edit
Vous pouvez utiliser css avec un positionnement relatif / absolu si vous le souhaitez réactif. De plus, il peut gérer facilement la multi-ligne.
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>
Ceci est basé sur la mise à jour de Cmyker pour Chart.js 2. (publiée comme une autre réponse car je ne peux pas encore commenter)
J'ai eu un problème avec l'alignement du texte sur Chrome lorsque la légende est affichée car la hauteur du graphique ne l'inclut pas, donc elle n'est pas correctement alignée au milieu. Correction de cela en tenant compte de cela dans le calcul de fontSize et textY.
J'ai calculé le pourcentage à l'intérieur de la méthode plutôt qu'une valeur définie car j'en ai plusieurs sur la page. L'hypothèse est que votre graphique n'a que 2 valeurs (sinon quel est le pourcentage de? Et que la première est celle pour laquelle vous voulez afficher le pourcentage. J'ai également un tas d'autres graphiques, donc je vérifie type = donut. J'utilise uniquement des beignets pour afficher les pourcentages, donc cela fonctionne pour moi.
La couleur du texte semble un peu hasardeuse en fonction de l'ordre dans lequel les choses se déroulent, etc., donc j'ai rencontré un problème lors du redimensionnement selon lequel le texte changerait de couleur (entre le noir et la couleur principale dans un cas, et la couleur secondaire et le blanc dans un autre). Je "sauvegarde" quel que soit le style de remplissage existant, dessine le texte (dans la couleur des données primaires) puis restaure l'ancien style de remplissage. (La préservation de l'ancien style de remplissage ne semble pas nécessaire, mais on ne sait jamais.)
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();
}
}
});
Vous pouvez également coller le code de mayankcpdixit dans l' onAnimationComplete
option:
// ...
var myDoughnutChart = new Chart(ctx).Doughnut(data, {
onAnimationComplete: function() {
ctx.fillText(data[0].value + "%", 100 - 20, 100, 200);
}
});
Le texte sera affiché après l'animation
save
méthode
Je crée une démo avec 7 jQueryUI Slider et ChartJs (avec du texte dynamique à l'intérieur)
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
});
La réponse de @ rap-2-h et @Ztuons Ch ne permet pas à l' showTooltips
option d'être active, mais ce que vous pouvez faire est de créer et de superposer un deuxième canvas
objet derrière celui qui rend le graphique.
La partie importante est le style requis dans les divs et pour l'objet canvas lui-même afin qu'ils s'affichent les uns sur les autres.
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>
Voici le jsfiddle: https://jsfiddle.net/68vxqyak/1/
@Cmyker, excellente solution pour chart.js v2
Une petite amélioration: il est logique de vérifier l'ID de canevas approprié, voir l'extrait de code modifié ci-dessous. Sinon, le texte (c'est-à-dire 75%) est également rendu au milieu d'autres types de graphiques dans la 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();
}
}
});
Puisqu'une légende (voir: http://www.chartjs.org/docs/latest/configuration/legend.html ) agrandit la hauteur du graphique, la valeur de la hauteur doit être obtenue par le rayon.
Tout d'abord, félicitations pour avoir choisi Chart.js! Je l'utilise sur l'un de mes projets actuels et je l'adore absolument - il fait parfaitement le travail.
Bien que les étiquettes / info-bulles ne fassent pas encore partie de la bibliothèque, vous voudrez peut-être jeter un coup d'œil à ces trois pull requests:
Et, comme Cracker0dks l'a mentionné, Chart.js utilise canvas
pour le rendu afin que vous puissiez également implémenter vos propres info-bulles en interagissant directement avec lui.
J'espère que cela t'aides.
La solution d'Alesana fonctionne très bien pour moi en général, mais comme d'autres, je voulais pouvoir spécifier où se produisent les sauts de ligne. J'ai fait quelques modifications simples pour envelopper les lignes aux caractères '\ n', tant que le texte est déjà enveloppé. Une solution plus complète forcerait le retour à la ligne s'il y a des caractères '\ n' dans le texte, mais je n'ai pas le temps pour le moment de faire fonctionner cela avec le dimensionnement des polices. Le changement se centre également un peu mieux horizontalement lors de l'enrubannage (évite les espaces de fuite). Le code est ci-dessous (je ne peux pas encore publier de commentaires).
Ce serait cool si quelqu'un mettait ce plug-in sur GitHub ...
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 lines = [];
var chunks = txt.split('\n');
for (var m = 0; m < chunks.length; m++) {
var words = chunks[m].split(' ');
var line;
// Break words up into multiple lines if necessary
for (var n = 0; n < words.length; n++) {
var testLine = (n == 0) ? words[n] : 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;
}
}
lines.push(line);
}
// Move the center up depending on line height and number of lines
centerY -= ((lines.length-1) / 2) * lineHeight;
// All but last line
for (var n = 0; n < lines.length; n++) {
ctx.fillText(lines[n], centerX, centerY);
centerY += lineHeight;
}
}
}
});