FPS
FPS

Reputation: 23

Bar values in Chart.js 2.X - dataset.metadata undefined

I am quite new at Chart.js 2, so any help will be appreciated.

I'm trying to show values for each bar in the chart. As suggested in Display values in Pareto chart using Chart.js 2.0.2 and other users I'm using this solution. However, this part throws an exception TypeError: dataset.metaData is undefined :

dataset.metaData.forEach(function(p) {
   ctx.fillText(p._chart.config.data.datasets[p._datasetIndex].data[p._index], p._model.x, p._model.y  + 20);
});

I just want to show the value over the bar. Any help?

Upvotes: 2

Views: 9654

Answers (4)

Chris
Chris

Reputation: 33

I have adapted it a little bit for horizontal Bars to show the sum of values instead of the stacked values. maybe someone can beautify the code a little bit but it works this way:

        onComplete: function() {
        var ctx = this.chart.ctx;
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        var chart = this;
        var datasets = this.config.data.datasets;
        var sum=new Array();
        datasets.forEach(function (dataset, i) {
            ctx.font = "10px Arial";

            switch ( chart.getDatasetMeta(i).type ) {
                case "line":
                    ctx.fillStyle = "Black";
                    chart.getDatasetMeta(i).data.forEach(function (p, j) {
                        ctx.fillText(datasets[i].data[j], p._model.x, p._model.y - 20);
                    });
                    break;
                case "bar":
                    ctx.fillStyle = "White";
                    chart.getDatasetMeta(i).data.forEach(function (p, j) {
                        ctx.fillText(datasets[i].data[j], p._model.x, p._model.y + 20);
                    });
                    break;
                case "horizontalBar":
                    ctx.fillStyle = "Black";
                    chart.getDatasetMeta(i).data.forEach(function (p, j) {
                    if (sum[j]== null) { sum[j] = 0; }
                    sum[j]=sum[j]+parseFloat(datasets[i].data[j]);
                    if (i==datasets.length-1) {ctx.fillText(sum[j], p._model.x+10, p._model.y);}

                    });

                    break;
            }
        });
    }

Upvotes: 0

Julha
Julha

Reputation: 1125

Works for me! chart.js 2.5.0

In addition to potatopeelings's and slashpm answers.

To handle horizontalBar you can add this case (change the padding "offsetY" to "offsetX")

case "horizontalBar":
    ctx.fillStyle = "Black";
    chart.getDatasetMeta(i).data.forEach(function (p, j) {
    ctx.fillText(datasets[i].data[j], p._model.x + 20, p._model.y);
  });
break;

Here is the full function

function chartValuesShow() { // show max values of the chart
  var ctx = this.chart.ctx;
  ctx.textAlign = "center";
  ctx.textBaseline = "middle";
  var chart = this;
  var datasets = this.config.data.datasets;

  datasets.forEach(function (dataset, i) {
    ctx.fontSize = "10px";
    switch (chart.getDatasetMeta(i).type) {
      case "line":
        ctx.fillStyle = "Black";
        chart.getDatasetMeta(i).data.forEach(function (p, j) {
          ctx.fillText(datasets[i].data[j], p._model.x, p._model.y - 20);
        });
        break;
      case "bar":
        ctx.fillStyle = "Black";
        chart.getDatasetMeta(i).data.forEach(function (p, j) {
          ctx.fillText(datasets[i].data[j], p._model.x, p._model.y + 20);
        });
        break;
      case "horizontalBar":
        ctx.fillStyle = "Black";
        chart.getDatasetMeta(i).data.forEach(function (p, j) {
          ctx.fillText(datasets[i].data[j], p._model.x + 20, p._model.y);
        });
        break;
    }
  });
}

Upvotes: 1

slashpm
slashpm

Reputation: 214

In addition to potatopeelings's answer, using Chart.js v2.5, I had to adjust the following:

switch (dataset.type) to switch ( chart.getDatasetMeta(i).type )

Upvotes: 1

potatopeelings
potatopeelings

Reputation: 41075

With the below updated onComplete, your code should work with Chart.js v2.1

...
var options = {
    animation: {
        onComplete: function() {
            var ctx = this.chart.ctx;
            ctx.textAlign = "center";
            ctx.textBaseline = "middle";
            var chart = this;
            var datasets = this.config.data.datasets;

            datasets.forEach(function (dataset, i) {
                ctx.font = "20px Arial";
                switch (dataset.type) {
                    case "line":
                        ctx.fillStyle = "Black";
                        chart.getDatasetMeta(i).data.forEach(function (p, j) {
                            ctx.fillText(datasets[i].data[j], p._model.x, p._model.y - 20);
                        });
                        break;
                    case "bar":
                        ctx.fillStyle = "White";
                        chart.getDatasetMeta(i).data.forEach(function (p, j) {
                            ctx.fillText(datasets[i].data[j], p._model.x, p._model.y + 20);
                        });
                        break;
                }
            });
        }
    },
    ...

Fiddle - http://jsfiddle.net/0j4g7kxy/

I've assumed you needed only the bar, but I have retained the code for line in the onComplete, so it should work for lines too. If you don't need either, just remove the related case from the onComplete code

Upvotes: 6

Related Questions