Google 可视化 - 在事件 table 排序时,将特定行保留为第一个可见记录?

Google Visualization - On event table sort, keep specific row as first visible record?

当用户单击 header 进行排序时,我希望标记为 "Grand Total" 的行保留在可见的第一行。

我可以按如下方式捕获 table 排序事件:

google.visualization.events.addListener(table.getChart(), 'sort', function() {
      console.log('User clicked to sort.');
};

但我不知道如何才能将总行移回第一条记录。

我怎样才能做到这一点?感谢您的提示。

工作示例:(起始代码)

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

$(document).ready(function() {
  renderChart_onPageLoad();
});

function renderChart_onPageLoad() {
  google.charts.setOnLoadCallback(function() {
    drawDashboard();
  });
}

function 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: 'proxyTable',
    options: {
      width: '500px'
    }
  });

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

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

  google.visualization.events.addListener(dashboard, 'ready', function() {
    redrawChart();
  });

  function redrawChart() {

    var sourceData = proxyTable.getDataTable();
    var dataResults = sourceData.toDataTable().clone();

    var group = google.visualization.data.group(sourceData, [{
      // we need a key column to group on, but since we want all rows grouped into 1, 
      // then it needs a constant value
      column: 0,
      type: 'number',
      modifier: function() {
        return 1;
      }
    }], [{
      column: 1,
      id: 'SumRool',
      label: 'SumRool',
      type: 'number',
      aggregation: google.visualization.data.sum
    }, {
      column: 3,
      id: 'SumAge',
      label: 'SumAge',
      type: 'number',
      aggregation: google.visualization.data.sum
    }, {
      // get the average age
      column: 4,
      id: 'SumEaten',
      label: 'SumEaten',
      type: 'number',
      aggregation: google.visualization.data.sum
    }]);

    dataResults.insertRows(0, [
      ['Grand Total', group.getValue(0, 1), null, group.getValue(0, 2), group.getValue(0, 3)],
    ]);

    //Set dataTable
    table.setDataTable(dataResults);
    table.draw();

    // table sort event
    google.visualization.events.addListener(table.getChart(), 'sort', function() {
      console.log('User clicked header to sort.');

      //When a user clicks the header and resorts the table I want the row labeled "Grand Total" to stay as the first row visible.


    });
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>

<div id="dashboard">
  <div id="categoryPicker"></div><br />
  <div id="proxyTable" style='display:none;'></div>
  <div id="table"></div><br /><br />
</div>

为了完成,我们需要手动控制排序顺序。

首先,在 table 图表上设置排序选项。

var table = new google.visualization.ChartWrapper({
  chartType: 'Table',
  containerId: 'table',
  options: {
    sort: 'event',  // <-- set sort to 'event'
    width: '500px'
  }
});

接下来,我们需要在绘制图表之前分配事件侦听器。
首先,我们必须等待包装器准备好,
然后将排序事件分配给图表。
但我们只想这样做一次,因此 --> addOneTimeListener

google.visualization.events.addOneTimeListener(table, 'ready', function() {
  google.visualization.events.addListener(table.getChart(), 'sort', function(sender) {

排序事件接收发生排序的列和方向的属性。 (sender)
我们将使用这些属性从数据 table.
中获取排序后的行 之后,我们找到总计行的索引,将其从排序顺序中删除,
然后将其添加回第一个索引。

// table sort event
google.visualization.events.addOneTimeListener(table, 'ready', function() {
  google.visualization.events.addListener(table.getChart(), 'sort', function(sender) {
    // sort data table according to sort properties
    var tableData = table.getDataTable();
    var sortIndexes = tableData.getSortedRows({column: sender.column, desc: !sender.ascending});

    // find grand total row
    var grandTotal = tableData.getFilteredRows([{
      column: 0,
      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]);

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

      // set table view
      table.setView({rows: sortIndexes});

      // re-draw table
      table.draw();
    }
  });
});

请参阅以下工作片段...

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

$(document).ready(function() {
  renderChart_onPageLoad();
});

function renderChart_onPageLoad() {
  google.charts.setOnLoadCallback(function() {
    drawDashboard();
  });
}

function 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: 'proxyTable',
    options: {
      width: '500px'
    }
  });

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

 // table sort event
 // Moved this listener to main drawDashboard() because having this in redrawChart() was adding a new listener every time someone filtered categoryPicker.
    google.visualization.events.addOneTimeListener(table, 'ready', function() {
      google.visualization.events.addListener(table.getChart(), 'sort', function(sender) {
        // sort data table according to sort properties
        var tableData = table.getDataTable();
        var sortIndexes = tableData.getSortedRows({column: sender.column, desc: !sender.ascending});

        // find grand total row
        var grandTotal = tableData.getFilteredRows([{
          column: 0,
          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]);

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

          // set table view
          table.setView({rows: sortIndexes});

          // re-draw table
          table.draw();
        }
      });
    });

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

  google.visualization.events.addListener(dashboard, 'ready', function() {
    redrawChart();
  });

  function redrawChart() {
    var sourceData = proxyTable.getDataTable();
    var dataResults = sourceData.toDataTable().clone();
 
    var group = google.visualization.data.group(sourceData, [{
      // we need a key column to group on, but since we want all rows grouped into 1,
      // then it needs a constant value
      column: 0,
      type: 'number',
      modifier: function() {
        return 1;
      }
    }], [{
      column: 1,
      id: 'SumRool',
      label: 'SumRool',
      type: 'number',
      aggregation: google.visualization.data.sum
    }, {
      column: 3,
      id: 'SumAge',
      label: 'SumAge',
      type: 'number',
      aggregation: google.visualization.data.sum
    }, {
      // get the average age
      column: 4,
      id: 'SumEaten',
      label: 'SumEaten',
      type: 'number',
      aggregation: google.visualization.data.sum
    }]);

    dataResults.insertRows(0, [
      ['Grand Total', group.getValue(0, 1), null, group.getValue(0, 2), group.getValue(0, 3)],
    ]);
    
   //Reset view to clear any user sorting initiated by event listener table.getChart(), 'sort'
    table.setView(null);   
   
    //Set dataTable
    table.setDataTable(dataResults);
    table.draw();
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>

<div id="dashboard">
  <div id="categoryPicker"></div><br />
  <div id="proxyTable" style='display:none;'></div>
  <div id="table"></div><br /><br />
</div>