1

I'm using the "new" Material Charts from google charts. It currently lacks a lot of options from the classic charts, including legend position.

Without being able to set legend position, I'm forced to hide the built-in legend and render my own in html below the canvas. I also need to manually implement interactivity, which is where my problem lies:

The material charts have styles for hover and select states, so when the user hovers or selects a given column in the legend, the graph responds to his action. I can easily control select state through the API, but it looks like there's no way to control hover state.

So, is there any way to programmatically customize styles, so that I can mimic the hover state when the user hovers my custom legend?

WhiteHat
  • 59,912
  • 7
  • 51
  • 133
rzb
  • 2,077
  • 6
  • 22
  • 31
  • 1
    sure, once the chart is finished drawing, you can change the style of the svg elements that make up the chart -- however, the chart will reset the style back to the original, anytime there interactivity, such as hover / select -- which is why the following example uses a `MutationObserver`, to know when the activity has occurred -- see [this example](http://stackoverflow.com/a/40476688/5090771) which changes the style of the labels on a `Sankey` chart... – WhiteHat Mar 31 '17 at 13:32
  • How do I go about targeting the column nodes in a bar chart? – rzb Mar 31 '17 at 14:22

1 Answers1

1

the columns in a BarChart or ColumnChart will represented by <rect> elements

however, there will be other <rect> elements, such as the chart itself, gridlines, etc

so finding the correct <rect> elements to modify is usually the hardest part


once the elements are found, use a MutationObserver to override the style every time activity occurs

see following working snippet,

the colors of the columns are switched out for rgba, which support transparency...

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

function drawChart() {
  var data = google.visualization.arrayToDataTable([
    ['Year', 'Y1', 'Y2'],
    ['2010', 10, 14],
    ['2020', 14, 22],
    ['2030', 16, 24],
    ['2040', 22, 30],
    ['2050', 28, 36]
  ]);

  var seriesColors = ['#00ffff', '#ff00ff'];
  var rgbaMap = {
    '#00ffff': 'rgba(0,255,0,0.5)',
    '#ff00ff': 'rgba(255,0,0,0.5)'
  };

  var options = {
    colors: seriesColors,
  };

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

  // modify svg
  var observer = new MutationObserver(function () {
    Array.prototype.forEach.call(chartDiv.getElementsByTagName('rect'), function(rect) {
      if (seriesColors.indexOf(rect.getAttribute('fill')) > -1) {
        rect.setAttribute('fill', rgbaMap[rect.getAttribute('fill')]);
      }
    });
  });
  observer.observe(chartDiv, {
    childList: true,
    subtree: true
  });

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

EDIT

following is an example of a typical <rect> element that represents a column

<rect x="283" y="113" width="27" height="48" stroke="none" stroke-width="0" fill="rgba(0,255,0,0.5)"></rect>

you'll notice there isn't an attribute for 'id'

you can access by index, but since there are more <rect> elements than columns, you'll need to use something like width or fill in addition

to access by index...

chartDiv.getElementsByTagName('rect')[0]
chartDiv.getElementsByTagName('rect')[1]

setting a specific color is an easy way to identify, similar to above snippet...

WhiteHat
  • 59,912
  • 7
  • 51
  • 133
  • Is there any way to get the color of a column by its index or id? That way I could search for `` elements by their `fill` attribute. Sort of like you have done, but I don't have the colors beforehand. – rzb Mar 31 '17 at 14:49
  • I meant to get the column color using the API. Perhaps something like `getColumnProperties(columnIndex)`. I'll have to play with it a bit. – rzb Mar 31 '17 at 15:13
  • [here is an example](http://stackoverflow.com/a/41857399/5090771) of building the `rowIndex` for relation back to the data table. candlestick charts do not support annotations, the example adds them (using candlestick to produce waterfall)... – WhiteHat Mar 31 '17 at 16:17
  • I ended up falling back to the classic charts. Too much hacking for my taste. But your answer points to the right direction. – rzb Apr 07 '17 at 23:26
  • yes, _material_ [just lacks too many options](https://github.com/google/google-visualization-issues/issues/2143) -- there is an option for classic or _core_, that will get close to the _material_ look & feel --> `theme: 'material'`... – WhiteHat Apr 07 '17 at 23:33
  • Yeah, I decided to go with `theme: 'material'` plus tooltip and padding customizations. The only thing I miss now is the bar styles. They don't have the beautiful shadows etc. But I can live without them. – rzb Apr 08 '17 at 09:09