He estado tratando de modificar un ejemplo de gráficos de Google para tener tres gráficos circulares uno al lado del otro, y aunque puedo hacer que funcione satisfactoriamente, encuentro que necesito disminuir un contador que, lógicamente, creo que debería dejarse solo. . Agradecería que alguien echara un vistazo a este fragmento de código de trabajo y explicara por qué es necesaria la disminución manual de un contador de bucle (ver el comentario), porque sin él el código falla (solo muestra un gráfico).

<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      var num_charts = 3;
      var userdata = new Array(num_charts);
      var fn_array = new Array(num_charts);

      for ( var i=0; i<num_charts; i++ )
      {
        userdata[i] = new Array(
          ['Work',      1 + Math.floor(Math.random()*10)],
          ['Eat',       1 + Math.floor(Math.random()*10)],
          ['Commute',   1 + Math.floor(Math.random()*10)],
          ['Watch TV',  1 + Math.floor(Math.random()*10)],
          ['Sleep',     1 + i ]
        );

        fn_array[i] = function() {
          // Need to decrement i for it to work, but why??? The value
          // of i inside this function is one greater than the corresponding 
          // fn_array index, but I don't see why.  
          i--;

          var data = new google.visualization.DataTable();
          data.addColumn('string', 'Task');
          data.addColumn('number', 'Hours per Day');
          data.addRows(userdata[i]);

          var options = {
            width: 400, height: 300,
            title: 'Hello ' + i
          };

          var chart = new google.visualization.PieChart(document.getElementById('chart_div'+i));
          chart.draw(data, options);
        }
      }

      for ( var j=0; j<num_charts; j++ )
        google.setOnLoadCallback(fn_array[j]);

    </script>
  </head>
  <body>
    <span id="chart_div0"></span>
    <span id="chart_div1"></span>
    <span id="chart_div2"></span>
  </body>
</html>
0
Bob Briscoe 18 ene. 2012 a las 18:10

1 respuesta

La mejor respuesta

Dado que usa la misma variable dentro de la devolución de llamada, cada llamada de las devoluciones de llamada tendrá el mismo valor, disminuyendo su valor dentro de la devolución de llamada porque su valor será diferente cada vez. Dado que javascript es de un solo subproceso (sin contar a los webworkers), esto está 'bien'. Si te sientes incómodo con esto, haz lo siguiente:

for ( var i=0; i<num_charts; i++ )
{
  userdata[i] = new Array(
    ['Work',      1 + Math.floor(Math.random()*10)],
    ['Eat',       1 + Math.floor(Math.random()*10)],
    ['Commute',   1 + Math.floor(Math.random()*10)],
    ['Watch TV',  1 + Math.floor(Math.random()*10)],
    ['Sleep',     1 + i ]
  );

  fn_array[i] = (function(local_i){
    return function() {
      // Need to decrement i for it to work, but why??? The value
      // of i inside this function is one greater than the corresponding 
      // fn_array index, but I don't see why.  
      //i--;

      var data = new google.visualization.DataTable();
      data.addColumn('string', 'Task');
      data.addColumn('number', 'Hours per Day');
      //data.addRows(userdata[i]);
      data.addRows(userdata[local_i]);

      var options = {
        width: 400, height: 300,
        //title: 'Hello ' + i
        title: 'Hello ' + local_i
      };

      //var chart = new google.visualization.PieChart(document.getElementById('chart_div'+i));
      var chart = new google.visualization.PieChart(document.getElementById('chart_div'+local_i));
      chart.draw(data, options);
    }
  })(i);
}
0
Prusse 18 ene. 2012 a las 18:20
Eso es correcto pero realmente incómodo. Sería más claro envolver todo el interior del bucle en una función anónima y pasar i como i en lugar de como local_i.
 – 
Brian Nickel
18 ene. 2012 a las 18:39
Acabo de proponer un cambio mínimo, de hecho, si fn_array no se usa en otro lugar, podría evitarse y el código del segundo ciclo se colocaría dentro del primero.
 – 
Prusse
18 ene. 2012 a las 18:43
Gracias por la explicación y la solución, Prusse. Se restaura la cordura.
 – 
Bob Briscoe
18 ene. 2012 a las 18:49