After intensive search for the right utility for the job, I finally gave in and solved the problem I was facing: How do you render asynchronously loaded data (RPC) in a Google Visualization for GWT chart which itself is loaded via the asynchronous AjaxLoader
doing the two requests in parallel?
Or, in other words: How can we make sure that chart rendering works regardless of whether chart data arrives before or after the Visualization library is loaded?
The two less restrictive (or; less ambitious) scenarios are pretty straightforward.
Easy scenario #1: Using static data
Without depending on RPC data using Visualization is straightforward. This is due to the fact that there is only one asynchronous request: loading the Visualization library. Therefore there is no risk that data will arrive before the Visualization library is loaded.
Sample code snippet:
public class MyViewImpl implements MyView {
private Panel main;
public MyViewImpl() {
this.main = new FlowPanel();
Runnable onVizLoaded = new Runnable() {
@Override
public void run() {
DataTable data = DataTable.create();
Options options = Options.create();
// Populate data and options based on static data here...
// Instantiate and attach new chart.
LineChart lineChart = new LineChart(data, options);
main.add(lineChart);
}
};
// Load Google Visualization asynchronously.
VisualizationUtils.loadVisualizationApi(onVizLoaded, LineChart.PACKAGE);
}
// View logic goes here...
}
The Visualization library is easily loaded and a LineChart
is created and rendered when loading is done. Consider this outline of the load characteristics:
Viz load: |---?---|
Chart data: |
Render: |--->
Easy scenario #2: Running requests in serial
It is possible to utilize the above snippet when loading chart data via RPC. However the following implies that chart data will not be fetched until the Visualization library is loaded and ready. You may be OK with this performance impact - I am not!
- Mainly because I have no control over the load time of the Visualization library and thus no control over the delay before fetching data
- I don't like my View to dictate application behavior. Application logic belongs in the Presenter.
Sample code snippet:
public class MyViewImpl implements MyView {
private Panel main;
public MyViewImpl() {
this.main = new FlowPanel();
Runnable onVizLoaded = new Runnable() {
@Override
public void run() {
// Make RPC call.
ClientFactory.getService().getData(new AsyncCallback<MyResult>() {
@Override
public void onSuccess(MyResult result) {
DataTable data = DataTable.create();
Options options = Options.create();
// Populate data from RPC result.
data.addColumn(ColumnType.DATE);
data.addRow();
data.setValue(0, 0, result.getDate());
// ... Etc.
// Set options.
options.setWidth(500);
// ... Etc.
// Instantiate and attach new chart.
LineChart lineChart = new LineChart(data, options);
main.add(lineChart);
}
@Override
public void onFailure(Throwable caught) {
// Handle RPC error.
}
});
}
};
// Load Google Visualization asynchronously.
VisualizationUtils.loadVisualizationApi(onVizLoaded, LineChart.PACKAGE);
}
// View logic goes here...
}
Load characteristics illustrates the problem:
Viz load: |---?---|
Chart data: |----~----|
Render: |--->
Desired scenario: Running in parallel
The desired scenario will have the following charateristics with the Visualization library loading faster than data:
Viz load: |---?---|
Chart data: |----~----|
Render: |--->
Or with data loading faster than the Visualization library:
Viz load: |---?---|
Chart data: |--~--|
Render: |--->
The question is: How?