web-dev-qa-db-fra.com

Comment ajouter du texte dans le graphique en anneau à l'aide de Chart.js?

Comment rendre le texte à l'intérieur du graphique en anneau, j'utilise ChartJs .

79
batman

Vous devez modifier le code comme suit: in 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 la même chose.

28
mayankcpdixit

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 toute quantité de texte au milieu et le redimensionner automatiquement. http://jsfiddle.net/nkzyx50o/

Doughnut With Dynamic Text in the Middle

Il faudra n'importe quelle quantité de texte dans le beignet, taille idéale pour le beignet. Pour éviter de toucher les bords, vous pouvez définir un remplissage latéral en tant que pourcentage du diamètre à l'intérieur du cercle. Si vous ne le définissez pas, la valeur par défaut sera 20. Vous aurez également la couleur, la police et le texte. Le plugin s'occupe du reste.

Le code du plugin commencera par une taille de police de base de 30px. À partir de là, il vérifie la largeur du texte, le compare au rayon du cercle et le redimensionne en fonction du rapport largeur/cercle.

C'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 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);
    }
  }
});

Et vous utilisez les options suivantes dans votre objet graphique

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

Nous remercions @ Jenna Sloan pour l’aide apportée aux calculs utilisés dans cette solution.

139
Alesana

Voici nettoyé et combiné l'exemple des solutions ci-dessus - responsive (essayez de redimensionner la fenêtre), prend en charge l'animation s'alignant automatiquement, 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>

UPDATE 17.06.16:

Même fonctionnalité mais pour 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>
51
Cmyker

Pour ce faire, j'éviterais de modifier le code chart.js, car c'est assez facile avec CSS et 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:

enter image description here

33
Mattias

Cela fonctionne aussi à ma fin ...

<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

16
Amrik Singh

Base sur la réponse @ rap-2-h, voici le code pour utiliser du texte sur un graphique en anneau sur Chart.js pour l’utiliser dans un tableau de bord, comme. Il a une taille de police dynamique pour l’option responsive.

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

11
Ztuons Ch

Ceci est basé sur la mise à jour de Cmyker pour Chart.js 2. (posté comme une autre réponse car je ne peux pas commenter pour le moment)

J'ai eu un problème d'alignement du texte sur Chrome lorsque la légende est affichée, car la hauteur du graphique n'inclut pas cette valeur, de sorte qu'elle n'est pas alignée correctement au milieu. Ce problème a été corrigé 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. On suppose 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 aussi d'autres graphiques, alors je vérifie le type = donut. J'utilise uniquement des beignets pour afficher les pourcentages, donc cela fonctionne pour moi.

La couleur du texte semble un peu aléatoire en fonction de l'ordre dans lequel les choses se passent, etc. 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. (Préserver 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();
    }
  }
});
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
Rory

Vous pouvez également coller le code de mayankcpdixit dans l'option onAnimationComplete:

// ...
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

7
rap-2-h

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

DEMO IN JSFIDDLE

enter image description here

6
sgrillon

Vous pouvez utiliser css avec positionnement relatif/absolu si vous le souhaitez réactif. De plus, il peut gérer facilement les lignes multiples.

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>
4
Dayze

La réponse de @ rap-2-h et @Ztuons Ch ne permet pas à l'option showTooltips d'être active, mais vous pouvez créer et superposer un second objet canvas derrière celui qui représente le graphique. .

La partie importante est le style requis dans les divs et pour l’objet de travail lui-même, afin qu’ils s’affichant 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/

3
RYUUSEiiSTAR

@Cmyker, excellente solution pour chart.js v2

Une petite amélioration: il est judicieux de vérifier l'ID de canevas approprié, voir l'extrait modifié ci-dessous. Sinon, le texte (75%) est également affiché au milieu des autres types de graphique de 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();
      }
    }
  });

Comme une légende (voir: http://www.chartjs.org/docs/latest/configuration/legend.html ) grossit la hauteur du graphique, la valeur de height devrait être obtenue par le rayon.

1
Larmia

Tout d’abord, félicitations pour le choix de Chart.js! Je l’utilise sur l’un de mes projets en cours et j’adore ça, c’est un travail parfait.

Bien que les étiquettes/info-bulles ne fassent pas encore partie de la bibliothèque, vous pouvez jeter un œil à ces trois demandes d'extraction:

Et, comme Cracker0dks est mentionné, Chart.js utilise canvas pour le rendu afin que vous puissiez tout aussi bien implémenter vos propres info-bulles en interagissant directement avec celle-ci.

J'espère que cela t'aides.

0
volpav