Skip to content Skip to sidebar Skip to footer

Google Visualization Cluster Multiple Column Stacks Having Goal Lines

My goal is to cluster two or more column stacks having corresponding goal lines. What is the best way to get this chart? My initial thought was to use a ComboChart. I can only ac

Solution 1:

the problem here, material charts do not support combo charts (adding the line). and classic charts do not support multiple stacks.

however, by adding a line series in between the columns series, and moving one to another y-axis, the stacks will become separated, though on top of one another.

on the chart's 'ready' event, we can reduce the size of both stacks by half, then move the second stack to the right.

the biggest problem here is on interactivity. the chart will reset all the columns back to their original position on interactivity, such as hover. as such, we must use a MutationObserver to prevent the reset.

however, there is still a couple minor issues I haven't worked out.

when you hover the first stack, the tooltip appears above the original position. and there is a highlight surrounding the original position.

here is what I have so far...

google.charts.load('current', {
  packages: ['corechart']
}).then(function () {
  var data = google.visualization.arrayToDataTable([
    ['Month', 'Ax1 line', 'Stack1 1', 'Stack1 2', 'Ax2 line', 'Stack2 1', 'Stack2 2'],
    ['2004/05', 10, 110, 210, 710, 810, 910],
    ['2005/06', 20, 120, 220, 720, 820, 920],
    ['2006/07', 30, 130, 230, 730, 830, 930],
    ['2007/08', 40, 140, 240, 740, 840, 940],
    ['2008/09', 50, 150, 250, 750, 850, 950]
  ]);

  var options = {
    title: 'Monthly Coffee Production by Country',
    vAxis: {
      title: 'Cups'
    },
    hAxis: {
      title: 'Month'
    },
    seriesType: 'bars',
    series: {
      0: { type: 'line', targetAxisIndex: 0},
      1: { type: 'bars', targetAxisIndex: 0},
      2: { type: 'bars', targetAxisIndex: 0},
      3: { type: 'line', targetAxisIndex: 1},
      4: { type: 'bars', targetAxisIndex: 1},
      5: { type: 'bars', targetAxisIndex: 1}
    },
    isStacked: true,
    legend: {
      maxLines: 2,
      position: 'top'
    },
    tooltip: {
      target: 'both'
    }
  };

  var chart = new google.visualization.ComboChart(document.getElementById('chart_div'));
  var chartLayout;
  var chartBounds;
  var legendColors = [];
  var saveCoords = {};
  google.visualization.events.addListener(chart, 'ready', function () {
    // init chart elements
    chartLayout = chart.getChartLayoutInterface();
    chartBounds = chartLayout.getChartAreaBoundingBox();
    var bars = chart.getContainer().getElementsByTagName('rect');

    // find legend markersArray.prototype.forEach.call(bars, function (bar) {
      var color = bar.getAttribute('fill');
      var xCoord = parseFloat(bar.getAttribute('x'));
      var yCoord = parseFloat(bar.getAttribute('y'));
      if ((xCoord >= chartBounds.left) && (yCoord < chartBounds.top) && (color !== '#ffffff')) {
        legendColors.push(color);
      }
    });

    // find barsArray.prototype.forEach.call(bars, function (bar, index) {
      var xCoord = parseFloat(bar.getAttribute('x'));
      var yCoord = parseFloat(bar.getAttribute('y'));
      if ((xCoord > chartBounds.left) && (yCoord > chartBounds.top)) {
        var color = bar.getAttribute('fill');
        var width = parseFloat(bar.getAttribute('width')) / 2;
        bar.setAttribute('width', width);
        saveCoords[xCoord + yCoord] = {
          width: width,
          x: xCoord
        };
        if (legendColors.indexOf(color) > 1) {
          bar.setAttribute('x', xCoord + width);
          saveCoords[xCoord + yCoord].x = xCoord + width;
          saveCoords[xCoord + width + yCoord] = saveCoords[xCoord + yCoord];
        }
      }
    });

    var observer = newMutationObserver(function () {
      // reset barsvar bars = chart.getContainer().getElementsByTagName('rect');
      Array.prototype.forEach.call(bars, function (bar, index) {
        var xCoord = parseFloat(bar.getAttribute('x'));
        var yCoord = parseFloat(bar.getAttribute('y'));
        if ((xCoord > chartBounds.left) && (yCoord > chartBounds.top)) {
          var color = bar.getAttribute('fill');
          if (saveCoords.hasOwnProperty(xCoord + yCoord)) {
            bar.setAttribute('width', saveCoords[xCoord + yCoord].width);
            bar.setAttribute('x', saveCoords[xCoord + yCoord].x);
          }
        }
      });
    });
    observer.observe(chart.getContainer(), {
      childList: true,
      subtree: true
    });
  });

  chart.draw(data, options);
  window.addEventListener('resize', function () {
    chart.draw(data, options);
  });
});
#chart_div {
  height: 400px;
}
<scriptsrc="https://www.gstatic.com/charts/loader.js"></script><divid="chart_div"></div>

Note: I also found an issue once posted here. For now, the legend must be fully displayed on one line. To run the example here, you must run the snippet, then click Full page.

Post a Comment for "Google Visualization Cluster Multiple Column Stacks Having Goal Lines"