Chartjs-Horizontal stacked angular bar charts

1πŸ‘

βœ…

In order to get the label to show in the bar, reference the labels property of $scope.ChartData:

ctx.fillText($scope.ChartData.labels[index] +" "+ data, 50, bar._model.y + 4);

Instead of hard coding in the dataset which is what its doing now, is there a way I can use the data "ChartData" that I outlined in the beginning of the post?

Use properties from the data variable (supplied by the ChartService get function) i.e. data.labels and data.data instead of the hard-coded values.

So update the labels line from:

labels: ["2014", "2013", "2012", "2011"],

To this:

labels: data.labels,

And similarly for the datasets:

datasets: [{
    data: data.data,

So when creating the Chart it should look like this:

var myChart = new Chart(ctx, {
    type: 'horizontalBar',
    data: {
        labels: data.labels,
        datasets: [{
            data: data.data,
            backgroundColor: "rgba(63,103,126,1)",
            hoverBackgroundColor: "rgba(50,90,100,1)"
        }]
    },

    options: barOptions_stacked,
});

Expand the code snippet below for a demonstration.

Note: there is currently an issue with the resize-listener, blocked by a CORS issue – I am trying to find a way to disable that.

Update:

Per your comment about stacking the bars (horizontally) – yes that is possible. Just have one element in the datasets array for each item. One simple way to have this is to use Array.map() to create an array similar to the example:

var bgColors = [
    "rgba(63,103,126,1)",
    "rgba(50,90,100,1)"
];
var hoverBgColors = [
    "rgba(50,90,100,1)",
    "rgba(140,85,100,1)"
];
var datasets = data.data.map(function(value, index) {
    return {
      data: [value],
      backgroundColor: bgColors[index],
      hoverBackgroundColor: hoverBgColors[index]
    }
});

Then use variable datasets when creating the Chart object:

var myChart = new Chart(ctx, {
    type: 'horizontalBar',
    data: {
        labels: data.labels,
        datasets: datasets
    },
    options: barOptions_stacked,
});

Also, there is some weird math going on for the location of the second label but the helper function can be updated like below (I tried dividing the x value by 75 but that may need to be adjusted – I am not sure what "appropriate" values are for that …):

if (i == 0) {
    ctx.fillText($scope.ChartData.labels[i] + " " + data, 50, bar._model.y + 4);
} else {
    ctx.fillText($scope.ChartData.labels[i] + " " + data, (bar._model.x - 25) / 75, bar._model.y + 4);
}
var app = angular.module('myApp', []);
app.factory('ChartService', function() {
  return { //dummy chart service
    get: function(obj, callback) {
      var data = {
        "data": ["63", "38"],
        "labels": ["Ford", "GM"]
      };
      callback(data);
    }
  };
});
app.controller('PieController', function($scope, ChartService) {
  $scope.getBarChart = function() {
    ChartService.get({
      name: 'main'
    }, function(data) {
      $scope.ChartData = data;
      var barOptions_stacked = {
        tooltips: {
          enabled: false
        },
        hover: {
          animationDuration: 0
        },
        scales: {
          xAxes: [{
            ticks: {
              beginAtZero: true,
              fontFamily: "'Open Sans Bold', sans-serif",
              fontSize: 11
            },
            scaleLabel: {
              display: false
            },
            gridLines: {},
            stacked: true
          }],
          yAxes: [{
            gridLines: {
              display: false,
              color: "#fff",
              zeroLineColor: "#fff",
              zeroLineWidth: 0
            },
            ticks: {
              fontFamily: "'Open Sans Bold', sans-serif",
              fontSize: 11
            },
            stacked: true
          }]
        },
        legend: {
          display: false
        },
        animation: {
          onComplete: function() {
            var chartInstance = this.chart;
            var ctx = chartInstance.ctx;
            ctx.textAlign = "left";
            ctx.font = "9px Open Sans";
            ctx.fillStyle = "#fff";

            Chart.helpers.each(this.data.datasets.forEach(function(dataset, i) {
              var meta = chartInstance.controller.getDatasetMeta(i);
              Chart.helpers.each(meta.data.forEach(function(bar, index) {
                data = dataset.data[index];
                if (i == 0) {
                  ctx.fillText($scope.ChartData.labels[i] + " " + data, 50, bar._model.y + 4);
                } else {
                  ctx.fillText($scope.ChartData.labels[i] + " " + data, (bar._model.x - 25) / 75, bar._model.y + 4);
                }
              }), this)
            }), this);
          }
        },
        pointLabelFontFamily: "Quadon Extra Bold",
        scaleFontFamily: "Quadon Extra Bold",
      };

      var ctx = document.getElementById("Chart1");
      var bgColors = [
        "rgba(63,103,126,1)",
        "rgba(50,90,100,1)"
      ];
      var hoverBgColors = [
        "rgba(50,90,100,1)",
        "rgba(140,85,100,1)"
      ];
      var datasets = data.data.map(function(value, index) {
        return {
          data: [value],
          backgroundColor: bgColors[index],
          hoverBackgroundColor: hoverBgColors[index]
        }
      });
      var myChart = new Chart(ctx, {
        type: 'horizontalBar',
        data: {
          //use empty labels because the labels are on the bars
          labels: data.labels.map(function() {
            return '';
          }),
          datasets: datasets
        },
        options: barOptions_stacked,
      })
    }); //end chat service.get
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.3/Chart.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="PieController">
  data {{ChartData}} //testing purposes
  <div ng-init="getBarChart()">
    <canvas id="Chart1"></canvas>

Leave a comment