Chartjs-Chart.js how to display multiple labels on multi bar stacked chart

2👍

using google charts…

on the chart’s 'ready' event,
you can use chart method –> getChartLayoutInterface()

var chartLayout = chart.getChartLayoutInterface();

the interface has a method –> getBoundingBox()
which will return the position of requested chart element
to get the position of a bar…

var barBounds = chartLayout.getBoundingBox('bar#0#0');

where the first #0 is the series, and the second is the row,
'bar#0#0' would get the first bar on the first row

we can also get the position of the axis label…

var labelBounds = chartLayout.getBoundingBox('hAxis#0#label#0');

we can use a combination of the bar and label bounds to position the icon
we want the left position from the bar, and the top position from the label

see following working snippet,
a column property is used to store the icon name,
the x-axis labels are used for the group
once the icon is in position, the axis label is moved down to make room

google.charts.load('current', {
  packages: ['corechart']
}).then(function () {
  var data = new google.visualization.DataTable({
    cols: [
      {label: 'x', type: 'string'},
      {label: 'file', type: 'number', p: {icon: 'fa-file'}},
      {label: 'database', type: 'number', p: {icon: 'fa-database'}},
      {label: 'random', type: 'number', p: {icon: 'fa-random'}},
    ],
    rows: [
      {c:[{v: 'Label 1'}, {v: 11}, {v: 6}, {v: 15}]},
      {c:[{v: 'Label 2'}, {v: 8}, {v: null}, {v: 12}]},
      {c:[{v: 'Label 3'}, {v: 6}, {v: 8}, {v: 18}]},
      {c:[{v: 'Label 4'}, {v: null}, {v: 1}, {v: 16}]},
    ]
  });

  var options = {
    bar: {
      groupWidth: '50%',
      width: 20
    },
    colors: ['#ffc107', '#d32f2f', '#00bcd4'],
    height: 600,
    legend: 'none',
    title: 'Capacities',
    width: 1000,
  };

  var container = document.getElementById('chart_div');
  var chart = new google.visualization.ColumnChart(container);

  google.visualization.events.addListener(chart, 'ready', function () {
    // initialize bounds variables
    var axisLabels = container.getElementsByTagName('text');
    var chartLayout = chart.getChartLayoutInterface();
    var chartBounds = chartLayout.getChartAreaBoundingBox();
    var containerBounds = container.getBoundingClientRect();
    var labelIndex;

    // add icons
    for (var r = 0; r < data.getNumberOfRows(); r++) {
      var barBounds;
      var icon;
      var iconBounds;
      var labelBounds = chartLayout.getBoundingBox('hAxis#0#label#' + r);
      for (var c = 1; c < data.getNumberOfColumns(); c++) {
        barBounds = chartLayout.getBoundingBox('bar#' + (c - 1) + '#' + r);
        if (barBounds !== null) {
          icon = container.appendChild(document.createElement('i'));
          icon.className = 'fa ' + data.getColumnProperty(c, 'icon');
          icon.style.position = 'absolute';
          iconBounds = icon.getBoundingClientRect();
          icon.style.top = (containerBounds.top + labelBounds.top) + 'px';
          icon.style.left = (barBounds.left + containerBounds.left + (barBounds.width / 2) - (iconBounds.width / 2)) + 'px';
        }
      }

      // move axis label down
      labelIndex = -1;
      Array.prototype.forEach.call(axisLabels, function(label) {
        if (label.getAttribute('text-anchor') === 'middle') {
          labelIndex++;
          if (labelIndex === r) {
            label.setAttribute('y', (parseFloat(label.getAttribute('y')) + (iconBounds.height * 2)));
          }
        }
      });
    }
  });

  chart.draw(data, options);
});
i {
  color: #00bcd4;
}
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous">
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

Leave a comment