smartGWT and FusionCharts
In the previous post we added support for login security to Serendipity. In this post, we're going to add support for interactive charting to Serendipity.
In this post, we'll:
- Identify some options
- Install FusionCharts
- Implement support for FusionCharts
- Test the application in development mode
Note: You can download the sample application from the CRMdipity (Se-r-en-dipity) project's download page.
1. Identify some options
There are several products that we could leverage in order to add support for interactive charting to Serendipity. For example:
- Axiis: A data visualisation framework.
- flot: A pure Javascript plotting library for jQuery.
- amCharts: A set of Flash and JavaScript charts.
- JFreeChart: A Java charting library.
You might also like to take a look at jgraph, yFiles and Tom Sawyer Software. However, in this post we're going to look at FusionCharts.
2. Install FusionCharts
Download and then unzip FusionCharts. I downloaded:
- FusionChartsFree.zip - Version 2.2 of FusionCharts Free
Copy the .swf files from the FusionChartsFree/Charts directory into the project's war/charts/fusioncharts/flash directory. Copy the .xml files from the FusionChartsFree/Gallery/Data directory into the project's war/charts/fusioncharts/data directory and copy the FusionCharts.js file from the FusionChartsFree/JSClass directory into the project's war/charts/fusioncharts/javascript directory.
3. Implement support for FusionCharts
While including JavaScript in your Java code is very easy with JSNI, sometimes you just want to include a JavaScript file. The easiest way to do this is to use a <script> tag in your module's gwt.xml file. While you can link to scripts directly from host pages, doing so can be problematic — modules cannot be easily distributed and reused if they depend on an external JavaScript file.
Serendipity's updated module definition file:
... <!-- Other module inherits --> <inherits name="com.gwtplatform.mvp.Mvp" /> <inherits name="com.gwtplatform.dispatch.Dispatch" /> <!-- begin FusionCharts include files --> <inherits name="com.smartgwt.SmartGwtPluginBridges" /> <script src="../charts/fusioncharts/javascript/FusionCharts.js"></script> <!-- end FusionCharts include files --> <inherits name="com.smartgwt.SmartGwtNoTheme" /> <inherits name="com.smartclient.theme.enterpriseblue.EnterpriseBlue" /> <inherits name="com.smartclient.theme.enterpriseblue.EnterpriseBlueResources" /> ...
As well as including the FusionCharts.js file we also need to inherit smartGWT's PluginBridges module. Now we can implement a simple wrapper class by taking advantage of smartGWT's Flashlet widget.
The FusionChart class:
import java.util.HashMap;
import com.smartgwt.client.widgets.plugins.Flashlet;
public class FusionChart extends Flashlet {
private static int count = 0;
private String swfId;
public FusionChart(String src, String width, String height, String dataUrl) {
super();
setCodeBase("http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0");
setClassID("clsid:d27cdb6e-ae6d-11cf-96b8-444553540000");
setPluginsPage("http://www.macromedia.com/go/getflashplayer");
swfId = "fusionChartId_" + count;
++count;
setID(swfId);
setName(swfId);
setSrc("charts/fusioncharts/flash/" + src);
setSize(width, height);
HashMap<String, String> hashMap = new HashMap<String, String>();
hashMap.put("id", swfId);
hashMap.put("flashvars", "&id=" + swfId + "&chartWidth=" + width + "&chartHeight=" + height +
"®isterWithJS=1" + "&debugMode=0" + "&dataURL=" + "charts/fusioncharts/data/" + dataUrl);
// hashMap.put("allowscriptaccess", "always");
// hashMap.put("bgcolor", "#ffffff");
// hashMap.put("quality", "high");
// If you embed the chart into your web page, and the page has layers such as drop-down menus or
// drop-down forms, and you want them appear above the chart, you need to add the following line
// to your code.
// hashMap.put("wmode", "opaque" );
setParams(hashMap);
// setCanSelectText(true);
}
}
The Dashboards View:
...
public class DashboardsView extends ViewWithUiHandlers<DashboardsUiHandlers> implements
DashboardsPresenter.MyView {
private static final String CONTEXT_AREA_WIDTH = "*";
private VLayout panel;
public DashboardsView() {
super();
panel = new VLayout();
panel.setStyleName("crm-ContextArea");
panel.setWidth(CONTEXT_AREA_WIDTH);
panel.setOverflow(Overflow.AUTO);
drawFusionCharts(panel);
}
private void drawFusionCharts(VLayout panel) {
FusionChart chart1 = new FusionChart("FCF_StackedColumn2D.swf", "400", "350", "StCol2D.xml");
FusionChart chart2 = new FusionChart("FCF_StackedBar2D.swf", "400", "350", "StBar2D.xml");
FusionChart chart3 = new FusionChart("FCF_Doughnut2D.swf", "400", "350", "Doughnut2D.xml");
FusionChart chart4 = new FusionChart("FCF_Funnel.swf", "350", "300", "Funnel.xml");
HLayout northLayout = new HLayout();
northLayout.setHeight("50%");
northLayout.setBackgroundColor("#FFFFFF");
northLayout.addMember(chart1);
northLayout.addMember(chart2);
HLayout southLayout = new HLayout();
southLayout.setHeight("50%");
southLayout.setBackgroundColor("#FFFFFF");
southLayout.addMember(chart3);
southLayout.addMember(chart4);
panel.addMember(northLayout);
panel.addMember(southLayout);
}
@Override
public Widget asWidget() {
return panel;
}
...
}
Take a look at the Dashboards View's constructor and you will notice that it calls the nested layout containers (the panels) setOverflow method. This ensures that when the browser window is resized, scroll bars will be drawn when they are needed.
The Dashboards Presenter:
...
public class DashboardsPresenter extends
Presenter<DashboardsPresenter.MyView, DashboardsPresenter.MyProxy> implements
DashboardsUiHandlers {
// don't forget to update SerendipityGinjector & ClientModule
@ProxyCodeSplit
@NameToken(NameTokens.dashboards)
@UseGatekeeper(LoggedInGatekeeper.class)
public interface MyProxy extends Proxy<DashboardsPresenter>, Place {
}
public interface MyView extends View, HasUiHandlers<DashboardsUiHandlers> {
void setResultSet();
}
@Inject
public DashboardsPresenter(EventBus eventBus, MyView view, MyProxy proxy) {
super(eventBus, view, proxy);
getView().setUiHandlers(this);
}
@Override
protected void onReveal() {
super.onReveal();
MainPagePresenter.getNavigationPaneHeader().setContextAreaHeaderLabelContents(
Serendipity.getConstants().dashboardsMenuItemName());
MainPagePresenter.getNavigationPane().selectRecord(NameTokens.dashboards);
}
@Override
protected void revealInParent() {
RevealContentEvent.fire(this, MainPagePresenter.TYPE_SetContextAreaContent, this);
}
}
4. Test the application in development mode
At this point, you should be able to compile Serendipity and launch it from within Eclipse.
The nested Dashboards presenter and view:

The nested Dashboards presenter and view:

Note: You can download the sample application from the CRMdipity (Se-r-en-dipity) project's download page.
- Tags:
