cómo mostrar valores de datos en Chart.js

118

Me gustaría preguntar si es posible usar Chart.js mostrar valores de datos? Quiero imprimir el gráfico.

Gracias por cualquier consejo.

FuSsA
fuente
mi gráfico funciona perfectamente ... solo quiero mostrar valores de datos en mi gráfico LineBar ... luego puedo imprimir mis gráficos ... porque ahora puedo mostrar valores de datos solo con el evento del mouse
FuSsA

Respuestas:

138

Edición tardía: hay un complemento oficial para Chart.js 2.7.0+para hacer esto: https://github.com/chartjs/chartjs-plugin-datalabels

Respuesta original:

Puede recorrer los puntos / barras enAnimationComplete y mostrar los valores


Avance

ingrese la descripción de la imagen aquí


HTML

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

Guión

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/

peladuras de papa
fuente
¿Y si tuviera dos gráficos de líneas en el mismo gráfico?
FuSsA
1
Con lo anterior, aún mostraría los valores, pero es posible que vea una superposición si los puntos están demasiado cerca entre sí. Pero siempre puedes poner en lógica para cambiar la posición del valor. Como, por ejemplo, jsfiddle.net/hh719qex si tiene una impresora a color. Si solo tiene 2 series, también puede hacer cosas como establecer el textBaseline diferente SI los 2 puntos están 2 cerca uno del otro.
cáscaras de patata
4
esto fue para la v1.0.2 ¿cómo hacer esto para la v2.1.3? La estructura del objeto es diferente en la versión posterior.
techie_28
2
@potatopeelings He usado la onCompletedevolución de llamada aquí, pero también se activa cuando el mouse se encuentra en la barra del gráfico, lo que hace que el número parpadee debido a que se vuelve a dibujar. ¿Sería igual si onAnimationComplete? No puedo usar esta devolución de llamada con mi código de gráfico existente (ver var chartBaren la parte inferior pastebin.com/tT7yTkGh )
techie_28
1
Necesito información sobre herramientas y datos en la parte superior de la barra de mi gráfico. Cuando se muestra la información sobre herramientas, los datos en la parte superior de la barra se vuelven de color blanco, que es visible en mi información sobre herramientas transparente. ¿Cómo puedo arreglar esto?
LJP
82

Aquí hay una versión actualizada para Chart.js 2.3

23 de septiembre de 2016: Edité mi código para que funcione con v2.3 tanto para el tipo de línea como de barra.

Importante: incluso si no necesita la animación, no cambie la opción de duración a 0, de lo contrario obtendrá chartInstance.controller es un error indefinido .

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
fuente
Obtengo "Uncaught TypeError: No se puede leer la propiedad '0' de indefinido" cuando intento esto en gráficos de barras. ¿Las barras usan algo diferente a "dataset.metaData [i] ._ model"?
Chris Ensell
En realidad, es var model = dataset._meta [i] .data [0] ._ model;
Flanamacca
Esa tampoco es toda la verdad. Sigo recibiendo excepciones. Intentaré resolverlo.
val
var model = dataset._meta [0] .data [i] ._ model; Realmente.
Brian
2
Parece que no es tan simple como _meta [0]. De hecho, el objeto _meta no es una matriz, tiene un solo elemento con un número como clave. No puedo entender el fundamento detrás de cuál será el número, así que solo tomo el primer elemento mirando en la lista de claves, así: var model = dataset._meta [Object.keys (dataset._meta) [0]] .data [i] ._ modelo;
IrishDubGuy
34

Esta opción de animación funciona para 2.1.3 en un gráfico de barras.

Respuesta de @Ross ligeramente 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
fuente
3
También tuve que configurar hover: {animationDuration: 0}para detener la animación de las etiquetas al pasar el
mouse
1
Además, tenga en cuenta que si desea ocultar etiquetas cuando oculta algo de la leyenda, debe agregar lo siguiente antes del bucle forEach:.filter(dataset => !dataset._meta[0].hidden)
iamyojimbo
1
Este método hace que los valores se recorten si no hay suficiente espacio sobre las barras.
Janne Annala
2
No puedo creer que sea tan feo ^^ buen trabajo
La masse
Se ve bien, pero parpadea cuando se vuelve a dibujar la información sobre herramientas. Tampoco procesa colisiones en gráficos combinados y etiquetas de datos acumulativos para barras apiladas, lo que, por supuesto, requerirá más codificación.
dma_k
22

Creo que la mejor opción para hacer esto en chartJS v2.x es usar un complemento, por lo que no tiene un gran bloque de código en las opciones. Además, evita que los datos desaparezcan al pasar el cursor sobre una barra.

Es decir, simplemente use este código, que registra un complemento que agrega el texto después de que se dibuja el gráfico.

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
fuente
Chart.plugins.register ({
hasentopf
Tuve que usar Chart.defaults.global.tooltips.enabled = false;. El problema con esa solución es que la afterDrawfunción se llama cientos de veces, probablemente generando una sobrecarga de CPU. Aún así, es la única respuesta por ahora sin parpadeos. Si necesita una mejor representación para horizontalBargráficos, use ctx.textAlign = 'left'; ctx.textBaseline = 'middle';y ctx.fillText(dataset.data[i], model.x+5, model.y);.
KrisWebDev
una solución mucho más limpia y modular.
hadaytullah
20

Según la respuesta de @ Ross para Chart.js 2.0 y superior, tuve que incluir un pequeño ajuste para protegerme contra el caso en que las alturas de la barra también se eligieron en el límite de la escala.

Ejemplo

El animationatributo de la opción del 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
fuente
El texto parpadea al pasar el mouse por encima del gráfico. Intenté llamar ctx.save()al final, pero no ayudó
techie_28
la onCompletedevolución de llamada se ejecuta cuando coloqué el cursor sobre la barra, lo que hace que el redibujo y el texto parezca parpadear. ¿Sería lo mismo con esto onAnimationCompletetambién? No puedo usar la onAnimationCompletedevolución de llamada con mi código existente (ver var chartBaren la parte inferior de pastebin. com / tT7yTkGh
techie_28
¿Es posible hacer lo mismo en un gráfico circular?
Ravi Khambhati
@RaviKhambhati Sí, puede verificarlo en esta respuesta: stackoverflow.com/a/38797604/6402571
Hung Tran
17

Si está utilizando el complemento chartjs-plugin-datalabels , el siguiente objeto de opciones de código le ayudará

Asegúrese de importar import 'chartjs-plugin-datalabels';en su archivo mecanografiado o agregar una referencia <script src="chartjs-plugin-datalabels.js"></script>en su archivo javascript.

options: {
    maintainAspectRatio: false,
    responsive: true,
    scales: {
      yAxes: [{
        ticks: {
          beginAtZero: true,
        }
      }]
    },
    plugins: {
      datalabels: {
        anchor: 'end',
        align: 'top',
        formatter: Math.round,
        font: {
          weight: 'bold'
        }
      }
    }
  }
Karthik
fuente
1
Tu respuesta es tan simple y me funcionó. Gracias. Codificación feliz.
Bandham Manikanta
7

Siguiendo esta buena respuesta , usaría estas opciones para un 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

Esto todavía utiliza el sistema de información sobre herramientas y sus ventajas (posicionamiento automático, plantillas, ...) pero ocultando las decoraciones (color de fondo, símbolo de intercalación, ...)

Pierre de LESPINAY
fuente
La implementación puede cambiar según el tipo de gráfico. Para un gráfico de líneas, por ejemplo, es en this.datasets[0].pointslugar de .bars. Prefiero esta solución porque utiliza el sistema de información sobre herramientas.
Telmo Marques
1
Esta solución para una versión anterior. Cómo lograr esto para la última versión, es decir, 2.1.3. He utilizado las respuestas de peladuras de papa y Huang Trang en la onCompletedevolución de llamada de las animaciones, pero se activa incluso cuando se pasa sobre las barras del gráfico, lo que hace que el texto se vuelva a dibujar y dé un efecto de parpadeo no deseado. También lo intenté afterDrawy es todo lo mismo. no sucede en el violín proporcionado por peladuras de papa. ¿Alguna idea por favor?
techie_28
6

De las muestras de chart.js (archivo Chart.js-2.4.0 / samples / data_labelling.html):

`` `// Defina un complemento para proporcionar etiquetas de datos

    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
fuente
Agregué una línea a esto para la alineación en un gráfico de barras horizontales haciendo if (chart.config.type == "horizontalBar") y luego definiendo un relleno vertical personalizado de 10 para alinearlo en el centro.
Jeff Beagley
6

Recomendaría usar este complemento: https://github.com/chartjs/chartjs-plugin-datalabels

Las etiquetas se pueden agregar a sus gráficos simplemente importando el complemento al archivo js, ​​por ejemplo:

import 'chartjs-plugin-datalabels'

Y se puede ajustar con estos documentos: https://chartjs-plugin-datalabels.netlify.com/options.html

DavidX
fuente
2
El más fácil, no requiere "código", solo personalización usando el objeto estándar "opciones". Un aviso: la versión mínima requerida de charts.js es 2.7.0 , estaba haciendo referencia a 2.5.0 de CDN y no hubo cambios en los gráficos ...
GBU
@GBU ¿cuál es el atributo de opción ?.
Bhimbim
5

Editado un poco la respuesta de @ ajhuddy. Solo para gráficos de barras . Mi versión agrega:

  • Fundido en la animación de los valores.
  • Evite el recorte colocando el valor dentro de la barra si la barra es demasiado alta.
  • Sin parpadear.

Ejemplo

Desventaja: al pasar el cursor sobre una barra que tiene un valor en su interior, el valor puede verse un poco irregular. No he encontrado una solución para desactivar los efectos de desplazamiento. También podría necesitar ajustes dependiendo de su propia configuración.

Configuración:

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

Ayudantes:

// 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
fuente
Janne, gracias por la solución, se ve genial. Pero tengo una situación en la que mis valores son en realidad un poco grandes (5 números decimales), y cuando el tamaño de la pantalla es pequeño o tengo muchos gráficos, los números están uno encima del otro. ¿Hay alguna forma de hacer que esto funcione con capacidad de respuesta? Por ejemplo, ¿hacer que los números giren cuando no hay espacio, como las etiquetas debajo de la barra?
Phiter
@PhiterFernandes Creo que debería ser posible rotar verificando el tamaño de pantalla actual en la función modificarCtx y usando ctx.rotate. Sin embargo, no estoy seguro de cómo comparar el tamaño del valor con el espacio disponible para determinar cuándo rotar.
Janne Annala
La función modificarCtx solo funciona una vez, y no al cambiar el tamaño, ¿verdad? Echaré un vistazo al código fuente de chart.js y veré dónde hacen la rotación de las etiquetas en el eje x. Si veo algo, intentaré hacer algo y te lo diré aquí, ¿de acuerdo? =)
Phiter
Encontré algo en la versión 2.3.0, línea 7075. calculateTickRotation, está dentro de la función Scale. Yo lo analizaré.
Phiter
5

Según mi experiencia, una vez que incluye el complemento chartjs-plugin-datalabels (asegúrese de colocar la <script>etiqueta después de la etiqueta chart.js en su página), sus gráficos comienzan a mostrar valores.

Si elige, puede personalizarlo para que se ajuste a sus necesidades. La personalización está claramente documentada aquí, pero básicamente, el formato es como este ejemplo 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
fuente