comment afficher les valeurs de données sur Chart.js

118

Je voudrais demander s'il est possible d'utiliser Chart.js afficher les valeurs des données? Je veux imprimer le graphique.

Merci pour tout conseil.

FuSsA
la source
mon graphique fonctionne parfaitement .. je veux juste afficher les valeurs de données dans mon graphique LineBar .. alors je peux imprimer mes graphiques .. parce que maintenant je peux afficher les valeurs de données juste par événement de souris
FuSsA

Réponses:

138

Modification tardive: il existe un plugin officiel pour Chart.js 2.7.0+pour ce faire: https://github.com/chartjs/chartjs-plugin-datalabels

Réponse originale:

Vous pouvez parcourir les points / barres surAnimationComplete et afficher les valeurs


Aperçu

entrez la description de l'image ici


HTML

<canvas id="myChart1" height="300" width="500"></canvas>
<canvas id="myChart2" height="300" width="500"></canvas>

Scénario

var chartData = {
    labels: ["January", "February", "March", "April", "May", "June"],
    datasets: [
        {
            fillColor: "#79D1CF",
            strokeColor: "#79D1CF",
            data: [60, 80, 81, 56, 55, 40]
        }
    ]
};

var ctx = document.getElementById("myChart1").getContext("2d");
var myLine = new Chart(ctx).Line(chartData, {
    showTooltips: false,
    onAnimationComplete: function () {

        var ctx = this.chart.ctx;
        ctx.font = this.scale.font;
        ctx.fillStyle = this.scale.textColor
        ctx.textAlign = "center";
        ctx.textBaseline = "bottom";

        this.datasets.forEach(function (dataset) {
            dataset.points.forEach(function (points) {
                ctx.fillText(points.value, points.x, points.y - 10);
            });
        })
    }
});

var ctx = document.getElementById("myChart2").getContext("2d");
var myBar = new Chart(ctx).Bar(chartData, {
    showTooltips: false,
    onAnimationComplete: function () {

        var ctx = this.chart.ctx;
        ctx.font = this.scale.font;
        ctx.fillStyle = this.scale.textColor
        ctx.textAlign = "center";
        ctx.textBaseline = "bottom";

        this.datasets.forEach(function (dataset) {
            dataset.bars.forEach(function (bar) {
                ctx.fillText(bar.value, bar.x, bar.y - 5);
            });
        })
    }
});

Violon - http://jsfiddle.net/uh9vw0ao/

pommes de terre
la source
Et si j'avais deux graphiques en courbes dans le même graphique?
FuSsA
1
Avec ce qui précède, il afficherait toujours les valeurs, mais vous pourriez voir un chevauchement si les points sont trop proches les uns des autres. Mais vous pouvez toujours mettre en logique pour changer la position de valeur. Comme par exemple - jsfiddle.net/hh719qex si vous avez une imprimante couleur. Si vous n'avez que 2 séries, vous pouvez également faire des choses comme définir le textBaseline différent SI les 2 points sont proches l'un de l'autre.
potatopeelings
4
c'était pour la v1.0.2 comment faire cela pour la v2.1.3? La structure de l'objet est différente dans la version ultérieure.
techie_28
2
@potatopeelings J'ai utilisé le onCompleterappel ici, mais il se déclenche également lorsque le survol de la souris est sur la barre du graphique, provoquant le clignotement du nombre en raison du redessiner onAnimationComplete. Je ne peux pas utiliser ce rappel avec mon code de graphique existant (voir var chartBaren bas pastebin.com/tT7yTkGh )
techie_28
1
J'ai besoin de l'info-bulle et des données en haut de la barre dans mon graphique. Lorsque l'info-bulle est affichée, les données en haut de la barre deviennent blanches, ce qui est visible dans mon info-bulle transparente. Comment puis-je réparer cela?
LJP
82

Voici une version mise à jour pour Chart.js 2.3

23 septembre 2016: J'ai modifié mon code pour qu'il fonctionne avec la v2.3 pour le type ligne / barre.

Important: même si vous n'avez pas besoin de l'animation, ne modifiez pas l'option de durée sur 0, sinon vous obtiendrez une erreur chartInstance.controller is undefined .

var chartData = {
    labels: ["January", "February", "March", "April", "May", "June"],
        datasets: [
            {
                fillColor: "#79D1CF",
                strokeColor: "#79D1CF",
                data: [60, 80, 81, 56, 55, 40]
            }
        ]
    };

var opt = {
    events: false,
    tooltips: {
        enabled: false
    },
    hover: {
        animationDuration: 0
    },
    animation: {
        duration: 1,
        onComplete: function () {
            var chartInstance = this.chart,
                ctx = chartInstance.ctx;
            ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
            ctx.textAlign = 'center';
            ctx.textBaseline = 'bottom';

            this.data.datasets.forEach(function (dataset, i) {
                var meta = chartInstance.controller.getDatasetMeta(i);
                meta.data.forEach(function (bar, index) {
                    var data = dataset.data[index];                            
                    ctx.fillText(data, bar._model.x, bar._model.y - 5);
                });
            });
        }
    }
};
 var ctx = document.getElementById("Chart1"),
     myLineChart = new Chart(ctx, {
        type: 'bar',
        data: chartData,
        options: opt
     });
<canvas id="myChart1" height="300" width="500"></canvas>

Ross
la source
J'obtiens "Uncaught TypeError: Cannot read property '0' of undefined" en essayant ceci sur des graphiques à barres. Les barres utilisent-elles autre chose que "dataset.metaData [i] ._ model"?
Chris Ensell
Il s'agit en fait de var model = dataset._meta [i] .data [0] ._ model;
Flanamacca
Ce n'est pas non plus toute la vérité. J'ai encore des exceptions. Je vais essayer de le comprendre.
val
var model = dataset._meta [0] .data [i] ._ model; réellement.
brian
2
On dirait que ce n'est pas aussi simple que _meta [0]. En fait, l'objet _meta n'est pas un tableau, il a un seul élément avec un nombre comme clé. Je ne peux pas comprendre la justification du nombre, alors je prends simplement le premier élément en regardant dans la liste des clés, comme ceci: var model = dataset._meta [Object.keys (dataset._meta) [0]] .data [i] ._ modèle;
IrishDubGuy
34

Cette option d'animation fonctionne pour 2.1.3 sur un graphique à barres.

Réponse @Ross légèrement modifiée

animation: {
duration: 0,
onComplete: function () {
    // render the value of the chart above the bar
    var ctx = this.chart.ctx;
    ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, 'normal', Chart.defaults.global.defaultFontFamily);
    ctx.fillStyle = this.chart.config.options.defaultFontColor;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'bottom';
    this.data.datasets.forEach(function (dataset) {
        for (var i = 0; i < dataset.data.length; i++) {
            var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
            ctx.fillText(dataset.data[i], model.x, model.y - 5);
        }
    });
}}
Aaron Hudon
la source
3
J'ai également dû régler hover: {animationDuration: 0}pour arrêter l'animation des étiquettes en survol
iamyojimbo
1
Notez également que si vous souhaitez masquer les étiquettes lorsque vous masquez quelque chose de la légende, vous devez ajouter ce qui suit avant la boucle forEach:.filter(dataset => !dataset._meta[0].hidden)
iamyojimbo
1
Cette méthode provoque le découpage des valeurs s'il n'y a pas assez de place au-dessus des barres.
Janne Annala
2
Je ne peux pas croire que c'est ce moche ^^ beau travail
La masse
Cela semble correct, mais clignote lorsque les info-bulles sont redessinées. Ne traite pas non plus les collisions sur les graphiques combinés et les étiquettes de données cumulées pour les barres empilées - cela nécessitera bien sûr plus de codage.
dma_k
22

Je pense que la meilleure option pour faire cela dans chartJS v2.x consiste à utiliser un plugin, vous n'avez donc pas un gros bloc de code dans les options. De plus, il empêche les données de disparaître lors du survol d'une barre.

C'est-à-dire utiliser simplement ce code, qui enregistre un plugin qui ajoute le texte une fois le graphique dessiné.

Chart.pluginService.register({
    afterDraw: function(chartInstance) {
        var ctx = chartInstance.chart.ctx;

        // render the value of the chart above the bar
        ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, 'normal', Chart.defaults.global.defaultFontFamily);
        ctx.textAlign = 'center';
        ctx.textBaseline = 'bottom';

        chartInstance.data.datasets.forEach(function (dataset) {
            for (var i = 0; i < dataset.data.length; i++) {
                var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
                ctx.fillText(dataset.data[i], model.x, model.y - 2);
            }
        });
  }
});
David
la source
Chart.plugins.register ({
hasentopf
Je devais utiliser Chart.defaults.global.tooltips.enabled = false;. Le problème avec cette solution est que la afterDrawfonction est appelée des centaines de fois, générant probablement une surcharge du processeur. Pourtant, c'est la seule réponse pour l'instant sans cligner des yeux. Si vous avez besoin d'un meilleur rendu pour les horizontalBargraphiques, utilisez ctx.textAlign = 'left'; ctx.textBaseline = 'middle';et ctx.fillText(dataset.data[i], model.x+5, model.y);.
KrisWebDev
une solution beaucoup plus propre et modulaire.
hadaytullah
20

Sur la base de la réponse de @ Ross pour Chart.js 2.0 et plus, j'ai dû inclure un petit ajustement pour me prémunir contre le cas lorsque les hauteurs de la barre sont trop choisies pour la limite de l'échelle.

Exemple

L' animationattribut de l'option du graphique à barres:

animation: {
            duration: 500,
            easing: "easeOutQuart",
            onComplete: function () {
                var ctx = this.chart.ctx;
                ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal', Chart.defaults.global.defaultFontFamily);
                ctx.textAlign = 'center';
                ctx.textBaseline = 'bottom';

                this.data.datasets.forEach(function (dataset) {
                    for (var i = 0; i < dataset.data.length; i++) {
                        var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model,
                            scale_max = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._yScale.maxHeight;
                        ctx.fillStyle = '#444';
                        var y_pos = model.y - 5;
                        // Make sure data value does not get overflown and hidden
                        // when the bar's value is too close to max value of scale
                        // Note: The y value is reverse, it counts from top down
                        if ((scale_max - model.y) / scale_max >= 0.93)
                            y_pos = model.y + 20; 
                        ctx.fillText(dataset.data[i], model.x, y_pos);
                    }
                });               
            }
        }
Hung Tran
la source
Le texte clignote au survol de la souris sur le graphique .. J'ai essayé d'appeler ctx.save()à la fin mais cela n'a pas aidé
techie_28
le onCompleterappel est exécuté lorsque j'ai survolé la barre, ce qui fait que le redessiner et le texte semblent clignoter.Est-ce que ce serait la même chose avec onAnimationComplete? Je ne peux pas utiliser le onAnimationCompleterappel avec mon code existant (voir var chartBaren bas de pastebin. com / tT7yTkGh
techie_28
Est-il possible de faire la même chose dans un graphique à secteurs
Ravi Khambhati
@RaviKhambhati Oui, vous pouvez le vérifier dans cette réponse: stackoverflow.com/a/38797604/6402571
Hung Tran
17

Si vous utilisez le plugin chartjs-plugin-datalabels, l'objet d'options de code suivant vous aidera

Assurez-vous d'importer import 'chartjs-plugin-datalabels';dans votre fichier dactylographié ou d'ajouter une référence à <script src="chartjs-plugin-datalabels.js"></script>dans votre fichier javascript.

options: {
    maintainAspectRatio: false,
    responsive: true,
    scales: {
      yAxes: [{
        ticks: {
          beginAtZero: true,
        }
      }]
    },
    plugins: {
      datalabels: {
        anchor: 'end',
        align: 'top',
        formatter: Math.round,
        font: {
          weight: 'bold'
        }
      }
    }
  }
Karthik
la source
1
Votre réponse est si simple et a fonctionné pour moi. Je vous remercie. Bon codage.
Bandham Manikanta
7

Suite à cette bonne réponse , j'utiliserais ces options pour un graphique à barres:

var chartOptions = {
    animation: false,
    responsive : true,
    tooltipTemplate: "<%= value %>",
    tooltipFillColor: "rgba(0,0,0,0)",
    tooltipFontColor: "#444",
    tooltipEvents: [],
    tooltipCaretSize: 0,
    onAnimationComplete: function()
    {
        this.showTooltip(this.datasets[0].bars, true);
    }
};

window.myBar = new Chart(ctx1).Bar(chartData, chartOptions);

Diagramme à bandes

Celui-ci utilise toujours le système d'info-bulles et ses avantages (positionnement automatique, templating, ...) mais cachant les décorations (couleur de fond, caret, ...)

Pierre de LESPINAY
la source
La mise en œuvre peut changer en fonction du type de graphique. Pour un graphique en courbes, par exemple, c'est au this.datasets[0].pointslieu de .bars. Je préfère cette solution car elle utilise le système d'info-bulles.
Telmo Marques
1
Cette solution pour une version antérieure. Comment y parvenir pour la dernière version à savoir 2.1.3. J'ai utilisé les réponses potatopeelings & Huang Trang dans le onCompleterappel d' animations, mais cela se déclenche même lorsque survolé les barres du graphique, ce qui fait que le texte se redessine et donne un effet de clignotement indésirable.J'ai également essayé afterDrawet c'est tout de même. ne se produit pas dans le violon fourni par potatopeelings.Any Ideas plz?
techie_28
6

À partir d'exemples de chart.js (fichier Chart.js-2.4.0 / samples / data_labelling.html):

`` `` // Définir un plugin pour fournir des étiquettes de données

    Chart.plugins.register({
        afterDatasetsDraw: function(chartInstance, easing) {
            // To only draw at the end of animation, check for easing === 1
            var ctx = chartInstance.chart.ctx;

            chartInstance.data.datasets.forEach(function (dataset, i) {
                var meta = chartInstance.getDatasetMeta(i);
                if (!meta.hidden) {
                    meta.data.forEach(function(element, index) {
                        // Draw the text in black, with the specified font
                        ctx.fillStyle = 'rgb(0, 0, 0)';

                        var fontSize = 16;
                        var fontStyle = 'normal';
                        var fontFamily = 'Helvetica Neue';
                        ctx.font = Chart.helpers.fontString(fontSize, fontStyle, fontFamily);

                        // Just naively convert to string for now
                        var dataString = dataset.data[index].toString();

                        // Make sure alignment settings are correct
                        ctx.textAlign = 'center';
                        ctx.textBaseline = 'middle';

                        var padding = 5;
                        var position = element.tooltipPosition();
                        ctx.fillText(dataString, position.x, position.y - (fontSize / 2) - padding);
                    });
                }
            });
        }
    });

''

Radek Dest
la source
J'ai ajouté une ligne à cela pour l'alignement sur un graphique à barres horizontales en faisant if (chart.config.type == "horizontalBar") puis en définissant un rembourrage vertical personnalisé de 10 pour l'aligner au centre.
Jeff Beagley
6

Je recommanderais d'utiliser ce plugin: https://github.com/chartjs/chartjs-plugin-datalabels

Des étiquettes peuvent être ajoutées à vos graphiques simplement en important le plugin dans le fichier js, par exemple:

import 'chartjs-plugin-datalabels'

Et peut être affiné à l'aide de ces documents: https://chartjs-plugin-datalabels.netlify.com/options.html

DavidX
la source
2
Le plus simple, ne nécessite pas de "code", juste une personnalisation à l'aide de l'objet standard "options". A heads-up: la version minimum requise de charts.js est 2.7.0 , je faisais référence à 2.5.0 à partir de CDN et il n'y a eu aucun changement sur les graphiques ...
GBU
@GBU quel est l'attribut option?.
Bhimbim
5

A légèrement modifié la réponse de @ ajhuddy. Uniquement pour les graphiques à barres . Ma version ajoute:

  • Fondu dans l'animation pour les valeurs.
  • Évitez l'écrêtage en positionnant la valeur à l'intérieur de la barre si la barre est trop haute.
  • Pas de clignotement.

Exemple

Inconvénient: lorsque vous survolez une barre qui a une valeur à l'intérieur, la valeur peut sembler un peu irrégulière. Je n'ai pas trouvé de solution pour désactiver les effets de survol. Il peut également avoir besoin d'être peaufiné en fonction de vos propres paramètres.

Configuration:

bar: {
  tooltips: {
    enabled: false
  },
  hover: {
    animationDuration: 0
  },
  animation: {
    onComplete: function() {
      this.chart.controller.draw();
      drawValue(this, 1);
    },
    onProgress: function(state) {
      var animation = state.animationObject;
      drawValue(this, animation.currentStep / animation.numSteps);
    }
  }
}

Aides:

// Font color for values inside the bar
var insideFontColor = '255,255,255';
// Font color for values above the bar
var outsideFontColor = '0,0,0';
// How close to the top edge bar can be before the value is put inside it
var topThreshold = 20;

var modifyCtx = function(ctx) {
  ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, 'normal', Chart.defaults.global.defaultFontFamily);
  ctx.textAlign = 'center';
  ctx.textBaseline = 'bottom';
  return ctx;
};

var fadeIn = function(ctx, obj, x, y, black, step) {
  var ctx = modifyCtx(ctx);
  var alpha = 0;
  ctx.fillStyle = black ? 'rgba(' + outsideFontColor + ',' + step + ')' : 'rgba(' + insideFontColor + ',' + step + ')';
  ctx.fillText(obj, x, y);
};

var drawValue = function(context, step) {
  var ctx = context.chart.ctx;

  context.data.datasets.forEach(function (dataset) {
    for (var i = 0; i < dataset.data.length; i++) {
      var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
      var textY = (model.y > topThreshold) ? model.y - 3 : model.y + 20;
      fadeIn(ctx, dataset.data[i], model.x, textY, model.y > topThreshold, step);
    }
  });
};
Janne Annala
la source
Janne, merci pour la solution, ça a l'air super. Mais j'ai une situation où mes valeurs sont en fait assez grandes (5 nombres décimaux), et lorsque la taille de l'écran est petite ou que j'ai beaucoup de graphiques, les chiffres sont superposés. Existe-t-il un moyen de faire fonctionner cela avec réactivité? Par exemple, faire tourner les nombres lorsqu'il n'y a pas d'espace, tout comme les étiquettes sous la barre?
Phiter
@PhiterFernandes Je pense qu'il devrait être possible de faire pivoter en vérifiant la taille actuelle de l'écran dans la fonction modifyCtx et en utilisant ctx.rotate. Cependant, je ne sais pas comment comparer la taille de la valeur à l'espace disponible pour déterminer le moment de la rotation.
Janne Annala
La fonction modifyCtx ne fonctionne qu'une seule fois, et pas lors du redimensionnement, non? Je vais jeter un œil au code source de chart.js et voir où ils font la rotation des étiquettes sur l'axe des x. Si je vois quelque chose, je vais essayer de faire quelque chose et vous le dire ici, d'accord? =)
Phiter
J'ai trouvé quelque chose sur la version 2.3.0, ligne 7075. calculateTickRotation, c'est dans la fonction Scale. Je vais l'analyser.
Phiter
5

D'après mon expérience, une fois que vous avez inclus le plugin chartjs-plugin-datalabels (assurez-vous de placer le<script> balise après la balise chart.js sur votre page), vos graphiques commencent à afficher des valeurs.

Si vous choisissez ensuite, vous pouvez le personnaliser en fonction de vos besoins. La personnalisation est clairement documentée ici mais fondamentalement, le format est comme cet exemple hypothétique:

var myBarChart = new Chart(ctx, {
    type: 'bar',
    data: yourDataObject,
    options: {
        // other options
        plugins: {
            datalabels: {
                anchor :'end',
                align :'top',
                // and if you need to format how the value is displayed...
                formatter: function(value, context) {
                    return GetValueFormatted(value);
                }
            }
        }
    }
});
Soma Mbadiwe
la source