[javascript] how to display data values on Chart.js

I would like to ask if it's possible using Chart.js to display data values? I want to print the graph.

Thanks for any advice.

This question is related to javascript chart.js

The answer is


If you are using the plugin chartjs-plugin-datalabels then the following code options object will help

Make sure you import import 'chartjs-plugin-datalabels'; in your typescript file or add reference to <script src="chartjs-plugin-datalabels.js"></script> in your javascript file.

options: {
    maintainAspectRatio: false,
    responsive: true,
    scales: {
      yAxes: [{
        ticks: {
          beginAtZero: true,
        }
      }]
    },
    plugins: {
      datalabels: {
        anchor: 'end',
        align: 'top',
        formatter: Math.round,
        font: {
          weight: 'bold'
        }
      }
    }
  }

Following this good answer, I'd use these options for a bar chart:

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

Bar Chart

This still uses the tooltip system and his advantages (automatic positionning, templating, ...) but hiding the decorations (background color, caret, ...)


Based on @Ross's answer answer for Chart.js 2.0 and up, I had to include a little tweak to guard against the case when the bar's heights comes too chose to the scale boundary.

Example

The animation attribute of the bar chart's option:

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

From my experience, once you include the chartjs-plugin-datalabels plugin (make sure to place the <script> tag after the chart.js tag on your page), your charts begin to display values.

If you then choose you can customize it to fit your needs. The customization is clearly documented here but basically, the format is like this hypothetical example:

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

This animation option works for 2.1.3 on a bar chart.

Slightly modified @Ross answer

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

I'd recommend using this plugin: https://github.com/chartjs/chartjs-plugin-datalabels

Labels can be added to your charts simply by importing the plugin to the js file e.g.:

import 'chartjs-plugin-datalabels'

And can be fine tuned using these docs: https://chartjs-plugin-datalabels.netlify.com/options.html


I think the nicest option to do this in chartJS v2.x is by using a plugin, so you don't have a large block of code in the options. In addition, it prevents the data from disappearing when hovering over a bar.

I.e. simply use this code, which registers a plugin that adds the text after the chart is drawn.

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

From chart.js samples (file Chart.js-2.4.0/samples/data_labelling.html) :

``` // Define a plugin to provide data labels

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

```


Edited @ajhuddy's answer a little. Only for bar charts. My version adds:

  • Fade in animation for the values.
  • Prevent clipping by positioning the value inside the bar if the bar is too high.
  • No blinking.

Example

Downside: When hovering over a bar that has value inside it the value might look a little jagged. I have not found a solution do disable hover effects. It might also need tweaking depending on your own settings.

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

Helpers:

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

Here is an updated version for Chart.js 2.3

Sep 23, 2016: Edited my code to work with v2.3 for both line/bar type.

Important: Even if you don't need the animation, don't change the duration option to 0, otherwise you will get chartInstance.controller is undefined error.

_x000D_
_x000D_
var chartData = {_x000D_
    labels: ["January", "February", "March", "April", "May", "June"],_x000D_
        datasets: [_x000D_
            {_x000D_
                fillColor: "#79D1CF",_x000D_
                strokeColor: "#79D1CF",_x000D_
                data: [60, 80, 81, 56, 55, 40]_x000D_
            }_x000D_
        ]_x000D_
    };_x000D_
_x000D_
var opt = {_x000D_
    events: false,_x000D_
    tooltips: {_x000D_
        enabled: false_x000D_
    },_x000D_
    hover: {_x000D_
        animationDuration: 0_x000D_
    },_x000D_
    animation: {_x000D_
        duration: 1,_x000D_
        onComplete: function () {_x000D_
            var chartInstance = this.chart,_x000D_
                ctx = chartInstance.ctx;_x000D_
            ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);_x000D_
            ctx.textAlign = 'center';_x000D_
            ctx.textBaseline = 'bottom';_x000D_
_x000D_
            this.data.datasets.forEach(function (dataset, i) {_x000D_
                var meta = chartInstance.controller.getDatasetMeta(i);_x000D_
                meta.data.forEach(function (bar, index) {_x000D_
                    var data = dataset.data[index];                            _x000D_
                    ctx.fillText(data, bar._model.x, bar._model.y - 5);_x000D_
                });_x000D_
            });_x000D_
        }_x000D_
    }_x000D_
};_x000D_
 var ctx = document.getElementById("Chart1"),_x000D_
     myLineChart = new Chart(ctx, {_x000D_
        type: 'bar',_x000D_
        data: chartData,_x000D_
        options: opt_x000D_
     });
_x000D_
<canvas id="myChart1" height="300" width="500"></canvas>
_x000D_
_x000D_
_x000D_