Search code examples
javascriptjquerychartsgoogle-visualization

Google charts - programmatic slider keeps putting both values to the left


I made a google chart that I want to use to check visitors of my website. The problem is that the programmatic slider keeps putting both values to the left on initial load and on new calls of the function drawChart().

Sample of my code:
HTML:

 <div id="programmatic_dashboard_div">
 <div id="programmatic_control_div"></div>
 <div id="programmatic_chart_div"></div>     
 </div>
 <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>

JS:

google.charts.load('current', {
  'packages': ['corechart', 'controls']
});
google.charts.setOnLoadCallback(drawChart);



function drawChart() {

  var visits = ([
    ['Date', 'Views', 'Unique visitors', 'Returning visitors'],
    [new Date('2020-04-20'), 5, 1, 0],
    [new Date('2020-04-21'), 1, 1, 1],
    [new Date('2020-04-22'), 4, 2, 1],
    [new Date('2020-04-23'), 4, 1, 1],
    [new Date('2020-04-24'), 0, 0, 0],
    [new Date('2020-04-25'), 0, 0, 0],
    [new Date('2020-04-26'), 1, 1, 1],
    [new Date('2020-04-27'), 2, 1, 1],
    [new Date('2020-04-28'), 6, 2, 1],
    [new Date('2020-04-29'), 5, 1, 1],
    [new Date('2020-04-30'), 5, 2, 2],
    [new Date('2020-05-01'), 5, 1, 1],
    [new Date('2020-05-02'), 8, 2, 1],
    [new Date('2020-05-03'), 2, 1, 1],
  ]);

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

  // We omit "var" so that programmaticSlider is visible to changeRange.
  var programmaticSlider = new google.visualization.ControlWrapper({
    'controlType': 'DateRangeFilter',
    'containerId': 'programmatic_control_div',
    'options': {
      'filterColumnLabel': 'Date',
      'ui': {
        'labelStacking': 'vertical'
      }
    }
  });

  var programmaticChart = new google.visualization.ChartWrapper({
    'chartType': 'ColumnChart',
    'containerId': 'programmatic_chart_div',
    'options': {
      'height': 400,
      'width': '100%',
      'legend': 'right',
      'chartArea': {
        'top': 10,
        'right': 200,
        'bottom': 100,
        'left': 100,
      },
    },
  });

  var data = google.visualization.arrayToDataTable(visits);

  dashboard.bind(programmaticSlider, programmaticChart);
  dashboard.draw(data);


  //default
  programmaticSlider.setState({
    'lowValue': new Date().addDays(-7),
    'highValue': new Date()
  });
  programmaticSlider.draw();



}




$(document).ready(function() {
  $(window).resize(function() {
    drawChart();
  });
});



Date.prototype.addDays = function(days) {
  var date = new Date(this.valueOf());
  date.setDate(date.getDate() + days);
  return date;
};


function dateConvert(date) {
  var dd = String(date.getDate()).padStart(2, '0');
  var mm = String(date.getMonth() + 1).padStart(2, '0'); //January is 0!
  var yyyy = date.getFullYear();

  return yyyy + '-' + mm + '-' + dd;
}

Fiddle: https://jsfiddle.net/rz8nypef/

You can see that by resizing the page the slider starts to quickly move between the right value where it should be and the left value where it ends up. What is causing this and is there a way to fix it?


Solution

  • not sure exactly why it behaves that way,
    but...

    the slider is being drawn once here...

    dashboard.bind(programmaticSlider, programmaticChart);
    dashboard.draw(data);
    

    then the state is changed and drawn again here...

    programmaticSlider.setState({
      lowValue: new Date().addDays(-7),
      highValue: new Date()
    });
    programmaticSlider.draw();
    

    all before it has time to finish the initial draw.
    and the slider does not need to be drawn after calling setState
    it's probably just too much for the control to handle properly.

    instead, just set the initial state in the control's definition...

    var programmaticSlider = new google.visualization.ControlWrapper({
      controlType: 'DateRangeFilter',
      containerId: 'programmatic_control_div',
      options: {
        filterColumnLabel: 'Date',
        ui: {
          labelStacking: 'vertical'
        }
      },
      state: {
        lowValue: new Date().addDays(-7),
        highValue: new Date()
      }
    });
    

    see following working snippet...

    google.charts.load('current', {
      packages: ['corechart', 'controls']
    });
    google.charts.setOnLoadCallback(drawChart);
    
    function drawChart() {
      var visits = ([
        ['Date', 'Views', 'Unique visitors', 'Returning visitors'],
        [new Date('2020-04-20'), 5, 1, 0],
        [new Date('2020-04-21'), 1, 1, 1],
        [new Date('2020-04-22'), 4, 2, 1],
        [new Date('2020-04-23'), 4, 1, 1],
        [new Date('2020-04-24'), 0, 0, 0],
        [new Date('2020-04-25'), 0, 0, 0],
        [new Date('2020-04-26'), 1, 1, 1],
        [new Date('2020-04-27'), 2, 1, 1],
        [new Date('2020-04-28'), 6, 2, 1],
        [new Date('2020-04-29'), 5, 1, 1],
        [new Date('2020-04-30'), 5, 2, 2],
        [new Date('2020-05-01'), 5, 1, 1],
        [new Date('2020-05-02'), 8, 2, 1],
        [new Date('2020-05-03'), 2, 1, 1],
      ]);
    
      var dashboard = new google.visualization.Dashboard(
        document.getElementById('programmatic_dashboard_div')
      );
    
      var programmaticSlider = new google.visualization.ControlWrapper({
        controlType: 'DateRangeFilter',
        containerId: 'programmatic_control_div',
        options: {
          filterColumnLabel: 'Date',
          ui: {
            labelStacking: 'vertical'
          }
        },
        state: {
          lowValue: new Date().addDays(-7),
          highValue: new Date()
        }
      });
    
      var programmaticChart = new google.visualization.ChartWrapper({
        chartType: 'ColumnChart',
        containerId: 'programmatic_chart_div',
        options: {
          height: 400,
          width: '100%',
          legend: 'right',
          chartArea: {
            top: 10,
            right: 200,
            bottom: 100,
            left: 100,
          },
        },
      });
    
      var data = google.visualization.arrayToDataTable(visits);
    
      dashboard.bind(programmaticSlider, programmaticChart);
      dashboard.draw(data);
    }
    
    $(document).ready(function() {
      $(window).resize(function() {
        drawChart();
      });
    });
    
    Date.prototype.addDays = function(days) {
      var date = new Date(this.valueOf());
      date.setDate(date.getDate() + days);
      return date;
    };
    
    function dateConvert(date) {
      var dd = String(date.getDate()).padStart(2, '0');
      var mm = String(date.getMonth() + 1).padStart(2, '0'); //January is 0!
      var yyyy = date.getFullYear();
    
      return yyyy + '-' + mm + '-' + dd;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://www.gstatic.com/charts/loader.js"></script>
    <div id="programmatic_dashboard_div">
      <div id="programmatic_control_div"></div>
      <div id="programmatic_chart_div"></div>
    </div>
    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>