48

Please refer this Fiddle : https://jsfiddle.net/4mxhogmd/1/

I am working on chart.js If you see in fiddle, you will notice that value which is top on bar is not properly displayed in some cases(goes outside the canvas) While research I came across this link how to display data values on Chart.js

But here they used tooltip also for same cases to the text tweak inside of bars. I don't want this.

var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ["2 Jan", "9 Jan", "16 Jan", "23 Jan", "30 Jan", "6 Feb", "13 Feb"],
        datasets: [{
            data: [6, 87, 56, 15, 88, 60, 12],
            backgroundColor: "#4082c4"
        }]
    },
    options: {
        "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);
                    });
                });
            }
        },
        legend: {
            "display": false
        },
        tooltips: {
            "enabled": false
        },
        scales: {
            yAxes: [{
                display: false,
                gridLines: {
                    display : false
                },
                ticks: {
                    display: false,
                    beginAtZero:true
                }
            }],
            xAxes: [{
                gridLines: {
                    display : false
                },
                ticks: {
                    beginAtZero:true
                }
            }]
        }
    }
});

What I want is to show value on top only, for all cases.

Community
  • 1
  • 1
Kiran Shinde
  • 5,732
  • 4
  • 24
  • 41
  • If you add a second data object and then you filter the data by the first data object, the values from the second data object will still be visible. Is there a solution to fix this issue? – abautista Jun 19 '17 at 21:11

9 Answers9

62

I pulled out the data from being defined inside of myChart that way I could pull out the max value from the dataset. Then inside of the yAxes you can set the max ticks to be the max value + 10 from your data set. This ensures that the top bars in the graph will not go off the edge of the canvas and not display their value.

var ctx = document.getElementById("myChart");
debugger;
var data = {
  labels: ["2 Jan", "9 Jan", "16 Jan", "23 Jan", "30 Jan", "6 Feb", "13 Feb"],
  datasets: [{
    data: [150, 87, 56, 50, 88, 60, 45],
    backgroundColor: "#4082c4"
  }]
}
var myChart = new Chart(ctx, {
  type: 'bar',
  data: data,
  options: {
    "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);
          });
        });
      }
    },
    legend: {
      "display": false
    },
    tooltips: {
      "enabled": false
    },
    scales: {
      yAxes: [{
        display: false,
        gridLines: {
          display: false
        },
        ticks: {
          max: Math.max(...data.datasets[0].data) + 10,
          display: false,
          beginAtZero: true
        }
      }],
      xAxes: [{
        gridLines: {
          display: false
        },
        ticks: {
          beginAtZero: true
        }
      }]
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.bundle.js"></script>
<canvas id="myChart" width="100" height="100"></canvas>
Joffutt4
  • 1,418
  • 14
  • 15
  • 1
    This is not a proper answer. As if value is too large this will not work. But still by making some changes, I can achieve what I want. Many Thanks – Kiran Shinde Mar 02 '17 at 16:03
  • @Kenny and others: check [DavidX's answer](https://stackoverflow.com/a/46803027). It presents an elegant plugin that would do the job. – J.Baoby Dec 06 '18 at 10:08
  • Nice thanks, but doesn't work with negative bar – crg Dec 23 '20 at 15:08
  • 1
    There are MANY upgrades with chart.js version 3, but this for the most part led to where I needed to be. Some changes for example: bar._model.x doesn't exist, it is now bar.x. Instead of chartInstance.controller.getDatasetMeta(i), it is chartInstance.getDatasetMeta(i). – workaholic Aug 24 '21 at 04:57
42

The fastest way I found to do this was to use 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 if you want to apply it values on top (globally), simply set these options in your code:

Chart.defaults.global.plugins.datalabels.anchor = 'end';
Chart.defaults.global.plugins.datalabels.align = 'end';

More options can be found here: https://chartjs-plugin-datalabels.netlify.com/options.html

DavidX
  • 1,281
  • 11
  • 16
  • 8
    This is a fabulous answer! Check this out if you're looking to aggregate stacked charts, https://github.com/chartjs/chartjs-plugin-datalabels/issues/16 – sambecker Jul 26 '18 at 18:43
  • 1
    Someone knows if that lib handles extra space to show the label when necessary? I achieved that increasing 10% of the original size but it would be great if that lib does it by default. `const maxValue = Math.max(...data.datasets[0].data) options.scales.yAxes[0].ticks.suggestedMax = maxValue * 1.1` – Sheldon Oliveira Jun 10 '20 at 13:06
19

Here is a more robust solution that will display the datapoint value inside the bar for cases where the axis height is close to the bar height. In other words, this will display the value above the bar and/or below the bar if the text will extend beyond the canvas visible area.

Chart.plugins.register({
  afterDraw: function(chartInstance) {
    if (chartInstance.config.options.showDatapoints) {
      var helpers = Chart.helpers;
      var ctx = chartInstance.chart.ctx;
      var fontColor = helpers.getValueOrDefault(chartInstance.config.options.showDatapoints.fontColor, chartInstance.config.options.defaultFontColor);

      // 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';
      ctx.fillStyle = fontColor;

      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;
          var scaleMax = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._yScale.maxHeight;
          var yPos = (scaleMax - model.y) / scaleMax >= 0.93 ? model.y + 20 : model.y - 5;
          ctx.fillText(dataset.data[i], model.x, yPos);
        }
      });
    }
  }
});

You can enable your chart to use the plugin by adding the below property in your chart options.

showDatapoints: true,
jordanwillis
  • 10,449
  • 1
  • 37
  • 42
  • I don't want this. I want value to be displayed on Top only, in all cases. Anyway Thanks – Kiran Shinde Mar 03 '17 at 05:33
  • Does this works for other charts? doughnut, radar.. etc. Tried using it but it doesn't work. – Yorki Bonilla Dec 18 '17 at 12:42
  • and if you factor in the dataset loop variable (function(dataset, eachLoopIndex)) in the fillText, if the column chart is a stacked version, the two values on a same column wont intersect, like so: ctx.fillText(dataset.data[i], model.x, y_pos-eachLegendIndex*10); – gawkface Aug 13 '18 at 08:10
  • How to increase the size of text visible above bar? – Vaibhav Grover Oct 12 '18 at 08:58
  • WARNING: afterDraw() callback is triggered many times by back-end engine during canvas and chart drawings for various events such as page reload, display orientation changes, canvas onclick, etc. Put a console.log() to verify it. If your operation is resource-expensive, you may want to avoid it as afterDraw() callback. – Panini Luncher Sep 02 '19 at 19:40
5

This worked in my case.(plugins section below)

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

Happy Coding.

Bandham Manikanta
  • 1,858
  • 21
  • 21
  • I paste your code in exactly, not working at all. Is it working ? – code-8 Apr 09 '20 at 19:44
  • Yes, It is a working code. What is mean by not working at all.?? Are you getting any error.?? – Bandham Manikanta Apr 10 '20 at 11:40
  • Make sure you have "chartjs-plugin-datalabels" plugin installed (package.json). you can refer this documentation for more details. https://chartjs-plugin-datalabels.netlify.com/guide/getting-started.html#configuration – Bandham Manikanta Apr 10 '20 at 11:55
3

Try these options:

animation: {
  duration: 1,
  onComplete: function({ chart }) {
    const ctx = chart.ctx;

    chart.config.data.datasets.forEach(function(dataset, i) {
      const meta = chart.getDatasetMeta(i);

      meta.data.forEach(function(bar, index) {
        const data = dataset.data[index];

        ctx.fillText(data, bar.x, bar.y - 5);
      });
    });
  }
}
Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
Caio Agiani
  • 41
  • 1
  • 2
2

You can use add some padding-top inside your chart options

layout: {
    padding: {
        left: 0,
        right: 0,
        top: 30,
        bottom: 0
    }
 },
Ishan Liyanage
  • 2,237
  • 1
  • 26
  • 25
1

You can consider plugin which show data value on top of each bar.

plugins: {
afterDatasetsDraw: function (context, easing) {
 var ctx = context.chart.ctx;
   context.data.datasets.forEach(function (dataset) {
     for (var i = 0; i < dataset.data.length; i++) {
        if (dataset.data[i] != 0) {
          var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
            var textY = model.y + (dataset.type == "line" ? -3 : 15); 
              ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, 'normal', Chart.defaults.global.defaultFontFamily);
              ctx.textAlign = 'start';
              ctx.textBaseline = 'middle';
              ctx.fillStyle = dataset.type == "line" ? "black" : "black";
              ctx.save();
              ctx.translate(model.x, textY-15);
              ctx.rotate(4.7);
              ctx.fillText(dataset.data[i], 0, 0);
              ctx.restore();
             }
           }
         });
       }
    }

live code: Link

Steffi Keran Rani J
  • 3,667
  • 4
  • 34
  • 56
0

this works in my case but its show values in mid of the bar.

chart.chart.config.options.animation["onComplete"] =  function () {
        var ctx = chart.chart.ctx;
        ctx.font = '22px "Helvetica Neue", Helvetica, Arial, sans-serif';
        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 + 50;
                if ((scale_max - model.y) / scale_max >= 0.5)
                    y_pos = model.y + 20;
                ctx.fillText(dataset.data[i], model.x, y_pos);    
            }
        });                
    }
Syed Tabish Ali
  • 309
  • 3
  • 5
-1
var ctx = document.getElementById("myChart");
debugger;
var data = {
  labels: ["2 Jan", "9 Jan", "16 Jan", "23 Jan", "30 Jan", "6 Feb", "13 Feb"],
  datasets: [{
    data: [150, 87, 56, 50, 88, 60, 45],
    backgroundColor: "#4082c4"
  }]
}
var myChart = new Chart(ctx, {
  type: 'bar',
  data: data,
  options: {
    "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);
          });
        });
      }
    },
    legend: {
      "display": false
    },
    tooltips: {
      "enabled": false
    },
    scales: {
      yAxes: [{
        display: false,
        gridLines: {
          display: false
        },
        ticks: {
          max: Math.max(...data.datasets[0].data) + 10,
          display: false,
          beginAtZero: true
        }
      }],
      xAxes: [{
        gridLines: {
          display: false
        },
        ticks: {
          beginAtZero: true
        }
      }]
    }
  }
});
Iva
  • 2,447
  • 1
  • 18
  • 28
  • 1
    Please refrain from only providing code snippets. It would be great if you explain your code. [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer) – The Myth Nov 06 '22 at 18:17