2

I'm trying to create multiple Google Charts recursively with the code below. I'm using AJAX to get the chart data and to store in the array histogramData.

With this code I can create the multiple i_histogram charts, but apparently, on each loop interaction, the previous chart is overwritten by the last one.

HTML code:

<div id="histogramCharts"></div>

Javascript code:

var histogramChartElement = document.getElementById('histogramCharts');
// remove histogram chart element children
while (histogramChartElement.hasChildNodes()) {
    histogramChartElement.removeChild(histogramChartElement.childNodes[0]);
}

for (var i = 0; i < histogramLabels.length; i++) {
    var label = histogramLabels[i];
    var node = document.createElement('div');

    node.setAttribute('id', i + '_histogram');

    histogramChartElement.appendChild(node);

    var dataTable = new google.visualization.DataTable();
    dataTable.addColumn('string', 'A');
    dataTable.addColumn('number', 'B');
    dataTable.addRows(histogramData[i]);

    google.charts.setOnLoadCallback(function () {
        var options = {
            title: histogramLabels[i],
            legend: {position: 'none'},
            histogram: {bucketSize: 0.1}
        };
        var histogramChart = new google.visualization.Histogram(node);
        histogramChart.draw(dataTable, options);
    });
}

I got this result:

<div id="histogramCharts">
    <div id="0_histogram"></div>
    <div id="1_histogram"></div>
    <div id="2_histogram">
        <div style="position: relative;">....</div>
    </div>
</div>
msampaio
  • 3,394
  • 6
  • 33
  • 53
  • 1
    The reason only the last values in the loop apply is that your for loop is not doing what you expect. Each time through the loop, it is changing the variables, like node, and the inner function that is creating charts is referring to those variables, not the values when the inner function is created. So the node variable always contains the last value by the time each chart is created. This is a frequent problem people have with JavaScript. See https://stackoverflow.com/questions/2828718/javascript-scope-problem-when-lambda-function-refers-to-a-variable-in-enclosing – dlaliberte Jul 08 '17 at 16:33

1 Answers1

1

first, setOnLoadCallback should only be called once per page load,
once it fires, you can draw as many charts as needed...

you can also depend on the callback to know when the page is ready,
instead of --> $(document).ready -- or something similar...

as such, recommend loading google first, before anything else,
then use ajax to get the data, then draw the charts...

try similar setup as follows, placing the callback in the load statement...

google.charts.load('current', {
  callback: getData,
  packages:['corechart']
});

function getData() {
  $.ajax({
    url: '...',
  }).done(drawCharts);
}

function drawCharts(data) {

  // use data to build histogramData

  var histogramChartElement = document.getElementById('histogramCharts');
  // remove histogram chart element children
  while (histogramChartElement.hasChildNodes()) {
      histogramChartElement.removeChild(histogramChartElement.childNodes[0]);
  }

  for (var i = 0; i < histogramLabels.length; i++) {
      var label = histogramLabels[i];
      var node = document.createElement('div');

      node.setAttribute('id', i + '_histogram');

      histogramChartElement.appendChild(node);

      var dataTable = new google.visualization.DataTable();
      dataTable.addColumn('string', 'A');
      dataTable.addColumn('number', 'B');
      dataTable.addRows(histogramData[i]);

      var options = {
          title: histogramLabels[i],
          legend: {position: 'none'},
          histogram: {bucketSize: 0.1}
      };
      var histogramChart = new google.visualization.Histogram(node);
      histogramChart.draw(dataTable, options);
  }
}
WhiteHat
  • 59,912
  • 7
  • 51
  • 133
  • 1
    hope this helps, [here is a working example](https://stackoverflow.com/a/42725725/5090771) of creating charts in a loop... – WhiteHat Jul 07 '17 at 16:20
  • With recent versions, you can call google.charts.load and google.charts.setOnLoadCallback multiple times. The setOnLoadCallback calls always apply to the most recent load call, waiting for its resources to be loaded before calling the callback. Both also return Promises now, so you can also do, e.g. google.charts.load(...).then(drawChart1).then(drawChart2). – dlaliberte Jul 08 '17 at 16:24