Google 可视化事件侦听器累计触发

Google Visualization Event Listeners Trigger in Cumulative

我有一个 table 在我使用类别选择器之前它的行为是正确的。

正确行为:单击 table 行时,将触发“selected”事件。对列进行排序时,将触发“排序”事件。

代理 Table 的事件侦听器有问题。我从最初的 table 抽奖中放松了行为。

我的问题是当使用类别选择器来减少 table 时,我的正确行为结束了。

有问题的行为:1. 过滤“性别”,2. 单击 table 中的一行 3. “selected”事件触发两次。为什么?
当您过滤另一个“性别”时,单击 table 中的一行,“selected”事件触发三次。

所有性别筛选器都将继续存在此附加问题。

我怎样才能停下来?以下是我目前所拥有的。

一如既往地感谢您的指导。

====== 更新:

所有更改都在代码段中标记为已更新。这是摘要:

  1. 根据包含“select”侦听器的 White Hat ProxyTable 事件侦听器进行更改。

    //UPDATED changed to .addOneTimeListener google.visualization.events.addOneTimeListener(proxyTable, 'ready', function() {

  2. 从包含“select”侦听器

    的代理Table侦听器中删除了重绘Table()

    //UPDATE removed from one time listener
    //redrawTable();

  3. 为代理添加了新的 .addListenerTable 以重绘Table()

    //UPDATE Added separate listener to redraw the table google.visualization.events.addListener(proxyTable, 'ready', function() { console.log(".addListener(proxyTable, 'ready' - redrawTable()"); redrawTable(); });

google.charts.load('current', {
  'packages': ['corechart', 'table', 'gauge', 'controls', 'charteditor']
});

$(document).ready(function() {
  //console.log("ready!");
  renderChart_onPageLoad();
});

function renderChart_onPageLoad() {
  google.charts.setOnLoadCallback(function() {
    //console.log("renderChart_onPageLoad");
    drawDashboard();
  });
}

function drawDashboard() {
  //console.log("drawDashboard");

  var data = google.visualization.arrayToDataTable([
    ['Name', 'RoolNumber', 'Gender', 'Age', 'Donuts eaten'],
    ['Michael', 1, 'Male', 12, 5],
    ['Elisa', 2, 'Female', 20, 7],
    ['Robert', 3, 'Male', 7, 3],
    ['John', 4, 'Male', 54, 2],
    ['Jessica', 5, 'Female', 22, 6],
    ['Aaron', 6, 'Male', 3, 1],
    ['Margareth', 7, 'Female', 42, 8],
    ['Miranda', 8, 'Female', 33, 6]
  ]);

  var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard'));

  var categoryPicker = new google.visualization.ControlWrapper({
    controlType: 'CategoryFilter',
    containerId: 'categoryPicker',
    options: {
      filterColumnLabel: 'Gender',
      ui: {
        labelStacking: 'vertical',
        allowTyping: false,
        allowMultiple: false
      }
    }
  });

  var proxyTable = new google.visualization.ChartWrapper({
    chartType: 'Table',
    containerId: 'div_proxyTable',
    options: {
      width: '500px'
    }
  });

  var table = new google.visualization.ChartWrapper({
    chartType: 'Table',
    containerId: 'div_table',
    options: {
      sort: 'event', // <-- set sort to 'event' for table totaling
      width: '500px',
      allowHtml: true,
      page: 'enable',
      pageSize: '5',
    }
  });

  google.visualization.events.addOneTimeListener(proxyTable, 'ready', function() {
    console.log(".addOneTimeListener(proxyTable, 'ready' - sort");

    google.visualization.events.addOneTimeListener(table, 'ready', function() {
      console.log(".addOneTimeListener(table, 'ready' - sort");

      //#region table - sort: 'event'
      google.visualization.events.addListener(table.getChart(), 'sort', function(sender) {
        console.log(".addListener(table.getChart(), 'sort' - sorted");

        //// update table --> options must include (sort: 'event') for total row to work properly
        //// update var grandTotal = tableData.getFilteredRows([{column: 0,
        //// update .draw() 'table' references to new name if using for a different table variable

        // sort data table according to sort properties
        var tableData = table.getDataTable();
        var sortIndexes = tableData.getSortedRows({
          column: sender.column,
          desc: !sender.ascending
        });

        //#region reposition total row - if required
        let totalRow = [];
        let hasTotalRow = true;
        if (hasTotalRow) {
          // find grand total row
          var grandTotal = tableData.getFilteredRows([{
            column: 0, //must be placed in a column which is of type string.
            value: "Grand Total"
          }]);
          if (grandTotal.length > 0) {
            // find grand total in sort
            var grandTotalSort = sortIndexes.indexOf(grandTotal[0]);

            // remove grand total from sort
            sortIndexes.splice(grandTotalSort, 1);

            // add grand total as first index
            sortIndexes.unshift(grandTotal[0]);
          }
        }
        //#endregion

        // set table sort arrow
        table.setOption('sortAscending', sender.ascending);
        table.setOption('sortColumn', sender.column);

        // set table view & re-draw table
        table.setView({
          rows: sortIndexes
        });
        table.draw();
      });
      //#endregion

    });
  });

//UPDATED changed to .addOneTimeListener
  google.visualization.events.addOneTimeListener(proxyTable, 'ready', function() {
    console.log(".addOneTimeListener(proxyTable, 'ready' - select");

    let clickGetFunc = true;
    if (clickGetFunc !== undefined || clickGetFunc !== null) {

      google.visualization.events.addOneTimeListener(table, 'ready', function() {
        console.log(".addOneTimeListener(table, 'ready' - select");

        google.visualization.events.addListener(table.getChart(), 'select', function() {
          console.log(".addListener(table.getChart(), 'select' - selected");
          console.log("result of select");
          //lib_gcharts_selectedRowCol(table, json.tableChart.clickGetFunc);//(wrapperName, callback)
        });

      });
    }

//UPDATE removed from one time listener
    //redrawTable();
  });

//UPDATE Added separate listener to redraw the table 
 google.visualization.events.addListener(proxyTable, 'ready', function() {
    console.log(".addListener(proxyTable, 'ready' - redrawTable()");

   redrawTable();
   });

  dashboard.bind([categoryPicker], [proxyTable]);
  dashboard.draw(data);

  function redrawTable(tableChart) {
    console.log('redrawTable()');

    // set defaults for any undefined settings
    let dataView = [];
    let groupView = [];
    let totalRow = [];
    let conditionalFormat = [];

    // update .draw() 'table' or 'chart' references when using a different or additional chart name

    var sourceData = proxyTable.getDataTable().toDataTable().clone();
    //console.log('sourceData', sourceData);

    //#region create data view - this is used as basis for dataResults
    let view = new google.visualization.DataView(sourceData);

    //// set view columns
    //const viewColumns = [];
    //for (let i = 0; i < dataView.columns.length; i++) {
    //    viewColumns.push(
    //        viewColumn_default(view, dataView.columns[i]),
    //    );
    //};
    //view.setColumns(viewColumns);
    ////#endregion

    //#region set view filtering - if required
    let hasViewFilters = false;
    if (hasViewFilters) {

      const viewFilters = [];
      for (let i = 0; i < dataView.filters.columns.length; i++) {
        viewFilters.push(
          viewFilter_default(sourceData, dataView.filters.columns[i]),
        );
      };
      //console.log('viewFilter', viewFilter);

      const viewSetFilter = view.getFilteredRows(viewFilters);
      view.setRows(viewSetFilter);
    }
    //console.log('view'); console.log(view);
    //#endregion

    //#region create group view - if required
    let dataResults_forTable;
    let hasGroupView = false;
    if (hasGroupView) {

      // create keys for grouping
      const groupKeys = [];
      for (let i = 0; i < groupView.keys.length; i++) {
        groupKeys.push(
          groupKey_default(view, groupView.keys[i]),
        );
      };
      // create columns for aggregating
      const groupColumns = [];
      for (let i = 0; i < groupView.columns.length; i++) {
        groupColumns.push(
          groupColumn_default(view, groupView.columns[i]),
        );
      };

      // create data aggregation
      let group = google.visualization.data.group(view, groupKeys, groupColumns);
      //console.log('group'); console.log(group);

      let formatter;
      // set data column formatting - dynamically
      for (let i = 0; i < groupView.columns.length; i++) {
        formatter = dataColumn_format(groupView.columns[i].format);
        if (formatter !== null) {
          formatter.format(group, group.getColumnIndex(groupView.columns[i].id));
        }
      }
      //console.log('data'); console.log(data);

      // set data sorting    let hasGroupView = groupView.hasGroupView;
      let hasDataSorting = groupView.sorting.hasSorting;
      if (hasDataSorting) {
        const dataSort = [];
        for (let i = 0; i < groupView.sorting.columns.length; i++) {
          dataSort.push(
            dataSort_default(group, groupView.sorting.columns[i]),
          );
        };
        //console.log('dataSort', dataSort);
        group.sort(dataSort);
      }

      dataResults_forTable = group.clone();
    } else {
      dataResults_forTable = view.toDataTable().clone();
    } //END if (hasGroupView) {
    //console.log('dataResults_forTable', dataResults_forTable);

    //#endregion

    //#region create total row - if required
    let hasTotalRow = true;
    if (hasTotalRow) {

      let labelCol = "Total";
      let labelColIndex = 0;
      let totalColumns = 1;

      //Create groupColumns for total row aggregation calculations
      const groupColumns = [];
      for (let i = 0; i < totalColumns.length; i++) {
        const column = {
          column: dataResults_forTable.getColumnIndex(totalColumns),
          type: 'number'
        }
        switch ('sum') {
          case 'sum':
            column.aggregation = google.visualization.data.sum;
            break;
          case 'count':
            column.aggregation = google.visualization.data.count;
            break;
          case 'average':
            column.aggregation = google.visualization.data.avg;
            break;
          case 'min':
            column.aggregation = google.visualization.data.min;
            break;
          case 'max':
            column.aggregation = google.visualization.data.avg;
            break;
          default:
            column.aggregation = google.visualization.data.sum;
        }
        groupColumns.push(column);
      }

      let groupTotal = google.visualization.data.group(dataResults_forTable,
        // need key column to group on, so we want all rows grouped into 1, then it needs a constant value
        [{
          column: 0,
          type: "number",
          modifier: function() {
            return 1;
          }
        }], groupColumns);

      // this code block will run if the filter results in rows available to total.  Otherwise the table will present no rows.
      if (groupTotal.getNumberOfRows() !== 0) {

        let formatDecimal = new google.visualization.NumberFormat({
          pattern: '#,###.##'
        });
        for (let i = 1; i < groupTotal.getNumberOfColumns(); i++) {
          formatDecimal.format(groupTotal, i);
        }

        // create Grand Total row from colToTotal and groupTotal
        const gtRow = [];
        for (let i = 0; i < dataResults_forTable.getNumberOfColumns(); i++) {
          //Build GT Row to match length of dataResults_forTable
          gtRow.push(null);
        }

        //Push words "Grand Total" into it's set position in gtRow - It must go into a column of type string.
        gtRow[labelColIndex] = labelCol;

        for (let i = 0; i < totalColumns.length; i++) {
          //Loop through groupColumns, test setting type for string.

          if (totalColumns[i].type === 'string') {
            //Convert to number from groupTotal result to string to match the column it's being pushed into
            gtRow[dataResults_forTable.getColumnIndex(totalColumns)] = String(groupTotal.getValue(0, i + 1));
          } else {
            //Otherwise push in the number value
            gtRow[dataResults_forTable.getColumnIndex(totalColumns)] = groupTotal.getValue(0, i + 1);
          }
        }
        //console.log('insertRow', insertRow);

        // insert complete gtRow with values into row position 0
        dataResults_forTable.insertRows(0, [gtRow]);

        //// set number formatting for dataResults_forTable row 0 (Grand Total row)
        //let formatter;
        //for (let i = 0; i < totalRow.totalColumns.length; i++) {
        //    formatter = dataColumn_format(totalRow.totalColumns[i].format);
        //    if (formatter !== null) {
        //        //This will override any previous formatting for the columns with totals.
        //        formatter.format(dataResults_forTable, dataResults_forTable.getColumnIndex(totalRow.totalColumns[i].id))
        //    }
        //}
        ////console.log('dataResults_forTable'); console.log(dataResults_forTable);

        // add formatting for grand total row to highlight && justify to right if of type number
        for (let j = 0; j < dataResults_forTable.getNumberOfColumns(); j++) {
          //if statement on column type for left right justification
          if (dataResults_forTable.getColumnType(j) === 'number') {
            dataResults_forTable.setColumnProperty(j, 'className', 'googleTableTextRight');
            dataResults_forTable.setProperty(0, j, 'className', 'googleTableTotalRow googleTableTextRight'); //stored in css file
          } else {
            dataResults_forTable.setProperty(0, j, 'className', 'googleTableTotalRow'); //stored in css file
          }
        }
        //console.log('dataResults_forTable', dataResults_forTable);
      } //END (groupTotal.getNumberOfRows() !== 0) {
    } //END if (hasTotalRow) {
    //#endregion

    //#region conditional formatting - if required
    let hasConditionalFormat = false;
    if (hasConditionalFormat) {
      dataResults_forTable = conditionalFormatting_default(dataResults_forTable, conditionalFormat);
    } //END if (hasConditionalFormat) {
    //#endregion

    var finalView_forTable = new google.visualization.DataView(dataResults_forTable);
    //console.log('finalView_forTable', finalView_forTable);

    // set reset sorting, set dataTable & draw chart
    table.setView(null); // reset in case sorting has been used via user click
    table.setDataTable(finalView_forTable); //includes any total row
    table.draw();

  } //END redrawChart()

}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
<div id="dashboard">
    <div id="categoryPicker"></div><br />
    
    <div id="div_proxyTable" style="display: none;"></div><br />

    <div id="div_table"></div><br /><br />
</div>

不确定应该使用代理完成什么 table,
但为了防止 select 事件被多次添加,
使用一次性监听器,这里...

google.visualization.events.addOneTimeListener(proxyTable, 'ready', function() {
  console.log(".addListener(proxyTable, 'ready' - select");

  let clickGetFunc = true;
  if (clickGetFunc !== undefined || clickGetFunc !== null) {

    google.visualization.events.addOneTimeListener(table, 'ready', function() {
      console.log(".addOneTimeListener(table, 'ready' - select");

      google.visualization.events.addListener(table.getChart(), 'select', function() {
        console.log(".addListener(table.getChart(), 'select' - selected");
        console.log("result of select");
        //lib_gcharts_selectedRowCol(table, json.tableChart.clickGetFunc);//(wrapperName, callback)
      });

    });
  }


  redrawTable();
});