[Chartjs]-Chart.js stacked and grouped horizontalBar chart

5👍

Looking for something similar, I took a look on example you gave, and decide to write something.

Rather than trying to fix the code or reusing the ‘groupableBar’, I get Chart.js code from Chart.controllers.horizontalBar and rewrite some part in functions calculateBarY, calculateBarHeight.
Just reused the getBarCount function from your example.

Chart.defaults.groupableHBar = Chart.helpers.clone(Chart.defaults.horizontalBar);

Chart.controllers.groupableHBar = Chart.controllers.horizontalBar.extend({
    calculateBarY: function(index, datasetIndex, ruler) {
        var me = this;
        var meta = me.getMeta();
        var yScale = me.getScaleForId(meta.yAxisID);
        var barIndex = me.getBarIndex(datasetIndex);
        var topTick = yScale.getPixelForValue(null, index, datasetIndex, me.chart.isCombo);
        topTick -= me.chart.isCombo ? (ruler.tickHeight / 2) : 0;
        var stackIndex = this.getMeta().stackIndex;

        if (yScale.options.stacked) {
            if(ruler.datasetCount>1) {
                var spBar=ruler.categorySpacing/ruler.datasetCount;
                var h=me.calculateBarHeight(ruler);
                
                return topTick + (((ruler.categoryHeight - h) / 2)+ruler.categorySpacing-spBar/2)+(h+spBar)*stackIndex;
            }
            return topTick + (ruler.categoryHeight / 2) + ruler.categorySpacing;
        }

        return topTick +
            (ruler.barHeight / 2) +
            ruler.categorySpacing +
            (ruler.barHeight * barIndex) +
            (ruler.barSpacing / 2) +
            (ruler.barSpacing * barIndex);
    },
    calculateBarHeight: function(ruler) {
        var returned=0;
        var me = this;
        var yScale = me.getScaleForId(me.getMeta().yAxisID);
        if (yScale.options.barThickness) {
            returned = yScale.options.barThickness;
        }
        else {
            returned= yScale.options.stacked ? ruler.categoryHeight : ruler.barHeight;
        }
        if(ruler.datasetCount>1) {
            returned=returned/ruler.datasetCount;
        }
        return returned;
    },
    getBarCount: function () {
        var stacks = [];

        // put the stack index in the dataset meta
        Chart.helpers.each(this.chart.data.datasets, function (dataset, datasetIndex) {
            var meta = this.chart.getDatasetMeta(datasetIndex);
            if (meta.bar && this.chart.isDatasetVisible(datasetIndex)) {
                var stackIndex = stacks.indexOf(dataset.stack);
                if (stackIndex === -1) {
                    stackIndex = stacks.length;
                    stacks.push(dataset.stack);
                }
                meta.stackIndex = stackIndex;
            }
        }, this);

        this.getMeta().stacks = stacks;

        return stacks.length;
    }
});




var data = {
  labels: ["January", "February", "March"],
  datasets: [
    {
      label: "Dogs",
      backgroundColor: "rgba(255,0,0,0.2)",
      data: [20, 10, 25],
      stack: 1,
      xAxisID: 'x-axis-0',
      yAxisID: 'y-axis-0'
    },
    {
      label: "Cats",
      backgroundColor: "rgba(255,255,0,0.2)",
      data: [70, 85, 65],
      stack: 1,
      xAxisID: 'x-axis-0',
      yAxisID: 'y-axis-0'
    },
    {
      label: "Birds",
      backgroundColor: "rgba(0,255,255,0.2)",
      data: [10, 5, 10],
      stack: 1,
      xAxisID: 'x-axis-0',
      yAxisID: 'y-axis-0'

    },
    {
      label: ":-)",
      backgroundColor: "rgba(0,255,0,0.2)",
      data: [20, 10, 30],
      stack: 2,
      xAxisID: 'x-axis-1',
      yAxisID: 'y-axis-0'
    },
    {
      label: ":-|",
      backgroundColor: "rgba(0,0,255,0.2)",
      data: [40, 50, 20],
      stack: 2,
      xAxisID: 'x-axis-1',
      yAxisID: 'y-axis-0'
    },
    {
      label: ":-(",
      backgroundColor: "rgba(0,0,0,0.2)",
      data: [60, 20, 20],
      stack: 2,
      xAxisID: 'x-axis-1',
      yAxisID: 'y-axis-0'
    },
  ]
};

var ctx = document.getElementById("myChart").getContext("2d");
new Chart(ctx, {
  type: 'groupableHBar',
  data: data,
  options: {
    scales: {
      yAxes: [{
        stacked: true,
        type: 'category',
        id: 'y-axis-0'
      }],
      xAxes: [{
        stacked: true,
        type: 'linear',
        ticks: {
          beginAtZero:true
        },
        gridLines: {
          display: false,
          drawTicks: true,
        },
        id: 'x-axis-0'
      },
      {
        stacked: true,
        position: 'top',
        type: 'linear',
        ticks: {
          beginAtZero:true
        },
        id: 'x-axis-1',
        gridLines: {
          display: true,
          drawTicks: true,
        },
        display: false
      }]
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.min.js"></script>
<canvas id="myChart"></canvas>

Also put example on jsfiddle here: https://jsfiddle.net/b7gnron7/4/

Code is not strongly tested, you might found some bugs especially if you try to display only one stacked group (use horizontalBar instead in this case).

Your post is a little bit old… not sure that you still need a solution, but it could be useful for others ^_^

Leave a comment