como exibir valores de dados em Chart.js

118

Gostaria de perguntar se é possível usar Chart.js exibir valores de dados? Eu quero imprimir o gráfico.

Obrigado por qualquer conselho.

FuSsA
fonte
meu gráfico está funcionando perfeitamente .. eu só quero exibir valores de dados em meu gráfico LineBar .. então eu posso imprimir meus gráficos .. porque agora posso exibir valores de dados apenas por evento de mouse
FuSsA

Respostas:

138

Edição tardia: há um plugin oficial para Chart.js 2.7.0+para fazer isso: https://github.com/chartjs/chartjs-plugin-datalabels

Resposta original:

Você pode percorrer os pontos / barras emAnimationComplete e exibir os valores


Antevisão

insira a descrição da imagem aqui


HTML

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

Roteiro

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

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

potatopeelings
fonte
E se eu tivesse dois gráficos de linhas no mesmo gráfico?
FuSsA
1
Com o acima, ainda mostraria os valores, mas você pode ver uma sobreposição se os pontos estiverem muito próximos um do outro. Mas você sempre pode colocar em lógica para alterar a posição do valor. Como, por exemplo - jsfiddle.net/hh719qex se você tiver uma impressora colorida. Se você tiver apenas 2 séries, também poderá fazer coisas como definir textBaseline diferente SE os 2 pontos forem 2 próximos um do outro.
potatopeelings
4
isso foi para a v1.0.2 como fazer isso para a v2.1.3? A estrutura do objeto é diferente na versão posterior.
techie_28
2
@potatopeelings Eu usei o onCompleteretorno de chamada aqui, mas ele também dispara quando o mouseover está na barra do gráfico, fazendo com que o número pisque devido ao redesenho. Seria o mesmo se onAnimationComplete? Não consigo usar este retorno de chamada com meu código de gráfico existente (consulte var chartBarno final pastebin.com/tT7yTkGh )
techie_28
1
Preciso da dica de ferramenta e dos dados no topo da barra do meu gráfico. Quando a dica de ferramenta é exibida, os dados na parte superior da barra são transformados em branco, que é visível em minha dica de ferramenta transparente. Como posso consertar isso?
LJP
82

Aqui está uma versão atualizada para Chart.js 2.3

23 de setembro de 2016: editei meu código para funcionar com a v2.3 para ambos os tipos de linha / barra.

Importante: Mesmo se você não precisar da animação, não altere a opção de duração para 0, caso contrário, você obterá chartInstance.controller is undefined error.

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
fonte
Recebo "TypeError não capturado: não é possível ler a propriedade '0' de indefinido" ao tentar fazer isso em gráficos de barras. As barras usam algo diferente de "dataset.metaData [i] ._ model"?
Chris Ensell
Na verdade, é var model = dataset._meta [i] .data [0] ._ model;
Flanamacca
Essa também não é toda a verdade. Ainda recebo exceções. Vou tentar descobrir.
val
var model = dataset._meta [0] .data [i] ._ model; na realidade.
brian
2
Parece que não é tão simples quanto _meta [0]. Na verdade, o objeto _meta não é um array, ele tem um único elemento com um número como chave. Não consigo descobrir a razão por trás de qual será o número, então apenas pego o primeiro elemento olhando na lista de chaves, como este: var model = dataset._meta [Object.keys (dataset._meta) [0]] .data [i] ._ model;
IrishDubGuy de
34

Esta opção de animação funciona para 2.1.3 em um gráfico de barras.

Resposta @Ross ligeiramente modificada

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
fonte
3
Também tive que definir hover: {animationDuration: 0}para interromper a animação dos rótulos no hover
iamyojimbo
1
Além disso, observe que se você deseja ocultar rótulos ao ocultar algo da legenda, é necessário adicionar o seguinte antes do loop forEach:.filter(dataset => !dataset._meta[0].hidden)
iamyojimbo
1
Este método faz com que os valores sejam cortados se não houver espaço suficiente acima das barras.
Janne Annala
2
Não posso acreditar que é tão feio ^^ bom trabalho
La masse
Parece bom, mas pisca quando as dicas de ferramentas são redesenhadas. Também não processa colisões em gráficos combinados e rótulos de dados cumulativos para barras empilhadas - isso, é claro, exigirá mais codificação.
dma_k
22

Acho que a melhor opção de fazer isso no chartJS v2.x é usar um plugin, então você não tem um grande bloco de código nas opções. Além disso, evita que os dados desapareçam ao passar o mouse sobre uma barra.

Ou seja, simplesmente use este código, que registra um plugin que adiciona o texto depois que o gráfico é desenhado.

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
fonte
Chart.plugins.register ({
hasentopf
Eu tive que usar Chart.defaults.global.tooltips.enabled = false;. O problema com essa solução é que a afterDrawfunção é chamada centenas de vezes, provavelmente gerando sobrecarga de CPU. Ainda assim, é a única resposta por enquanto sem piscar. Se você precisar de uma renderização melhor para horizontalBargráficos, use ctx.textAlign = 'left'; ctx.textBaseline = 'middle';e ctx.fillText(dataset.data[i], model.x+5, model.y);.
KrisWebDev
uma solução muito mais limpa e modular.
hadaytullah
20

Com base na resposta de @Ross para Chart.js 2.0 e superior, tive que incluir um pequeno ajuste para evitar o caso em que as alturas da barra chegam também escolhidas para o limite da escala.

Exemplo

o animation atributo da opção do gráfico de barras:

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
fonte
O texto pisca ao ctx.save()
passar o mouse
a onCompletechamada de retorno é executada quando eu passei o mouse sobre a barra, o que faz com que o redesenho e o texto pareçam piscar. Isso também seria o mesmo onAnimationComplete? Não consigo usar a onAnimationCompletechamada de retorno com meu código existente (veja var chartBarno final do pastebin. com / tT7yTkGh
techie_28
É possível fazer o mesmo no gráfico de pizza
Ravi Khambhati,
@RaviKhambhati Sim, você pode verificar nesta resposta: stackoverflow.com/a/38797604/6402571
Hung Tran
17

Se você estiver usando o plugin chartjs-plugin-datalabels então o seguinte objeto de opções de código ajudará

Certifique-se de importar import 'chartjs-plugin-datalabels';em seu arquivo typescript ou adicionar referência a <script src="chartjs-plugin-datalabels.js"></script>em seu arquivo javascript.

options: {
    maintainAspectRatio: false,
    responsive: true,
    scales: {
      yAxes: [{
        ticks: {
          beginAtZero: true,
        }
      }]
    },
    plugins: {
      datalabels: {
        anchor: 'end',
        align: 'top',
        formatter: Math.round,
        font: {
          weight: 'bold'
        }
      }
    }
  }
Karthik
fonte
1
Sua resposta é tão simples e funcionou para mim. Obrigado. Boa codificação.
Bandham Manikanta
7

Seguindo esta boa resposta , eu usaria estas opções para um gráfico de barras:

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

Gráfico de barras

Este ainda usa o sistema de dicas e suas vantagens (posicionamento automático, modelos, ...) mas escondendo as decorações (cor de fundo, circunflexo, ...)

Pierre de LESPINAY
fonte
A implementação pode mudar dependendo do tipo de gráfico. Para um gráfico de linha, por exemplo, é em this.datasets[0].pointsvez de .bars. Eu prefiro essa solução porque ela usa o sistema de dicas de ferramentas.
Telmo Marques
1
Esta solução para uma versão anterior. Como fazer isso para a versão mais recente, ou seja, 2.1.3. Eu usei as respostas potatopeelings & Huang Trang no onCompleteretorno de chamada das animações, mas é acionado mesmo quando pairado sobre as barras do gráfico, o que faz com que o texto seja redesenhado e dê um efeito de piscar indesejado. Eu também tentei afterDrawe é tudo igual. Estranhamente, não acontece no violino fornecido por potatopeelings.Any Ideas plz?
techie_28
6

A partir de amostras chart.js (arquivo Chart.js-2.4.0 / samples / data_labelling.html):

`` `// Definir um plugin para fornecer rótulos de dados

    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
fonte
Eu adicionei uma linha a isso para o alinhamento em um gráfico de barras horizontal fazendo if (chart.config.type == "horizontalBar") e definindo um preenchimento vertical personalizado de 10 para alinhá-lo ao centro.
Jeff Beagley
6

Eu recomendo usar este plugin: https://github.com/chartjs/chartjs-plugin-datalabels

Os rótulos podem ser adicionados aos seus gráficos simplesmente importando o plugin para o arquivo js, ​​por exemplo:

import 'chartjs-plugin-datalabels'

E pode ser ajustado usando estes documentos: https://chartjs-plugin-datalabels.netlify.com/options.html

DavidX
fonte
2
O mais fácil, não requer "código", apenas personalização usando o objeto padrão "opções". Aviso: a versão mínima exigida do chart.js é 2.7.0 , eu estava me referindo ao 2.5.0 do CDN e não houve alterações nos gráficos ...
GBU
@GBU qual é o atributo de opção?
Bhimbim de
5

Editou um pouco a resposta de @ ajhuddy. Apenas para gráficos de barras . Minha versão adiciona:

  • Fade in animação para os valores.
  • Evite o corte posicionando o valor dentro da barra se ela estiver muito alta.
  • Sem piscar.

Exemplo

Desvantagem: ao passar o mouse sobre uma barra que tem valor dentro dela, o valor pode parecer um pouco irregular. Não encontrei uma solução para desativar os efeitos de foco. Também pode precisar de ajustes, dependendo de suas próprias configurações.

Configuração:

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

Ajudantes:

// 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
fonte
Janne, obrigado pela solução, parece ótimo. Mas eu tenho uma situação em que meus valores são realmente grandes (5 números decimais), e quando o tamanho da tela é pequeno ou tenho muitos gráficos, os números ficam uns sobre os outros. Existe alguma maneira de fazer isso funcionar com responsividade? Tipo, fazer os números girarem quando não houver espaço, assim como os rótulos abaixo da barra?
Phiter
@PhiterFernandes Acho que deve ser possível girar verificando o tamanho da tela atual na função modifyCtx e usando ctx.rotate. No entanto, não tenho certeza de como comparar o tamanho do valor com o espaço disponível para determinar quando girar.
Janne Annala
A função modifyCtx funciona apenas uma vez, e não no redimensionamento, certo? Vou dar uma olhada no código-fonte chart.js e ver onde eles fazem a rotação dos rótulos no eixo x. Se eu ver algo vou tentar fazer algo e te falar aqui, ok? =)
Phiter
Encontrei algo na versão 2.3.0, linha 7075. calculateTickRotation, está dentro da função Escala. Vou analisar isso.
Phiter
5

Pela minha experiência, depois de incluir o plug-in chartjs-plugin-datalabels (certifique-se de colocar a <script>tag após a tag chart.js em sua página), seus gráficos começam a exibir valores.

Se você escolher, poderá personalizá-lo para atender às suas necessidades. A personalização está claramente documentada aqui, mas basicamente o formato é como este exemplo hipotético:

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
fonte