显示空白图表然后使用按钮更新它(Google Charts)

时间:2014-10-13 18:20:57

标签: javascript charts google-visualization

我正在尝试使用谷歌图表创建一些数据的散点图可视化。最初,我希望在用户单击按钮之前呈现图表但是为空。我希望它被绘制为空的原因是,即使没有加载数据,图表也会占据页面上的正确区域。

按html按钮会向远程服务器发送请求,获取一些数据,然后在加载数据后刷新显示,以显示可爱的更新图形。

问题是,即使将数据添加到TableData变量并请求dashboard.draw(),图表显示也不会更新。我觉得我必须在这里遗漏一些明显的东西,因为关于堆栈溢出的所有建议都表明只需将数据添加到DataTable并调用draw()就应该更新表。表DOES的控制器似乎更新以反映新数据,但图表本身不会。

如果我在调用drawChart()函数时立即加载数据,那么图表就会完美显示。同样,如果我没有显示空图表,但只有在数据加载回调函数中加载数据后才调用draw(),那么图表会正确显示。然而,当图表突然出现在页面上时,这看起来不太好。

HTML:

<body>
<h1>A nice chart showing user data.</h1>
<p>Simply insert a username into the text box and click get user data.</p>
<div class="usernameInputDiv">
    <form id="usernameForm1">
        Username: <input id="usernameTextBox" type="text" name="username">
    </form>
    <div class="button">
        <button class="btn">Get User Data</button>
    </div>
</div>
<div id="dashboard_div" style="width: 600px; height: 350px;">
    <div id="dashboardChart_div" style="width: 600px; height: 300px;">
    </div>

    <div id="rangeSlider_div" style="width: 600px; height: 50px;">
    </div>
 </div>
</body>

和javascript代码:

$(document).ready(function () {
    google.load("visualization", "1", {packages:["corechart", "controls"], "callback" : drawChart});
});


//Draws a scatter chart
function drawChart() {
    //Column names for adding data
    var columnNames = ["time","bytesInAvg","bytesOutAvg","bytesInMax","bytesOutMax"];

    //initialise a data structure to store the data
    var data = new google.visualization.DataTable();
    data.addColumn('datetime', 'Date');
    data.addColumn('number', 'bytesInAvg');
    data.addColumn('number', 'bytesOutAvg');
    data.addColumn('number', 'bytesInMax');
    data.addColumn('number', 'bytesOutMax');

    //Create a dashboard
    //Dashboards are used to group one (or more) graphs along with the controls for that graph
    var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard_div'));

    var options = {
        title: 'Data Sent/Received Per Minute (bytes)',
        hAxis: {title: 'Time'},
        vAxis: {title: 'Data Sent/Received (bytes)'},
        legend: '' //sets the legend to be displayed, use None for no legend
    };

    //Create chart for dashboard
    var dashboardChart = new google.visualization.ChartWrapper({
        'chartType': 'ScatterChart',
        'containerId': 'dashboardChart_div',
        'options': options
    });

    //Create controller for chart
    var dateRangeSlider = new google.visualization.ControlWrapper({
        'controlType': 'ChartRangeFilter',
        'containerId': 'rangeSlider_div',
        'options': {
          'filterColumnLabel': 'Date'
        }
    });

    //bind the chart and controller together in the dashboard
    dashboard.bind(dateRangeSlider, dashboardChart);

    //No data is loaded, so just show a blank chart for now so that it occupies the space
    //and is obvious to the user.
    updateDisplay(data,dashboard);

    //This is used to get and load data from a remote service
    $('.btn').click(function() {
        console.log("Received button press event");
        getTestData(data, dashboard, columnNames);
    });

    function updateDisplay(data, dashboard){
        //get the range of the data (just use col 1 for now)
        var yRange = data.getColumnRange(1);
        var xRange = data.getColumnRange(0);

        //Update chart axes. I would like this to be done automatically,
        //but it isn't, so for now I do it by hand.
        dashboardChart.setOption('vAxis.maxValue', yRange.max);
        dashboardChart.setOption('vAxis.minValue', yRange.min);

        dashboardChart.setOption('hAxis.maxValue', xRange.max);
        dashboardChart.setOption('hAxis.minValue', xRange.min);

        //update the display
        dashboard.draw(data);
    }

    //Test function simulating querying a server (using setTimeout to simulate delay)
    //and loading the data into a DataTable
    function getTestData(data, dashboard, columnNames){
        setTimeout(function() {
            var jsonObject = [
            {time:"2014-09-25T01:17:00.000Z", "bytesInAvg":713, "bytesOutAvg":1751, "bytesInMax":6916, "bytesOutMax":18947},
            {time:"2014-09-25T01:18:00.000Z", "bytesInAvg":146, "bytesOutAvg":328, "bytesInMax":810, "bytesOutMax":2877},
            {time:"2014-09-25T01:19:00.000Z", "bytesInAvg":44, "bytesOutAvg":73, "bytesInMax":122, "bytesOutMax":196},
            {"time":"2014-09-25T01:20:00.000Z", "bytesInAvg":41, "bytesOutAvg":69, "bytesInMax":122, "bytesOutMax":196},
        ];

        addResultToDataTable(data,jsonObject,columnNames);
        updateDisplay(data, dashboard);
        }, 2000);

    }//getTestData

    function addResultToDataTable(data, result, columnNames)
    {
      for ( var i = 0; i < result.length; i++)
      {
          data.addRow([ new Date(result[i]['time']), result[i][columnNames[1]], result[i][columnNames[2]], result[i][columnNames[3]], result[i][columnNames[4]] ]);
      }
    }//addResultsToDataTable

}//drawChart()

我已经包含了最低工作示例at jsfiddle here。任何人都可以找出图表无法正确更新的原因吗?

感谢。

2 个答案:

答案 0 :(得分:0)

不确定原因,但是dateRangeControl发生了错误,所以即使数据存在,也会按范围进行过滤而不显示。您可以使用以下方式检查:

dashboard.draw(data);

console.log(dateRangeSlider.getState()) // after update, shows same date for start and end(year 1969)

因此,快速解决方法是为您的数据设置有效范围:

dashboard.draw(data);

dateRangeSlider.setState({end:new Date(), start:new Date(new Date().setMonth(new Date().getMonth()-1))})

完全小提琴:http://jsfiddle.net/uf5wocx9/17/

答案 1 :(得分:0)

显然,一旦最初使用dashboard.draw(数据)绘制了空图形,随后应该在图形(ChartWrapper)本身上执行更新。因此,不应调用dashboard.draw(data),而应直接调用dashboardChart.draw()。这样做无需手动更改日期范围滑块。这种行为有点奇怪,在文档中并不明显。

文档here的第8部分:

  
      
  1. 绘制后的程序化更改
  2.         

    如果您需要以编程方式更改仪表板状态,则可以执行此操作   所以直接在ControlWrapper和ChartWrapper上操作   属于它的实例。经验法则是执行任何操作   直接在特定的ControlWrapper(或   ChartWrapper)实例:例如,更改控件选项或状态   分别通过setOption()和setState()调用它的draw()   之后的方法。然后仪表板将更新以匹配   要求更改。