【问题标题】:Google Charts Event listener - first click after filter fails谷歌图表事件监听器 - 过滤失败后第一次点击
【发布时间】:2020-07-16 18:49:54
【问题描述】:

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

正确的行为:

  1. 过滤“性别”
  2. 点击表格中的一行 - 接收结果
  3. 对表格中的任何列(如性别)进行排序
  4. 点击表格中的一行 - 接收结果

问题行为:我希望能够选择一行并接收结果,而不必先对性别列进行排序。

  1. 过滤“性别”
  2. 单击表格中的一行 - 失败 - 未返回任何结果
  3. 对表格中的任何列(如性别)进行排序
  4. 点击表格中的一行 - 成功 - 你现在得到一个结果

如何在不先对列进行排序的情况下获得成功?

Grazie Mille!

   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', 'DonutsEaten'],
            ['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',
            }
        });

        //This json contains my settings for later
        let json = {
            "tableChart": {
                "hasTable": true,
                "dataView": {
                    "columns": [
                        { "id": "Name" },
                        { "id": "RoolNumber" },
                        { "id": "Gender" },
                        { "id": "Age" },
                        { "id": "DonutsEaten" }
                    ]
                },
                "groupView": {
                    "hasGroupView": false                    
                },
                "totalRow": {
                    "hasTotalRow": true,
                    "labelCol": "Total",
                    "labelColIndex": 0,//This is the column where the words "Grand Total" are stored.  It must be text column.
                    "totalColumns": [
                        { "id": "RoolNumber", "type": "number", "function": "sum" }                       
                    ]
                },
                "conditionalFormat": {
                    "hasConditionalFormat": false
                },
                "options": {},
                "hasCSV": false,
                "clickGetFunc": null
            },
        };

        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 = (json.tableChart.totalRow !== undefined) ? json.tableChart.totalRow : [];
                    let hasTotalRow = totalRow.hasTotalRow;
                    if (hasTotalRow) {
                        // find grand total row
                        var grandTotal = tableData.getFilteredRows([{
                            column: json.tableChart.totalRow.labelColIndex, //must be placed in a column which is of type string.
                            value: json.tableChart.totalRow.labelCol
                        }]);
                        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();

                    //Table ready then fires
                });
                //#endregion

            });
        });

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

            google.visualization.events.addOneTimeListener(table, 'ready', function () {
                console.log(".addOneTimeListener(table, 'ready' - select");
                test_gcharts_selectedRowCol(table, json.tableChart.clickGetFunc);//(wrapperName, callback)
            });
        });

        google.visualization.events.addListener(proxyTable, 'ready', function () {
            console.log(".addListener(proxyTable, 'ready' - redrawTable()");
            redrawTable(json.tableChart);
        });

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


        //This is a table builder which uses json from above.  This is working ok.  Contains no listeners.
        function redrawTable(tableChart) {
            console.log('redrawTable()');

            // set defaults for any undefined settings
            let dataView = (tableChart.dataView !== undefined) ? tableChart.dataView : [];
            let groupView = (tableChart.groupView !== undefined) ? tableChart.groupView : [];
            let totalRow = (tableChart.totalRow !== undefined) ? tableChart.totalRow : [];
            let conditionalFormat = (tableChart.conditionalFormat !== undefined) ? tableChart.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);

            //#region create group view - if required
            let dataResults_forTable;
            let hasGroupView = groupView.hasGroupView;
            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);

                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 = totalRow.hasTotalRow;
            if (hasTotalRow) {

                let labelCol = totalRow.labelCol;
                let labelColIndex = totalRow.labelColIndex;
                let totalColumns = totalRow.totalColumns;

                //Create groupColumns for total row aggregation calculations
                const groupColumns = [];
                for (let i = 0; i < totalColumns.length; i++) {
                    const column = { column: dataResults_forTable.getColumnIndex(totalColumns[i].id), type: 'number' }
                    switch (totalColumns[i].function) {
                        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[i].id)] = String(groupTotal.getValue(0, i + 1));
                        }
                        else {
                            //Otherwise push in the number value
                            gtRow[dataResults_forTable.getColumnIndex(totalColumns[i].id)] = groupTotal.getValue(0, i + 1);
                        }
                    }
                    //console.log('insertRow', insertRow);

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

                    // 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 = conditionalFormat.hasConditionalFormat;
            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()

    }

    function test_gcharts_selectedRowCol(wrapperName, callback) {
        //console.log('wrapperName', wrapperName); console.log('callback', callback)

        //NEW - Works with paging active
        // initialize page number and size
        var page = 0;
        var pageSize = 10;
        if (wrapperName.getOption('page') === 'enable') {
            page = wrapperName.getOption('startPage');
            pageSize = wrapperName.getOption('pageSize');
        }
        test_enableCoordinates(callback);

        // page event
        google.visualization.events.addListener(wrapperName.getChart(), 'page', function (sender) {
            console.log(".addListener(wrapperName.getChart(), 'page' - paged - test_enableCoordinates called");
            page = sender.page; // save current page
            test_enableCoordinates(callback);
        });

        // sort event
        google.visualization.events.addListener(wrapperName.getChart(), 'sort', function () {
            console.log(".addListener(wrapperName.getChart(), 'sort' - sorted - test_enableCoordinates called ")
            page = 0; // reset back to first page
            test_enableCoordinates(callback);
        });

        function test_enableCoordinates(callback) {
            //console.log('callback enableCoordinates', callback);

            //remove event listeners
            var container = document.getElementById(wrapperName.getContainerId());
            Array.prototype.forEach.call(container.getElementsByTagName('td'), function (cell) {
                cell.removeEventListener("click", test_selectCell, false);
            });

            //add event listeners
            var container = document.getElementById(wrapperName.getContainerId());
            Array.prototype.forEach.call(container.getElementsByTagName('td'), function (cell) {
                cell.addEventListener('click', test_selectCell, false);
            });
        }

        function test_selectCell(sender) {

            var cell = sender.target;
            var row = cell.closest('tr');

            var wrapperDataTable = wrapperName.getDataTable();

            var selectedRow = row.rowIndex - 1; // adjust for header row (-1)
            selectedRow = (page * pageSize) + selectedRow;  // adjust for page number

            // Original from whitehat - save sorted info
            // This version does not work after a user clicks a column to sort
            //var sortInfo = wrapperName.getChart().getSortInfo();
            //if (sortInfo.sortedIndexes !== null) {
            //    selectedRow = sortInfo.sortedIndexes[selectedRow];
            //}

            // Replaced code to which finds the view row order by .getView then taking the selected row
            // and returning the number which is in the .getView result
            var sortInfo = wrapperName.getView();  // save sorted info
            if (sortInfo !== null) {
                selectedRow = sortInfo.rows[selectedRow];
            }
            var selectedCol = cell.cellIndex;

            //var result = "selectedRow: " + selectedRow + " selectedCol: " + selectedCol;
            //var ul = document.getElementById("demo");
            //var li = document.createElement("li");
            //li.innerHTML = result;
            //ul.appendChild(li);

            var selectedValue = wrapperDataTable.getValue(selectedRow, selectedCol);
            var colID = wrapperDataTable.getColumnId(selectedCol);
            var colLabel = wrapperDataTable.getColumnLabel(selectedCol);

            var result = //removed array brackets
            {
                "selectedRow": selectedRow,
                "selectedCol": selectedCol,
                "selectedValue": selectedValue,
                "colID": colID,
                "colLabel": colLabel
            };

            //callback(result, wrapperDataTable);
            console.log('test_selectCell', result);
            return result;
        }
    }
<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 />
    Proxy Table<br />
    <div id="div_proxyTable" style="display:none;"></div><br />
    Table<br />
    <div id="div_table"></div><br /><br />
</div>

================多个仪表板场景======================

提供的解决方案适用于单个 drawDashboard() 场景。然而,它在我想在接下来讨论的多个 drawDashboard() 场景中分解。

我将在此页面中添加额外的 drawDashboard() 函数。
它们还需要相同的功能并保持相互独立。

有没有办法在没有全局变量的情况下容纳多个drawDashboard() 函数?

我是否将 listenerPagelistenerSort 移动到特定的 drawDashboard() 函数中以自包含?

我希望只维护一个库函数test_gcharts_selectedRowCol(),而不是复制它以添加额外的drawDashboard()

https://jsfiddle.net/cmill/pvj23nfk/

在运行时,drawDashboard_A()listenerPage 开头,listenerSort = null。然后它将为每个执行.addListener 例程。

那么当drawDashboard_B() 运行时,listenerPagelistenerSort 不再为空,而是由drawDashboard_A() 的传递设置。

排序和点击事件可以根据需要完美运行并返回结果。

不良行为:

  1. 点击drawDashboard_A()中的第2页

  2. 点击一行 - 失败 - 没有结果。

  3. 点击drawDashboard_B()中的第2页

  4. 点击一行 - PASS - 接收结果。

【问题讨论】:

    标签: javascript charts google-visualization


    【解决方案1】:

    纠正表格单元格选择事件的问题,
    使用addListener 而不是addOneTimeListener,这里...

        google.visualization.events.addOneTimeListener(proxyTable, 'ready', function () {
            console.log(".addOneTimeListener(proxyTable, 'ready' - select");
    
       // USE addListener HERE
    
            google.visualization.events.addListener(table, 'ready', function () {
                console.log(".addOneTimeListener(table, 'ready' - select");
                test_gcharts_selectedRowCol(table, json.tableChart.clickGetFunc);//(wrapperName, callback)
            });
        });
    

    然后确保我们不会收到多个排序和页面事件,
    添加时保存对侦听器句柄的引用,
    并在再次添加之前删除。

    我们可以使用一个对象来存储处理程序,
    并将图表包装器的容器 id 作为键...

    // save handles to event listeners
    var listenerPage = {};
    var listenerSort = {};
    
    function test_gcharts_selectedRowCol(wrapperName, callback) {
      //console.log('wrapperName', wrapperName); console.log('callback', callback)
    
      //NEW - Works with paging active
      // initialize page number and size
      var page = 0;
      var pageSize = 10;
      if (wrapperName.getOption('page') === 'enable') {
        page = wrapperName.getOption('startPage');
        pageSize = wrapperName.getOption('pageSize');
      }
      test_enableCoordinates(callback);
    
      // remove previous event handlers
      if (listenerPage.hasOwnProperty(wrapperName.getContainerId())) {
        google.visualization.events.removeListener(listenerPage[wrapperName.getContainerId()]);
        delete listenerPage[wrapperName.getContainerId()];
      }
      if (listenerSort.hasOwnProperty(wrapperName.getContainerId())) {
        google.visualization.events.removeListener(listenerSort[wrapperName.getContainerId()]);
        delete listenerSort[wrapperName.getContainerId()];
      }
    
      // page event
      listenerPage[wrapperName.getContainerId()] = google.visualization.events.addListener(wrapperName.getChart(), 'page', function(sender) {
        console.log(".addListener(wrapperName.getChart(), 'page' - paged - test_enableCoordinates called");
        page = sender.page; // save current page
        test_enableCoordinates(callback);
      });
    
      // sort event
      listenerSort[wrapperName.getContainerId()] = google.visualization.events.addListener(wrapperName.getChart(), 'sort', function() {
        console.log(".addListener(wrapperName.getChart(), 'sort' - sorted - test_enableCoordinates called ")
        page = 0; // reset back to first page
        test_enableCoordinates(callback);
      });
    

    请参阅以下工作 sn-p...

    google.charts.load('current', {
      'packages': ['corechart', 'table', 'gauge', 'controls', 'charteditor']
    }).then(drawDashboard);
    
    function drawDashboard() {
      //console.log("drawDashboard");
    
      var data = google.visualization.arrayToDataTable([
        ['Name', 'RoolNumber', 'Gender', 'Age', 'DonutsEaten'],
        ['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',
        }
      });
    
      //This json contains my settings for later
      let json = {
        "tableChart": {
          "hasTable": true,
          "dataView": {
            "columns": [{
                "id": "Name"
              },
              {
                "id": "RoolNumber"
              },
              {
                "id": "Gender"
              },
              {
                "id": "Age"
              },
              {
                "id": "DonutsEaten"
              }
            ]
          },
          "groupView": {
            "hasGroupView": false
          },
          "totalRow": {
            "hasTotalRow": true,
            "labelCol": "Total",
            "labelColIndex": 0, //This is the column where the words "Grand Total" are stored.  It must be text column.
            "totalColumns": [{
              "id": "RoolNumber",
              "type": "number",
              "function": "sum"
            }]
          },
          "conditionalFormat": {
            "hasConditionalFormat": false
          },
          "options": {},
          "hasCSV": false,
          "clickGetFunc": null
        },
      };
    
      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 = (json.tableChart.totalRow !== undefined) ? json.tableChart.totalRow : [];
            let hasTotalRow = totalRow.hasTotalRow;
            if (hasTotalRow) {
              // find grand total row
              var grandTotal = tableData.getFilteredRows([{
                column: json.tableChart.totalRow.labelColIndex, //must be placed in a column which is of type string.
                value: json.tableChart.totalRow.labelCol
              }]);
              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();
    
            //Table ready then fires
          });
          //#endregion
    
        });
      });
    
      google.visualization.events.addOneTimeListener(proxyTable, 'ready', function() {
        console.log(".addOneTimeListener(proxyTable, 'ready' - select");
    
        google.visualization.events.addListener(table, 'ready', function() {
          console.log(".addOneTimeListener(table, 'ready' - select");
          test_gcharts_selectedRowCol(table, json.tableChart.clickGetFunc); //(wrapperName, callback)
        });
      });
    
      google.visualization.events.addListener(proxyTable, 'ready', function() {
        console.log(".addListener(proxyTable, 'ready' - redrawTable()");
        redrawTable(json.tableChart);
      });
    
      dashboard.bind([categoryPicker], [proxyTable]);
      dashboard.draw(data);
    
    
      //This is a table builder which uses json from above.  This is working ok.  Contains no listeners.
      function redrawTable(tableChart) {
        console.log('redrawTable()');
    
        // set defaults for any undefined settings
        let dataView = (tableChart.dataView !== undefined) ? tableChart.dataView : [];
        let groupView = (tableChart.groupView !== undefined) ? tableChart.groupView : [];
        let totalRow = (tableChart.totalRow !== undefined) ? tableChart.totalRow : [];
        let conditionalFormat = (tableChart.conditionalFormat !== undefined) ? tableChart.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);
    
        //#region create group view - if required
        let dataResults_forTable;
        let hasGroupView = groupView.hasGroupView;
        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);
    
          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 = totalRow.hasTotalRow;
        if (hasTotalRow) {
    
          let labelCol = totalRow.labelCol;
          let labelColIndex = totalRow.labelColIndex;
          let totalColumns = totalRow.totalColumns;
    
          //Create groupColumns for total row aggregation calculations
          const groupColumns = [];
          for (let i = 0; i < totalColumns.length; i++) {
            const column = {
              column: dataResults_forTable.getColumnIndex(totalColumns[i].id),
              type: 'number'
            }
            switch (totalColumns[i].function) {
              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[i].id)] = String(groupTotal.getValue(0, i + 1));
              } else {
                //Otherwise push in the number value
                gtRow[dataResults_forTable.getColumnIndex(totalColumns[i].id)] = groupTotal.getValue(0, i + 1);
              }
            }
            //console.log('insertRow', insertRow);
    
            // insert complete gtRow with values into row position 0
            dataResults_forTable.insertRows(0, [gtRow]);
    
            // 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 = conditionalFormat.hasConditionalFormat;
        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()
    
    }
    
    // save handles to event listeners
    var listenerPage = {};
    var listenerSort = {};
    
    function test_gcharts_selectedRowCol(wrapperName, callback) {
      //console.log('wrapperName', wrapperName); console.log('callback', callback)
    
      //NEW - Works with paging active
      // initialize page number and size
      var page = 0;
      var pageSize = 10;
      if (wrapperName.getOption('page') === 'enable') {
        page = wrapperName.getOption('startPage');
        pageSize = wrapperName.getOption('pageSize');
      }
      test_enableCoordinates(callback);
    
      // remove previous event handlers
      if (listenerPage.hasOwnProperty(wrapperName.getContainerId())) {
        google.visualization.events.removeListener(listenerPage[wrapperName.getContainerId()]);
        delete listenerPage[wrapperName.getContainerId()];
      }
      if (listenerSort.hasOwnProperty(wrapperName.getContainerId())) {
        google.visualization.events.removeListener(listenerSort[wrapperName.getContainerId()]);
        delete listenerSort[wrapperName.getContainerId()];
      }
    
      // page event
      listenerPage[wrapperName.getContainerId()] = google.visualization.events.addListener(wrapperName.getChart(), 'page', function(sender) {
        console.log(".addListener(wrapperName.getChart(), 'page' - paged - test_enableCoordinates called");
        page = sender.page; // save current page
        test_enableCoordinates(callback);
      });
    
      // sort event
      listenerSort[wrapperName.getContainerId()] = google.visualization.events.addListener(wrapperName.getChart(), 'sort', function() {
        console.log(".addListener(wrapperName.getChart(), 'sort' - sorted - test_enableCoordinates called ")
        page = 0; // reset back to first page
        test_enableCoordinates(callback);
      });
    
      function test_enableCoordinates(callback) {
        //console.log('callback enableCoordinates', callback);
    
        //remove event listeners
        var container = document.getElementById(wrapperName.getContainerId());
        Array.prototype.forEach.call(container.getElementsByTagName('td'), function(cell) {
          cell.removeEventListener("click", test_selectCell, false);
        });
    
        //add event listeners
        var container = document.getElementById(wrapperName.getContainerId());
        Array.prototype.forEach.call(container.getElementsByTagName('td'), function(cell) {
          cell.addEventListener('click', test_selectCell, false);
        });
      }
    
      function test_selectCell(sender) {
    
        var cell = sender.target;
        var row = cell.closest('tr');
    
        var wrapperDataTable = wrapperName.getDataTable();
    
        var selectedRow = row.rowIndex - 1; // adjust for header row (-1)
        selectedRow = (page * pageSize) + selectedRow; // adjust for page number
    
        // Original from whitehat - save sorted info
        // This version does not work after a user clicks a column to sort
        //var sortInfo = wrapperName.getChart().getSortInfo();
        //if (sortInfo.sortedIndexes !== null) {
        //    selectedRow = sortInfo.sortedIndexes[selectedRow];
        //}
    
        // Replaced code to which finds the view row order by .getView then taking the selected row
        // and returning the number which is in the .getView result
        var sortInfo = wrapperName.getView(); // save sorted info
        if (sortInfo !== null) {
          selectedRow = sortInfo.rows[selectedRow];
        }
        var selectedCol = cell.cellIndex;
    
        //var result = "selectedRow: " + selectedRow + " selectedCol: " + selectedCol;
        //var ul = document.getElementById("demo");
        //var li = document.createElement("li");
        //li.innerHTML = result;
        //ul.appendChild(li);
    
        var selectedValue = wrapperDataTable.getValue(selectedRow, selectedCol);
        var colID = wrapperDataTable.getColumnId(selectedCol);
        var colLabel = wrapperDataTable.getColumnLabel(selectedCol);
    
        var result = //removed array brackets
          {
            "selectedRow": selectedRow,
            "selectedCol": selectedCol,
            "selectedValue": selectedValue,
            "colID": colID,
            "colLabel": colLabel
          };
    
        //callback(result, wrapperDataTable);
        console.log('test_selectCell', result);
        return result;
      }
    }
    <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 />
        Proxy Table<br />
        <div id="div_proxyTable" style="display:none;"></div><br />
        Table<br />
        <div id="div_table"></div><br /><br />
    </div>

    【讨论】:

    • google.visualization.events.removeAllListeners(wrapperName.getChart()); 还删除了使排序工作的侦听器//#region table - sort: 'event' google.visualization.events.addListener(table.getChart(), 'sort', function (sender) { console.log(".addListener(table.getChart(), 'sort' - sorted"); 所以现在单击要排序的列时,不会发生实际排序。
    • 谢谢,没听懂。更改了上面的答案,请参阅listenerPage & listenerSort...
    • 您好,当页面上只有一个可视化时,这非常有用。当我添加第二个时,分页没有按预期工作。排序很好。请参阅上面对我的帖子的编辑。我是否需要为新问题再张贴一张票?
    • 好的,上面更改了答案,应该适用于多个仪表板,只要每个图表包装器都有一个唯一的容器 ID。我们唯一的event 方法是添加、删除和全部删除。要使用remove,我们必须有add...返回的句柄...
    • 你知道我总是很乐意提供帮助!希望这有效...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-21
    • 1970-01-01
    • 1970-01-01
    • 2016-10-14
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多