Search code examples
javascriptchartsgoogle-visualization

Google Visualization Stacked Column Chart with Aggregation & Custom Tooltips


How can I get the custom tooltips to come through for a stacked column chart?

I have to group/aggregate the detailed data in order to make the bars stack. I'd like to have a custom tooltip for each bar. enter image description here

Not sure where to start. Any help is appreciated!

// Load the Visualization API and the corechart package.
google.charts.load('current', { 'packages': ['corechart']});

// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(gChart0);

function gChart0() { drawDashboard()}

function drawDashboard() {
  const dummyJSON = [
[
{"id":"bucketName","label":"bucketName"},
{"id":"bin","label":"bin"},
{"id":"1_2_Shift_ERRORBIN","label":"1_2_Shift_ERRORBIN"},
{"id":"1_2_Shift_ERRORBIN_TT","role":"tooltip","label":"tooltip"},
{"id":"1_2_Shift_TRUCK","label":"1_2_Shift_TRUCK"},
{"id":"1_2_Shift_TRUCK_TT","role":"tooltip","label":"tooltip"},
{"id":"1_2_Shift_TRUCK01","label":"1_2_Shift_TRUCK01"},
{"id":"1_2_Shift_TRUCK01_TT","role":"tooltip","label":"tooltip"},
{"id":"1_2_Shift_TRUCK02","label":"1_2_Shift_TRUCK02"},
{"id":"1_2_Shift_TRUCK02_TT","role":"tooltip","label":"tooltip"},
{"id":"1_2_Shift_TRUCK04","label":"1_2_Shift_TRUCK04"},
{"id":"1_2_Shift_TRUCK04_TT","role":"tooltip","label":"tooltip"},
{"id":"1_2_Shift_TVSERROR","label":"1_2_Shift_TVSERROR"},
{"id":"1_2_Shift_TVSERROR_TT","role":"tooltip","label":"tooltip"},
{"id":"1_2_Shift_VBIN","label":"1_2_Shift_VBIN"},
{"id":"1_2_Shift_VBIN_TT","role":"tooltip","label":"tooltip"}
],
["1_2_Shift","TRUCK01",0,"custom tooltip A",0,"custom tooltip B",17,"custom tooltip C",0,"custom tooltip D",0,"custom tooltip E",0,"custom tooltip F",0,"custom tooltip G"],
["1_2_Shift","TRUCK04",0,"custom tooltip 1",0,"custom tooltip 2",0,"custom tooltip 3",0,"custom tooltip 4",20,"custom tooltip 5",0,"custom tooltip 6",0,"custom tooltip 7"],
["1_2_Shift","TRUCK04",0,"custom tooltip 1",0,"custom tooltip 2",0,"custom tooltip 3",0,"custom tooltip 4",40,"custom tooltip 5",0,"custom tooltip 6",0,"custom tooltip 7"]
];

var data = google.visualization.arrayToDataTable(dummyJSON);
var grouped = google.visualization.data.group(data, [0],
  [{'column': 2, 'aggregation': google.visualization.data.sum, 'type': 'number'},
  {'column': 4, 'aggregation': google.visualization.data.sum, 'type': 'number'},
  {'column': 6, 'aggregation': google.visualization.data.sum, 'type': 'number'},
  {'column': 8, 'aggregation': google.visualization.data.sum, 'type': 'number'},
  {'column': 10, 'aggregation': google.visualization.data.sum, 'type': 'number'},
  {'column': 12, 'aggregation': google.visualization.data.sum, 'type': 'number'},
  {'column': 14, 'aggregation': google.visualization.data.sum, 'type': 'number'}]
  );

  var options = {
    tooltip: { isHtml: true },
    height: 500,
    legend: { position: 'top', maxLines: 3 },
    bar: { groupWidth: '75%' },
    isStacked: true,
  };
 
  var chart = new google.visualization.ColumnChart(document.getElementById('chart'));
  chart.draw(grouped, options);

}
<script src="https://www.gstatic.com/charts/loader.js"></script>

<div id='chart'></div>


Solution

  • we can use a tooltip column role to display custom tooltips.
    which means we need to add the custom tooltip column after each series column.

    x, y1, tooltip1, y2, tooltip2, etc...
    

    and since the data is being created by the group method,
    we have to add the tooltip columns after the grouped data is created.

    we can use a data view to build a table with the original values,
    and calculated columns for the tooltips.
    first, we build an array of the view columns,
    then use method setColumns to add them to the data view.

    for html tooltips to work, we need to use the following config option, which you already have...

    tooltip: { isHtml: true },
    

    each tooltip column also needs a custom property, as follows...

    {html: true}
    

    here's the full example, see function addViewColumn

    // Load the Visualization API and the corechart package.
    google.charts.load('current', { 'packages': ['corechart']});
    
    // Set a callback to run when the Google Visualization API is loaded.
    google.charts.setOnLoadCallback(gChart0);
    
    function gChart0() { drawDashboard()}
    
    function drawDashboard() {
      const dummyJSON = [
    [
    {"id":"bucketName","label":"bucketName"},
    {"id":"bin","label":"bin"},
    {"id":"1_2_Shift_ERRORBIN","label":"1_2_Shift_ERRORBIN"},
    {"id":"1_2_Shift_ERRORBIN_TT","role":"tooltip","label":"tooltip"},
    {"id":"1_2_Shift_TRUCK","label":"1_2_Shift_TRUCK"},
    {"id":"1_2_Shift_TRUCK_TT","role":"tooltip","label":"tooltip"},
    {"id":"1_2_Shift_TRUCK01","label":"1_2_Shift_TRUCK01"},
    {"id":"1_2_Shift_TRUCK01_TT","role":"tooltip","label":"tooltip"},
    {"id":"1_2_Shift_TRUCK02","label":"1_2_Shift_TRUCK02"},
    {"id":"1_2_Shift_TRUCK02_TT","role":"tooltip","label":"tooltip"},
    {"id":"1_2_Shift_TRUCK04","label":"1_2_Shift_TRUCK04"},
    {"id":"1_2_Shift_TRUCK04_TT","role":"tooltip","label":"tooltip"},
    {"id":"1_2_Shift_TVSERROR","label":"1_2_Shift_TVSERROR"},
    {"id":"1_2_Shift_TVSERROR_TT","role":"tooltip","label":"tooltip"},
    {"id":"1_2_Shift_VBIN","label":"1_2_Shift_VBIN"},
    {"id":"1_2_Shift_VBIN_TT","role":"tooltip","label":"tooltip"}
    ],
    ["1_2_Shift","TRUCK01",0,"custom tooltip A",0,"custom tooltip B",17,"custom tooltip C",0,"custom tooltip D",0,"custom tooltip E",0,"custom tooltip F",0,"custom tooltip G"],
    ["1_2_Shift","TRUCK04",0,"custom tooltip 1",0,"custom tooltip 2",0,"custom tooltip 3",0,"custom tooltip 4",20,"custom tooltip 5",0,"custom tooltip 6",0,"custom tooltip 7"],
    ["1_2_Shift","TRUCK04",0,"custom tooltip 1",0,"custom tooltip 2",0,"custom tooltip 3",0,"custom tooltip 4",40,"custom tooltip 5",0,"custom tooltip 6",0,"custom tooltip 7"]
    ];
    
    var data = google.visualization.arrayToDataTable(dummyJSON);
    var grouped = google.visualization.data.group(data, [0],
      [{'column': 2, 'aggregation': google.visualization.data.sum, 'type': 'number'},
      {'column': 4, 'aggregation': google.visualization.data.sum, 'type': 'number'},
      {'column': 6, 'aggregation': google.visualization.data.sum, 'type': 'number'},
      {'column': 8, 'aggregation': google.visualization.data.sum, 'type': 'number'},
      {'column': 10, 'aggregation': google.visualization.data.sum, 'type': 'number'},
      {'column': 12, 'aggregation': google.visualization.data.sum, 'type': 'number'},
      {'column': 14, 'aggregation': google.visualization.data.sum, 'type': 'number'}]
      );
    
      // add custom tooltip columns
      var viewColumns = [0];
      for (var i= 0; i < grouped.getNumberOfColumns(); i++) {
        addViewColumn(i);
      }
    
      function addViewColumn(index) {
        // ignore x-axis column
        if (index === 0) {
          return;
        }
    
        // add series column
        viewColumns.push(index);
    
        // add tooltip column - column role should directly follow the series it represents
        viewColumns.push({
          calc: function (dt, row) {
            // build tooltip
            var tooltip = '<div class="ggl-tooltip"><div><span>ADD CUSTOM TOOLTIP FOR: ';
            tooltip += dt.getFormattedValue(row, 0) + '</span></div>';
            tooltip += '<div>' + dt.getColumnLabel(index) + ':&nbsp;';
            tooltip += '<span>' + dt.getFormattedValue(row, index) + '</span></div>';
            tooltip += '<div>Add whatever you want for column: ' + index + ', row: ' + row + '</div></div>';
    
            return tooltip;
          },
          properties: {html: true},
          role: 'tooltip',
          type: 'string'
        });
      }
    
      // create data view
      var dataView = new google.visualization.DataView(grouped);
      dataView.setColumns(viewColumns);
    
      var options = {
        tooltip: { isHtml: true },
        height: 500,
        legend: { position: 'top', maxLines: 3 },
        bar: { groupWidth: '75%' },
        isStacked: true,
      };
    
      var chart = new google.visualization.ColumnChart(document.getElementById('chart'));
      chart.draw(dataView, options);
    }
    .ggl-tooltip {
      border: 1px solid #E0E0E0;
      font-size: 10pt;
      padding: 8px 8px 8px 8px;
    }
    
    .ggl-tooltip div {
      margin-top: 4px;
    }
    
    .ggl-tooltip span {
      font-weight: bold;
    }
    <script src="https://www.gstatic.com/charts/loader.js"></script>
    <div id="chart"></div>