Marie Marie -4 years ago 134
Javascript Question

Is it possible to include individual bar labels inline with the bars on a vertical google chat line graph?

I am trying to create a simple google line graph to get an overview of time worked. This (modified) example from the Google Chart API documentation is almost perfect but requires you to mouse over each bar to see that bars name.

Data Example:

var data = google.visualization.arrayToDataTable([
['Day', 'Jane', 'John', 'Joe'],
['13th', 3, 7, 3],
['14th', 1, 3, 4],
['15th', 5, 8, 2],
['16th', 4, 8, 4]
]);


There may be dozens of bars per group so relying on the legend may not be easy. Is there a way to include group labels and bar labels?

Answer Source

you can use annotations to place text on the bars

annotations are added as separate columns,
the annotation will display on the series column it follows

however, annotations are not supported by Material charts

instead, recommend using a Core chart, with the following option...

theme: 'material'

see following working snippet, a DataView is used to add the annotations...

google.charts.load('current', {
  callback: function () {
    drawChart();
    window.addEventListener('resize', drawChart, false);
  },
  packages:['corechart', 'bar']
});

function drawChart() {
  var data = google.visualization.arrayToDataTable([
    ['Day', 'Jane', 'John', 'Joe'],
    ['13th', 3, 7, 3],
    ['14th', 1, 3, 4],
    ['15th', 5, 8, 2],
    ['16th', 4, 8, 4]
  ]);

  var view = new google.visualization.DataView(data);
  view.setColumns([0, 1,
    {
      calc: function (dt, row) {
        return dt.getColumnLabel(1)
      },
      type: 'string',
      role: 'annotation'
    },
    2,
    {
      calc: function (dt, row) {
        return dt.getColumnLabel(2)
      },
      type: 'string',
      role: 'annotation'
    },
    3,
    {
      calc: function (dt, row) {
        return dt.getColumnLabel(3)
      },
      type: 'string',
      role: 'annotation'
    }
  ]);


  var options = {
    annotations: {
      textStyle: {
        fontSize: 8
      }
    },
    hAxis: {format: 'decimal'},
    height: 400,
    colors: ['#1b9e77', '#d95f02', '#7570b3'],
    legend: {
      position: 'none'
    },
    theme: 'material'
  };

  var chart = new google.visualization.BarChart(document.getElementById('chart_div'));
  chart.draw(view, options);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

EDIT

following is an example of moving the bar labels to the left / start of bar

problem is the chart will move the label back on any interactivity, such as hover

thus, need to use a MutationObserver to know when interactivity has occurred

google.visualization.events.addOneTimeListener(chart, 'ready', function () {
  setBarLabels();
  var observer = new MutationObserver(setBarLabels);
  observer.observe(container, {
    childList: true,
    subtree: true
  });
});

then need to know which text elements are bar labels,
we can test against the column labels

also need to know what the new x-location should be,
use chart.getChartLayoutInterface().getXLocation(0) to get the x-location of the value 0
then adjust for the length of the label...

function setBarLabels() {
  var xLoc = chart.getChartLayoutInterface().getXLocation(0) + 4;
  Array.prototype.forEach.call(container.getElementsByTagName('text'), function(barLabel) {
    for (var i = 0; i < data.getNumberOfColumns(); i++) {
      if (data.getColumnLabel(i) === barLabel.innerHTML) {
        barLabel.setAttribute('x', xLoc + (barLabel.innerHTML.length * 4));
        break;
      }
    }
  });
}

see following working snippet...

google.charts.load('current', {
  callback: function () {
    drawChart();
    window.addEventListener('resize', drawChart, false);
  },
  packages:['corechart']
});

function drawChart() {
  var data = google.visualization.arrayToDataTable([
    ['Day', 'Jane', 'John', 'Joe'],
    ['13th', 3, 7, 3],
    ['14th', 1, 3, 4],
    ['15th', 5, 8, 2],
    ['16th', 4, 8, 4]
  ]);

  var view = new google.visualization.DataView(data);
  view.setColumns([0, 1,
    {
      calc: function (dt, row) {
        return dt.getColumnLabel(1)
      },
      type: 'string',
      role: 'annotation'
    },
    2,
    {
      calc: function (dt, row) {
        return dt.getColumnLabel(2)
      },
      type: 'string',
      role: 'annotation'
    },
    3,
    {
      calc: function (dt, row) {
        return dt.getColumnLabel(3)
      },
      type: 'string',
      role: 'annotation'
    }
  ]);


  var options = {
    annotations: {
      textStyle: {
        fontSize: 8
      }
    },
    hAxis: {format: 'decimal'},
    height: 400,
    colors: ['#1b9e77', '#d95f02', '#7570b3'],
    legend: {
      position: 'none'
    },
    theme: 'material'
  };

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

  google.visualization.events.addOneTimeListener(chart, 'ready', function () {
    setBarLabels();
    var observer = new MutationObserver(setBarLabels);
    observer.observe(container, {
      childList: true,
      subtree: true
    });
  });

  function setBarLabels() {
    var xLoc = chart.getChartLayoutInterface().getXLocation(0) + 4;
    Array.prototype.forEach.call(container.getElementsByTagName('text'), function(barLabel) {
      for (var i = 0; i < data.getNumberOfColumns(); i++) {
        if (data.getColumnLabel(i) === barLabel.innerHTML) {
          barLabel.setAttribute('x', xLoc + (barLabel.innerHTML.length * 4));
          break;
        }
      }
    });
  }

  chart.draw(view, options);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download