Google Charts 折线图切换数据表并保持状态

3

我在网上找到了一些示例,让我能够在单击系列(图例或线本身)时删除/灰掉它们。

然后,我想添加能够在数据表之间切换并将隐藏/灰掉的内容传输到新数据表的功能。

我从https://developers.google.com/chart/interactive/docs/animation#value-changes中获取了这个想法 (我的图表与示例不同步动画)

我的问题是,当单击“切换”按钮并切换数据表时,会得到非常奇怪的结果,有时它会保持正确的选择,但当您单击其他系列时,一个系列会神奇地出现或取消选择不同于所单击的系列。我无法弄清楚如何使两个数据表都保持相同的选择(选择意味着灰掉/删除系列)。

值得注意的是

         columns.push({
            calc: 'stringify',
            sourceColumn: i,
            type: 'string',
            role: 'annotation'
         });

在系列中添加隐藏列以辅助其他逻辑。虽然我目前没有直接使用它,但我希望它能保持并正常工作,因为我认为将来会用到它。这些“隐藏”的列增加了复杂性,我认为 bug 就存在于其中。

代码如下:

var button = document.getElementById('b1');
var current = 0;
var data = [];
var chart;
var options;
var ms2 = [{
   "LOCAL_ID": "W-133",
   "Class1": 29,
   "Class2": 3628,
   "Class3": 159,
   "Class4": 24,
   "Class5": 65,
   "Class6": 12,
   "Class7": 0,
   "Class8": 12,
   "Class9": 110,
   "Class10": 41,
   "Class11": 0,
   "Class12": 0,
   "Class13": 0
}, {
   "LOCAL_ID": "14-6A-060",
   "Class1": 19,
   "Class2": 290,
   "Class3": 224,
   "Class4": 0,
   "Class5": 0,
   "Class6": 0,
   "Class7": 0,
   "Class8": 2,
   "Class9": 0,
   "Class10": 0,
   "Class11": 1,
   "Class12": 0,
   "Class13": 0
}, {
   "LOCAL_ID": "45-5-006",
   "Class1": 7,
   "Class2": 191,
   "Class3": 165,
   "Class4": 0,
   "Class5": 6,
   "Class6": 3,
   "Class7": 0,
   "Class8": 4,
   "Class9": 18,
   "Class10": 11,
   "Class11": 0,
   "Class12": 0,
   "Class13": 10
}];



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

google.charts.setOnLoadCallback(init);


button.onclick = function() {
   current = 1 - current;
   button.disabled = true;
   options.chart['subtitle'] = (current ? 'View 1' : 'View 2');
   chart.draw(data[current], options);
};


function getData() {
   var data = new google.visualization.DataTable();

   data.addColumn('number', 'Class');
   ms2.forEach(function(masterLocation, index) {
      data.addColumn('number', masterLocation.LOCAL_ID);
   });

   for (var i = 0; i < 13; i++) {
      var arr = [i];
      ms2.forEach(function(masterLocation, index) {
         arr.push(masterLocation['Class' + i]);
      });

      data.addRow(arr);
   }

   return data;
}

function getRandomData(base) {
   var data = new google.visualization.DataTable();
   data.addColumn('number', 'Class');
   data.addColumn('number', ms2[0].LOCAL_ID);
   data.addColumn('number', ms2[1].LOCAL_ID);
   data.addColumn('number', ms2[2].LOCAL_ID);


   // add random data
   var y1 = base,
      y2 = base,
      y3 = base;
   for (var i = 0; i < 13; i++) {
      y1 += Math.floor(Math.random() * 5) * Math.pow(-1, Math.floor(Math.random() * 2));
      y2 += Math.floor(Math.random() * 5) * Math.pow(-1, Math.floor(Math.random() * 2));
      y3 += Math.floor(Math.random() * 5) * Math.pow(-1, Math.floor(Math.random() * 2));
      data.addRow([i, y1, y2, y3]);
   }

   return data;
}

function init() {
   data = [];
   data[0] = getData();
   data[1] = getRandomData(1000);
   chart = new google.charts.Line(document.getElementById('chart_div'));

   options = {
      chart: {
         title: 'Box Office Earnings in First Two Weeks of Opening',
         subtitle: 'in millions of dollars (USD)'
      },
      width: 500,
      height: 300,
      vAxis: {
         gridlines: {
            color: '#ccc'
         }
      },
      hAxis: {
         gridlines: {
            color: '#ccc'
         }
      },
      animation: {
         duration: 1000,
         easing: 'out'
      }
   };

   drawChart();
}


function drawChart() {
   var columns = [];
   var defaultSeries = [1, 2, 3];
   var series = {};
   for (var i = 0; i < data[current].getNumberOfColumns(); i++) {
      if (i === 0 || defaultSeries.indexOf(i) > -1) {
         // if the column is the domain column or in the default list, display the series
         columns.push(i);
      } else {
         // otherwise, hide it
         columns.push({
            label: data.getColumnLabel(i),
            type: data.getColumnType(i),
            sourceColumn: i,
            calc: function() {
               return null;
            }
         });
      }
      if (i > 0) {
         columns.push({
            calc: 'stringify',
            sourceColumn: i,
            type: 'string',
            role: 'annotation'
         });
         // set the default series option
         series[i - 1] = {};
         if (defaultSeries.indexOf(i) == -1) {
            // backup the default color (if set)
            if (typeof(series[i - 1].color) !== 'undefined') {
               series[i - 1].backupColor = series[i - 1].color;
            }
            series[i - 1].color = '#CCCCCC';
         }
      }
   }

   options['series'] = series;


   function showHideSeries() {
      var sel = chart.getSelection();
      if (sel.length < 1 || sel[0].row) {
         return;
      }

      var col = sel[0].column;
      if (typeof(columns[col]) == 'number') {
         var src = columns[col];


         var calcFunc = null;
         if (document.getElementById("removeSeriesOnSelect").checked) {
            calcFunc = function() {
               return null;
            };
         }

         columns[col] = {
            label: data[current].getColumnLabel(src),
            type: data[current].getColumnType(src),
            sourceColumn: src,
            calc: calcFunc
         };
         // grey out the legend entry
         series[src - 1].color = '#CCCCCC';
      } else {
         var src = columns[col].sourceColumn;
         // show the data series
         columns[col] = src;
         series[src - 1].color = null;
      }
      var view = new google.visualization.DataView(data[current]);
      view.setColumns(columns);

      chart.draw(view, options);
   }


   google.visualization.events.addListener(chart, 'select', showHideSeries);

   google.visualization.events.addListener(chart, 'ready', function() {
      button.disabled = false;
   });

   var view = new google.visualization.DataView(data[current]);
   view.setColumns(columns);
   chart.draw(view, options);
}

这里是 jsFiddle: https://jsfiddle.net/sp7atw1L/

编辑:我发起了一项悬赏。鉴于全局变量和可能的间接方式,我不反对直接重构/重新做同样的事情。

1个回答

0

实际上,这个 bug 与注释列有关。在 drawChart() 之后,您的列数组是 [0,1,{a},2,{a},3,{a}]

> when column 1 clicked, everything is ok. 
> when column 2 clicked, columns[2] is {a}, which in your code is replaced by 1, so, you get another copy of column 1
> when column 3 clicked, columns[3] is 2, so, the wrong row is selected

这些都是后果,但问题在于 chart.getSelection() 没有考虑注释列并返回错误的索引。我不确定为什么会发生这种情况,但如果您在 onclick 处理程序中像这样绘制 DataView(而不是 DataTable)

 //chart.draw(data[current], options);   <-------remove this

 var view = new google.visualization.DataView(data[current]);
 view.setColumns(columns);// <---make columns global
 chart.draw(view, options);

它解决了这个问题。注释的一个相关问题是例如here


此外,在 getData() 中的这行代码
arr.push(masterLocation['Class' + i]);

应该是

arr.push(masterLocation['Class' + i+1]);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接