GWT Google 异步数据可视化 (RPC)
GWT Google Visualization with asynchronous data (RPC)
在为这项工作寻找合适的实用程序之后,我终于屈服并解决了我面临的问题:你如何渲染异步加载的数据 (RPC) 在 Google Visualization for GWT chart which itself is loaded via the asynchronous AjaxLoader
中并行执行两个请求 ?
或者换句话说:无论图表数据是在加载可视化库之前还是之后到达,我们如何才能确保图表渲染正常?
这两个限制较少(或;不太雄心勃勃)的场景非常简单。
简单场景 #1:使用静态数据
不依赖于 RPC 数据,使用可视化非常简单。这是因为只有一个异步请求:加载可视化库。因此,不存在数据在加载可视化库之前到达的风险。
示例代码片段:
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...
}
可视化库很容易加载,加载完成后会创建和呈现 LineChart
。考虑负载特性的概述:
Viz load: |---?---|
Chart data: |
Render: |--->
简单场景 #2:运行 串行请求
在通过 RPC 加载图表数据时, 可以使用上述代码段。但是,以下内容暗示在加载并准备好可视化库之前不会获取图表数据。您可能对这种性能影响没有意见 - 我不是!
- 主要是因为我无法控制可视化库的加载时间,因此无法控制获取数据之前的延迟
- 我不喜欢我的视图决定应用程序行为。应用程序逻辑属于 Presenter。
示例代码片段:
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...
}
负载特征说明问题:
Viz load: |---?---|
Chart data: |----~----|
Render: |--->
期望的场景:运行并行
期望的场景将具有以下特征,可视化库加载速度快于数据:
Viz load: |---?---|
Chart data: |----~----|
Render: |--->
或者比可视化库更快的数据加载:
Viz load: |---?---|
Chart data: |--~--|
Render: |--->
问题是:如何?
以下策略将满足要求:
- 请求是 运行 并行
- 图表在两个请求完成后立即呈现
- 应用程序逻辑(RPC 调用)保留在 Presenter 中。
示例代码片段:Presenter
public class MyPresenter implements MyView.Presenter {
private MyView view;
// ... Constructor etc. goes here...
@Override
public void render() {
// Make RPC call immediately when Presenter should begin rendering.
ClientFactory.getService().getData(new AsyncCallback<MyResult>() {
@Override
public void onSuccess(MyResult result) {
// Pass data to view for rendering (when appropriate.)
view.render(result);
}
@Override
public void onFailure(Throwable caught) {
// Handle RPC error.
}
});
}
}
示例代码片段:ViewImpl
public class MyViewImpl implements MyView {
private Panel main;
private AsyncChart<LineChart> asyncLineChart;
public MyViewImpl() {
this.main = new FlowPanel();
// Runnable wrapper (see next snippet.)
this.asyncLineChart = new AsyncChart<LineChart>() {
@Override
public LineChart onAttach(DataTable data, Options options) {
// Instantiate and attach new chart.
LineChart lineChart = new LineChart(data, options);
main.add(lineChart);
return lineChart;
}
};
// Load Google Visualization asynchronously.
VisualizationUtils.loadVisualizationApi(this.asyncLineChart, LineChart.PACKAGE);
}
@Override
public void render(final MyResult result) { // Invoked from Presenter (see above snippet.)
// Schedule rendering to be invoked ASAP (but not before Visualization library is loaded.)
this.asyncLineChart.enqueueWriter(new AsyncChartWriter() {
@Override
public void onWrite(DataTable data, Options options) {
// Populate data from RPC result.
data.addColumn(ColumnType.DATE);
data.addRow();
data.setValue(0, 0, result.getDate());
// ... Etc.
// Set options.
options.setWidth(500);
// ... Etc.
}
});
}
}
现在该吃肉了!
示例代码片段:AsyncChart准备复制。
import com.google.gwt.visualization.client.DataTable;
import com.google.gwt.visualization.client.VisualizationUtils;
import com.google.gwt.visualization.client.visualizations.corechart.CoreChart;
import com.google.gwt.visualization.client.visualizations.corechart.Options;
/**
* Wrapping {@link Runnable} to use with the load methods of {@link VisualizationUtils}
* allowing a chart to be populated asynchronously (e.g., via RPC.)
*
* This wrapper handles the process of deferred attachment of the chart via the
* {@link #onAttach(DataTable, Options)} method.
*
* Chart data is set / updated by means of a {@link AsyncChartWriter} mutating the
* passed {@link DataTable} and {@link Options} instances.
*
* {@link AsyncChartWriter} can be reassigned (via {@link #enqueueWriter(AsyncChartWriter)})
* in order to redraw the chart.
*
* @param <T> The concrete chart type.
*/
public abstract class AsyncChart<T extends CoreChart> implements Runnable {
public interface AsyncChartWriter {
void onWrite(DataTable data, Options options);
}
private enum State {
NEW,
LOADED,
ATTACHED
}
private State state;
private T chart;
private AsyncChartWriter enqueuedWriter;
public AsyncChart() {
this.state = State.NEW;
}
public abstract T onAttach(DataTable data, Options options);
/**
* Enqueues a writer to populate or manipulate the chart. This will happen immediately
* if the visualization API is already loaded and will otherwise be deferred.
*
* @param writer The writer to enqueue.
*/
public void enqueueWriter(AsyncChartWriter writer) {
this.enqueuedWriter = writer;
processWriter();
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*
* Invoked when the visualization API has loaded.
*/
@Override
public void run() {
this.state = State.LOADED;
if (this.enqueuedWriter != null) {
processWriter();
}
}
private void processWriter() {
if (this.state == State.LOADED || this.state == State.ATTACHED) {
DataTable data = DataTable.create();
Options options = CoreChart.createOptions();
this.enqueuedWriter.onWrite(data, options);
if (this.state == State.LOADED) {
this.chart = onAttach(data, options); // Instantiate and attach.
this.state = State.ATTACHED;
} else {
this.chart.draw(data, options); // Redraw already attached chart.
}
this.enqueuedWriter = null;
}
// If state = NEW do nothing until run() is invoked (and state has changed to LOADED.)
}
}
享受您的并行负载。
在为这项工作寻找合适的实用程序之后,我终于屈服并解决了我面临的问题:你如何渲染异步加载的数据 (RPC) 在 Google Visualization for GWT chart which itself is loaded via the asynchronous AjaxLoader
中并行执行两个请求 ?
或者换句话说:无论图表数据是在加载可视化库之前还是之后到达,我们如何才能确保图表渲染正常?
这两个限制较少(或;不太雄心勃勃)的场景非常简单。
简单场景 #1:使用静态数据
不依赖于 RPC 数据,使用可视化非常简单。这是因为只有一个异步请求:加载可视化库。因此,不存在数据在加载可视化库之前到达的风险。
示例代码片段:
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...
}
可视化库很容易加载,加载完成后会创建和呈现 LineChart
。考虑负载特性的概述:
Viz load: |---?---|
Chart data: |
Render: |--->
简单场景 #2:运行 串行请求
在通过 RPC 加载图表数据时, 可以使用上述代码段。但是,以下内容暗示在加载并准备好可视化库之前不会获取图表数据。您可能对这种性能影响没有意见 - 我不是!
- 主要是因为我无法控制可视化库的加载时间,因此无法控制获取数据之前的延迟
- 我不喜欢我的视图决定应用程序行为。应用程序逻辑属于 Presenter。
示例代码片段:
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...
}
负载特征说明问题:
Viz load: |---?---|
Chart data: |----~----|
Render: |--->
期望的场景:运行并行
期望的场景将具有以下特征,可视化库加载速度快于数据:
Viz load: |---?---|
Chart data: |----~----|
Render: |--->
或者比可视化库更快的数据加载:
Viz load: |---?---|
Chart data: |--~--|
Render: |--->
问题是:如何?
以下策略将满足要求:
- 请求是 运行 并行
- 图表在两个请求完成后立即呈现
- 应用程序逻辑(RPC 调用)保留在 Presenter 中。
示例代码片段:Presenter
public class MyPresenter implements MyView.Presenter {
private MyView view;
// ... Constructor etc. goes here...
@Override
public void render() {
// Make RPC call immediately when Presenter should begin rendering.
ClientFactory.getService().getData(new AsyncCallback<MyResult>() {
@Override
public void onSuccess(MyResult result) {
// Pass data to view for rendering (when appropriate.)
view.render(result);
}
@Override
public void onFailure(Throwable caught) {
// Handle RPC error.
}
});
}
}
示例代码片段:ViewImpl
public class MyViewImpl implements MyView {
private Panel main;
private AsyncChart<LineChart> asyncLineChart;
public MyViewImpl() {
this.main = new FlowPanel();
// Runnable wrapper (see next snippet.)
this.asyncLineChart = new AsyncChart<LineChart>() {
@Override
public LineChart onAttach(DataTable data, Options options) {
// Instantiate and attach new chart.
LineChart lineChart = new LineChart(data, options);
main.add(lineChart);
return lineChart;
}
};
// Load Google Visualization asynchronously.
VisualizationUtils.loadVisualizationApi(this.asyncLineChart, LineChart.PACKAGE);
}
@Override
public void render(final MyResult result) { // Invoked from Presenter (see above snippet.)
// Schedule rendering to be invoked ASAP (but not before Visualization library is loaded.)
this.asyncLineChart.enqueueWriter(new AsyncChartWriter() {
@Override
public void onWrite(DataTable data, Options options) {
// Populate data from RPC result.
data.addColumn(ColumnType.DATE);
data.addRow();
data.setValue(0, 0, result.getDate());
// ... Etc.
// Set options.
options.setWidth(500);
// ... Etc.
}
});
}
}
现在该吃肉了!
示例代码片段:AsyncChart准备复制。
import com.google.gwt.visualization.client.DataTable;
import com.google.gwt.visualization.client.VisualizationUtils;
import com.google.gwt.visualization.client.visualizations.corechart.CoreChart;
import com.google.gwt.visualization.client.visualizations.corechart.Options;
/**
* Wrapping {@link Runnable} to use with the load methods of {@link VisualizationUtils}
* allowing a chart to be populated asynchronously (e.g., via RPC.)
*
* This wrapper handles the process of deferred attachment of the chart via the
* {@link #onAttach(DataTable, Options)} method.
*
* Chart data is set / updated by means of a {@link AsyncChartWriter} mutating the
* passed {@link DataTable} and {@link Options} instances.
*
* {@link AsyncChartWriter} can be reassigned (via {@link #enqueueWriter(AsyncChartWriter)})
* in order to redraw the chart.
*
* @param <T> The concrete chart type.
*/
public abstract class AsyncChart<T extends CoreChart> implements Runnable {
public interface AsyncChartWriter {
void onWrite(DataTable data, Options options);
}
private enum State {
NEW,
LOADED,
ATTACHED
}
private State state;
private T chart;
private AsyncChartWriter enqueuedWriter;
public AsyncChart() {
this.state = State.NEW;
}
public abstract T onAttach(DataTable data, Options options);
/**
* Enqueues a writer to populate or manipulate the chart. This will happen immediately
* if the visualization API is already loaded and will otherwise be deferred.
*
* @param writer The writer to enqueue.
*/
public void enqueueWriter(AsyncChartWriter writer) {
this.enqueuedWriter = writer;
processWriter();
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*
* Invoked when the visualization API has loaded.
*/
@Override
public void run() {
this.state = State.LOADED;
if (this.enqueuedWriter != null) {
processWriter();
}
}
private void processWriter() {
if (this.state == State.LOADED || this.state == State.ATTACHED) {
DataTable data = DataTable.create();
Options options = CoreChart.createOptions();
this.enqueuedWriter.onWrite(data, options);
if (this.state == State.LOADED) {
this.chart = onAttach(data, options); // Instantiate and attach.
this.state = State.ATTACHED;
} else {
this.chart.draw(data, options); // Redraw already attached chart.
}
this.enqueuedWriter = null;
}
// If state = NEW do nothing until run() is invoked (and state has changed to LOADED.)
}
}
享受您的并行负载。