Search code examples
javascriptsortingchartsgoogle-visualization

How to fix two rows at top when sorting a google visualization table?


I have two rows in a google visualization table that I want to keep fixed at the top after a sort and then draw the table again. I'm using:

var data = new google.visualization.DataTable();
var table1 = new google.visualization.Table(document.getElementById('my_div'));
var ascendOrDescend = true;
...
data.sort({column: colIndex, desc: ascendOrDescend});
ascendOrDescend = !ascendOrDescend;
table1.draw(data, options);

Is there a way to fix those two rows or after the sort force them back to the top?


Solution

  • in order to fix a row at a certain position within the sort,
    you need to manually control the sort order.

    to control manually, set the following option when drawing the table.

    var options = {
      sort: 'event'
    };
    

    the table's sort event will provide the column and direction requested by the user
    you can pass the column and direction to data table method getSortedRows
    which will return an array of row indexes that meet the sort criteria

    // table sort event
    google.visualization.events.addListener(table, 'sort', function (sender) {
      // get sorted rows indexes
      var sortIndexes = data.getSortedRows({column: sender.column, desc: !sender.ascending});
    

    we can manipulate the array of row indexes by moving the row indexes we want at the top
    and create a data view and use the setRows method to provide the order in which the data view should appear

    var view = new google.visualization.DataView(data);
    view.setRows(sortIndexes);
    

    in order for the table to display the sort direction arrow above the correct column we set the following table options

    options.sortAscending = sender.ascending;
    options.sortColumn = sender.column;
    

    then draw the table using the newly created data view

    see following working snippet,
    the rows for 'Michael' and 'Elisa' will remain at the top after each sort

    google.charts.load('current', {
      packages: ['corechart', 'table']
    }).then(function () {
      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 table = new google.visualization.Table(document.getElementById('table'));
      var options = {
        sort: 'event'
      };
    
      // table sort event
      google.visualization.events.addListener(table, 'sort', function (sender) {
        // get sorted rows indexes
        var sortIndexes = data.getSortedRows({column: sender.column, desc: !sender.ascending});
    
        // move values to top
        moveToTop(sender, sortIndexes, 'Elisa');
        moveToTop(sender, sortIndexes, 'Michael');
    
        // set table sort arrow
        options.sortAscending = sender.ascending;
        options.sortColumn = sender.column;
    
        // build table view with custom sort
        var view = new google.visualization.DataView(data);
        view.setRows(sortIndexes);
    
        // draw table with view
        table.draw(view, options);
      });
    
      // move value to top of sort
      function moveToTop(sender, sortIndexes, value) {
        // find value in current sort
        var fixedRows = data.getFilteredRows([{
          column: 0,
          value: value
        }]);
        if (fixedRows.length > 0) {
          // move value to top
          sortIndexes.splice(sortIndexes.indexOf(fixedRows[0]), 1);
          sortIndexes.unshift(fixedRows[0]);
        }
      }
    
      // first draw
      table.draw(data, options);
    });
    <script src="https://www.gstatic.com/charts/loader.js"></script>
    <div id="table"></div>