Google Timeline Visualization don't change ser

2019-02-28 21:53发布

问题:

So I've got a timeline with data in it that can be concurrent...

When I move the ChartRangeSlider to a different timeframe, some of the timeline bars will either disappear or show because there is nothing happening in the timeframe that is active.

These is how the timeline and the range slider are set up. I don't have any event listeners running...

       // Configure range slider
        var timelineRangeSlider = new google.visualization.ControlWrapper({
            'controlType': 'ChartRangeFilter',
            'containerId': 'timeline-filter',
            'state': 
            {
                'range': 
                {
                    'start': currentTime,
                    'end':   fourWeek                   
                }
            },
            'options': 
            {
                'filterColumnIndex': 4,
                'ui': 
                {
                    'chartType': 'ScatterChart',
                    'chartOptions': 
                    {
                        'width': '100%',
                        'height': '50',
                        'chartArea': 
                        {
                            'width': '80%', // make sure this is the same for the chart and control so the axes align right
                            'height': '80%'
                        },
                        'hAxis': 
                        {
                            'baselineColor': 'none'
                        }
                    },
                    'chartView': 
                    {
                        'columns': [4,6]
                    }
                }
            }
        });

        // Configure timeline
        var timeline = new google.visualization.ChartWrapper({
            'chartType': 'Timeline',
            'containerId': 'timeline-chart',
            'options': 
            {
                'timeline': 
                {
                    'showBarLabels': false
                },
                'width': '100%',
                'height': '325',
                'tooltip': 
                {
                    'isHtml': true
                },
                'chartArea': 
                {
                    'width': '80%', // make sure this is the same for the chart and control so the axes align right
                    'height': '80%'
                }, 
            },
            'view': 
            {
                'columns': [0,1,2,3,4,5]
            }           
        });

How can I stop this from happening, and have each of the four separate rows (one for each series) have a static height that won't change when I interact with the range slider?

回答1:

to display the same number of rows, regardless of the filter settings,
replace the rows removed by the filter with "blank" rows,
doing so will require some manipulation

if you're using a dashboard to bind the chart and filter,
it will probably be easier to draw each independently
listen for the 'statechange' event on the filter,
to know when to re-draw the chart

use a data view to exclude the rows hidden by the filter,
add blank rows in their place
use the colors option on the timeline to set blank rows to 'transparent'
also use a blank tooltip for these rows

see following working snippet, for an example of how this could be accomplished...

google.charts.load('current', {
  packages: ['controls', 'timeline']
}).then(function () {
  var dataTable = google.visualization.arrayToDataTable([
    ['Row Label', 'Bar Label', {role: 'tooltip', type: 'string', p: {html: true}}, 'Start', 'End', 'Scatter', 'Data / Blank'],
    ['A', 'Series 0', null, new Date(2018, 1, 1), new Date(2018, 1, 28), 1, 'data'],
    ['B', 'Series 1', null, new Date(2018, 4, 1), new Date(2018, 4, 31), 1, 'data'],
    ['C', 'Series 2', null, new Date(2018, 7, 1), new Date(2018, 7, 31), 1, 'data'],
    ['D', 'Series 3', null, new Date(2018, 10, 1), new Date(2018, 10, 30), 1, 'data']
  ]);

  var blankTooltip = '<div class="hidden"></div>';
  var colorPallette = ['cyan', 'magenta', 'lime', 'yellow'];
  var dateRange = {
    start: dataTable.getColumnRange(3),
    end: dataTable.getColumnRange(4)
  };

  // Configure range slider
  var timelineRangeSlider = new google.visualization.ControlWrapper({
    controlType: 'ChartRangeFilter',
    containerId: 'timeline-filter',

    dataTable: dataTable,

    state: {
      range: {
        start: dateRange.start.min,
        end: dateRange.end.max
      }
    },
    options: {
      filterColumnIndex: 3,
      ui: {
        chartType: 'ScatterChart',
        chartOptions: {
          width: '100%',
          height: '50',
          chartArea: {
            width: '80%',
            height: '80%'
          },
          hAxis: {
            baselineColor: 'none'
          }
        },
        chartView: {
          columns: [3,5]
        }
      }
    }
  });

  google.visualization.events.addListener(timelineRangeSlider, 'statechange', function (props) {
    // filter state
    var state = timelineRangeSlider.getState();

    // wait until statechange has finished
    if (!props.inProgress) {
      // delete previously added blank rows
      var blankRows = dataTable.getFilteredRows([{
        column: 6,
        value: 'blank'
      }]);
      var i = blankRows.length;
      while (i--) {
        dataTable.removeRow(blankRows[i]);
      }

      // add blank rows for non-visible rows
      var blankRows = [];
      var timelineColors = [];
      var visibleRows = dataTable.getFilteredRows([{
        column: 3,
        minValue: state.range.start
      }, {
        column: 4,
        maxValue: state.range.end
      }]);
      for (var i = 0; i < dataTable.getNumberOfRows(); i++) {
        if (visibleRows.indexOf(i) === -1) {
          blankRows.push([
            dataTable.getValue(i, 0),
            dataTable.getValue(i, 1),
            blankTooltip,
            state.range.start,
            state.range.start,
            1,
            'blank'
          ]);
          timelineColors.push('transparent');
        } else {
          timelineColors.push(colorPallette[i]);
        }
      }

      // build timeline view rows
      var lastRowIndex = dataTable.addRows(blankRows);
      var i = blankRows.length;
      while (i--) {
        visibleRows.push((lastRowIndex - i));
      }

      // re-config timeline
      var timelineView = new google.visualization.DataView(dataTable);
      timelineView.setRows(visibleRows);
      timelineView = timelineView.toDataTable();
      timelineView.sort([{column: 0}]);
      timeline.setDataTable(timelineView);
      timeline.setOption('colors', timelineColors);
      timeline.draw();
    }
  });

  timelineRangeSlider.draw();

  // Configure timeline
  var timeline = new google.visualization.ChartWrapper({
    chartType: 'Timeline',
    containerId: 'timeline-chart',

    dataTable: dataTable,

    options: {
      colors: colorPallette,

      timeline: {
        showBarLabels: false
      },
      width: '100%',
      height: '325',
      tooltip: {
        isHtml: true
      },
      chartArea: {
        width: '80%',
        height: '80%'
      }
    },
    view: {
      columns: [0,1,2,3,4]
    }
  });
  timeline.draw();
});
.hidden {
  display: none;
  visibility: hidden;
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="dashboard_div">
  <div id="timeline-filter"></div>
  <div id="timeline-chart"></div>
</div>