Thursday, June 25, 2009

Flex Chart inside GWT Page


Hello All, Today i want to talk about getting GWT to Work with Flex Charts.

We are going to tackle this from two sides. We will first talk about creating simple Flex Chart and then we will embed that in to GWT module.

In order to create a simple Flex Chart you would be needing Flex Builder from Adobe. You can download latest trial version from here. Flex Builder is built on eclipse platform, so if you are comfortable with eclipse, you should feel comfortable with Flex Builder. When i evaluated it, it only took me an hour to get familiar with.

Once you have it up an running, Create new Flex Project from File-> New-> Flex Project.

This will create a sample .mxml file, this is basically where you code your flex Chart.

I am first going to spit the content for .mxml file and then our Gwt Module to access this chart.

Note : As my intention here is to talk about GWT and show how Flex Chart can be used with GWT. So i am not going to explain this code below in detail, Just Play closer attention to Highlighted code.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal" styleName="myApplication" xmlns:ns1="bridge.*">
<mx:Script>
<![CDATA[
import mx.collections.*;
<!-- [Bindable] basically is saying we are binding the variable below to some component. In our case its Column Chart -->
[Bindable]
public var stateArray:ArrayCollection;

public function initData():void {
stateArray=new ArrayCollection( [
{ Profit: getRandomUint(100), Expenses: getRandomUint(10) },
{ Profit: getRandomUint(100), Expenses: getRandomUint(10) },
{ Profit: getRandomUint(100), Expenses: getRandomUint(10) } ]);
}
private function getRandomUint(max:uint):uint {
return Math.round(Math.random() * max);
}

]]>
</mx:Script>
<!-- Define custom colors for use as plot point fills. -->
<mx:SolidColor id="sc1" color="blue" alpha=".3"/>
<mx:SolidColor id="sc2" color="red" alpha=".3"/>
<mx:SolidColor id="sc3" color="green" alpha=".3"/>


<!-- Define custom Strokes. -->
<mx:Stroke id="s1" color="blue" weight="1"/>
<mx:Stroke id="s2" color="red" weight="1"/>
<mx:Stroke id="s3" color="green" weight="1"/>

<mx:SeriesSlide
id="slideIn"
duration="1000"
direction="up"
/>
<mx:SeriesSlide
id="slideOut"
duration="1000"
direction="down"
/>
<mx:SeriesInterpolate
id="interpol"
duration="1000"
elementOffset="0"
minimumElementDuration="200"
/>

<mx:ApplicationControlBar dock="true">
<mx:Button label="Change Data"
click="initData();" />
</mx:ApplicationControlBar>

<mx:ColumnChart name="columnchart" x="73" y="55" id="columnchartid" width="519" height="211" dataProvider="{stateArray}">
<mx:series>
<mx:ColumnSeries displayName="Plot 1" yField="Profit" xField="Expenses" fill="{sc1}" stroke="{s1}" showDataEffect="{slideIn}"
hideDataEffect="{slideOut}"/>
</mx:series>
</mx:ColumnChart>
<ns1:FABridge/>
</mx:Application>

When you execute above code in flex builder from Run Menu, it will create bunch of files. Couple that we are interested are .mxml and .swf, copy them in to your GWT module that you are creating. Refer to my previous post on how to create a basic GWT Module.

Now Lets see what goes in to GWT Module.

In order to use Flex Charts, you would basically need to use gwt-fabrdge.jar, this internally depends on gwt2swf-0.6.0.jar, Add them to your GWT module Classpath.

Lets first list out package structure and then i will explain in detail.

com/gwtbasics/gwtflex/gwtFlash.gwt.xml
com/gwtbasics/gwtflex/public/flexChart.mxml
com/gwtbasics/gwtflex/public/flexChart.swf
com/gwtbasics/gwtflex/client/GwtFlexModule.java
war/flexCharts.html

First lets talk gwtFlash.gwt.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 1.7.0//EN" "http://google-web-toolkit.googlecode.com/svn/tags/1.7.0/distro-source/core/src/gwt-module.dtd">
<module rename-to='gwtflex'>
<inherits name='com.google.gwt.user.User' />
<inherits name="pl.rmalinowski.gwt2swf.GWT2SWF"/>
<inherits name='org.argunet.gwt.fabridge.FABridge' />

<!-- Specify the app entry point class. -->
<entry-point class='com.gwtbasics.gwtflex.client.GwtFlexModule'/>
</module>
Most important is that the module inherits two packages namely GWT2SWF and FABridge.

Next in list is GwtGlexModule.java
package com.gwtbasics.gwtflex.client;

import org.argunet.gwt.fabridge.client.SWFABridgeWidget;

import pl.rmalinowski.gwt2swf.client.ui.SWFSettings;
import pl.rmalinowski.gwt2swf.client.utils.PlayerVersion;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.VerticalPanel;

public class GwtFlexModule implements EntryPoint {
public void onModuleLoad() {
SWFSettings swfSettings = new SWFSettings();
swfSettings.setMinPlayerVersion(new PlayerVersion(9,0,124));
SWFABridgeWidget swfbridge = new SWFABridgeWidget("gwtflex/flexChart.swf", 800, 500, swfSettings, "sample");
swfbridge.setVisible(true);
VerticalPanel outer = new VerticalPanel();
outer.add(swfbridge);
RootPanel.get("flexChartWidget").add(outer);
}
}
All we need now is the html file to call this GWT module.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<style type="text/css">
h1 {
font-size: 2em;
font-weight: bold;
color: #777777;
margin: 40px 0px 70px;
text-align: center;
}
</style>
<title>Flex GWT Module Demo Starter Project</title>
<script type="text/javascript" language="javascript" src="gwtflex/gwtflex.nocache.js"></script>
</head>
<body>
<h1>Simple Column Chart from Flex</h1>
<div align=" center" id="statusLabel"></div>
<div align=" center" id="flexChartWidget"></div>
</body>
</html>

For this example you need to get gwtflex/gwtflex.nocache.js that gets created when you compile using GWT compiler.

If you are using Google Plugin for Eclipse, just right click on the project and run/debug as Web Application and you will see the result.
But if you have generated your application through webAppCreator, you can use ant build.xml to execute. Execute hosted
ant task to invoke your app in hosted mode.

I hope you were able to successfully used flex chart inside GWT Page and enjoyed the experience of it.

Please stay tuned to my blog for more advanced implementation of GWT Flex Integration. In next Blog i will talk about passing dynamic content to Flex Chart from GWT Application.

Friday, June 12, 2009

Google Maps Api With GWT


Today i am going to demonstrate how to use google maps Api with GWT.
To get your hands free, i am going to show a simple map with an address plotted on it.


On the left you are seeing the snapshot of what we are trying to achieve. It surely don't look pretty. My intention is concentrate more on its functionality and how it can be achieved.

Let us start writing code directly, If you already don't have the GWT environment setup, Please refer to my GWT Basics post on how to set up your GWT application.

I order for you to use google api, you need to have gwt-maps-1.0.4.jar(get it here) along with gwt-user.jar and gwt-dev-{OS}.jar (refer to my GWT Basics post for detail explanation on gwt-dev-{OS}.jar)

Now that you got the environment set up, shall we start coding? I will take that as Yes then.

Lets first list out the files we are going to create and then i will talk in detail about each one.

com/gwtbasics/gmaps/gmaps.gwt.xml
com/gwtbasics/gmaps/client/GMapsModule.java
war/WEB-INF/gmaps.html

I will first explian GMapsModule.java EntryPoint. Give a closer look a the highlighted code for better understanding.
package com.gwtbasics.gmaps.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.maps.client.InfoWindowContent;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.geocode.Geocoder;
import com.google.gwt.maps.client.geocode.LatLngCallback;
import com.google.gwt.maps.client.geom.LatLng;
import com.google.gwt.maps.client.overlay.Marker;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.VerticalPanel;

public class GMapsModule implements EntryPoint {

public void onModuleLoad() {
final MapWidget map = new MapWidget(LatLng.newInstance(0, 0), 12);
final Label statusLabel = new Label();

VerticalPanel outer = new VerticalPanel();
map.setDoubleClickZoom(true);
map.setDraggable(true);
outer.add(map);
map.setSize("500px", "300px");
map.setGoogleBarEnabled(true);

LatLngCallback callback = new LatLngCallback() {

public void onFailure() {
statusLabel.setText("Address was Not Found");
}

public void onSuccess(LatLng point) {
statusLabel.setText("Address was Found");
Marker marker = new Marker(point);
map.addOverlay(marker);
map.setCenter(point);
VerticalPanel panel = new VerticalPanel();
InfoWindowContent content = new InfoWindowContent(panel);
panel.add(new Label("Voila Google Found me !!!"));
map.getInfoWindow().open(marker, content);
}
};
Geocoder geocoder = new Geocoder();
geocoder.getLatLng("dallas downtown", callback);

RootPanel.get("statusLabel").add(statusLabel);
RootPanel.get("mapWidget").add(outer);

}

}



Now lets talk about highlighted code.

final MapWidget map = new MapWidget(LatLng.newInstance(0, 0), 12);
Here we are creating an instance to MapWidget which takes an instance LatLng instance and default zoom level. I just created LatLng with (0,0), As i dont know the latitude and longitude values for address i am looking.


LatLngCallback callback = new LatLngCallback() {

public void onFailure() {
statusLabel.setText("Address was Not Found");
}
public void onSuccess(LatLng point) {
------
------
------
}
What we are doing above is, creating an instance of LatLngCallback that will be passed as an input parameter for Geocoder class. We will have to implement onFailure and onSuccess handler methods. In our example if address is found, we will plot that location with a marker.



Geocoder geocoder= new Geocoder();
geocoder.getLatLng("dallas downtown", callback);
This is critical but simple, what we are doing above is creating an instance of Geocoder and calling getLatLng() method, which take two parameters. It takes the address you are trying to search as string and a LatLngCallback handler.
Behind the scenes at run time, google maps api will try to contact google servers to pharse latitude and longitude values of given address, if pharse was successfull it executes the onSuccess() method and if pharse has failed it executes onFailure() method.


Note that in order to use the Maps API in live, you need to apply for a Google Maps API key. But if you are running it on localhost you dont need that.


Let Talk about gmaps.gwt.xml , as you know its a GWT module configuration file. Here is how it looks

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 1.7.0//EN" "http://google-web-toolkit.googlecode.com/svn/tags/1.7.0/distro-source/core/src/gwt-module.dtd">
<module rename-to='gmaps'>
<inherits name="com.google.gwt.maps.GoogleMaps" />
<script src="http://maps.google.com/maps?gwt=1&file=api&v=2&sensor=false" />
<entry-point class='com.gwtbasics.gmaps.client.GMapsModule'/>
</module>
Place close attention at highlighted code.


<script src="http://maps.google.com/maps?gwt=1&file=api&v=2&sensor=false" />
You can see, we are not specifying any key here, as we are running this on localhost. If you run on server you need a key. You can replace ??? with key value
<script src="http://maps.google.com/maps?gwt=1&file=api&v=2&key=???" />
One Last bit of our module is the html file. I have to say, its layout looks simple and not fancy. I am just concentrating on the functionality. Here is the html file.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<style type="text/css">
h1 {
font-size: 2em;
font-weight: bold;
color: #777777;
margin: 40px 0px 70px;
text-align: center;
}
</style>
<title>SimpleMaps Module</title>

<!-- -->
<!-- This script loads your compiled module. -->
<!-- If you add any GWT meta tags, they must -->
<!-- be added before this line. -->
<!-- -->
<script type="text/javascript" language="javascript" src="gmaps/gmaps.nocache.js"></script>
</head>

<!-- -->
<!-- The body can have arbitrary html, or -->
<!-- you can leave the body empty if you want -->
<!-- to create a completely dynamic UI. -->
<!-- -->
<body>

<h1>SimpleMaps</h1>
<div align=" center" id="statusLabel"></div>
<div align=" center" id="mapWidget"></div>

</body>
</html>
For this example you need to get gmaps/gmaps.nocache.js that gets created when you compile using GWT compiler.


If you are using Google Plugin for Eclipse, just right click on the project and run/debug as Web Application and you will see the result.
But if you have generated your application through webAppCreator, you can use ant build.xml to execute. Execute hosted
ant task to invoke your app in hosted mode.

I hope you were able to successfully use Google Maps in your application and enjoyed the experience of it.

Please stay tuned to my blog for more advanced implementation of Google maps Api.