Chronoscope is a charting platform, currently in alpha, for GWT
focused on time series charts, and providing a "Google Maps"-like
experience of soaring around the dataset, as well as providing maps-
style API for mashups, like adding overlays, pushpin markers, etc. You
can see an indepth preview at http://www.timepedia.org, bugs and all.
(It only works on Firefox at the moment. It also works in Webkit/
Hosted Mode, but not in Safari 2.0.4 without rendering errors. Camino
has some issues too.)
What's interesting is how we arrived at GWT. Our requirements for
Chronoscope demand that it run on the server as well as the client and
mobile devices.
Originally, Chronoscope was done with JFreeGraph (heavily modified)
and a parallel hand-crafted Javascript version, but maintaining a
separate Java and Javascript code base turned out to be intractable.
GWT allowed us to unify Java Graphics2D rendering, client-side
Javascript, and mobile platforms into a single code base, and now
porting to another rendering platform (e.g. Flash, Silverlight, etc)
takes only a few extra classes. I think this is a real success story
for GWT, atleast from our point of view -- it was invaluable.
The second thing we are releasing today is GWT Exporter. We wanted
Chronoscope to be scriptable from ordinary Javascript, so we put alot
of effort into generating bridge methods between ordinary JS class
method idioms and JSNI methods.
For example, stuff like $wnd.MyClass.prototype.foo = function()
{ this.instance.@jsniReference::foo(..)(..); }
As our platform grew, the manual bridging code became a pain to
maintain, so I decided to see what it would take to get GWT to do the
work automatically. I was pleasantly surprised that it wasn't that
hard to achieve by creating a custom generator (albeit, better
documentation would be nice) After a day of hacking, I came up with
the following solution:
Given a class like:
public class MyClass {
public static final int FIELD_1=1;
public static final int FIELD_2=20;
private int origin;
public MyClass(int origin) {
this.origin=origin;
}
public int add(int amt) {
return origin+amt;
}
}
one can export a Javascript API that looks like this:
var myclass = new mypackage.MyClass(10);
alert(myclass.add(mypackage.MyClass.FIELD_2));
by doing the following annotations:
/**
* this line overrides the default package which may be too long/deep
* @gwt.exportPackage mypackage
*/
public class MyClass implements Exportable {
/**
* @gwt.export
*/
public static final int FIELD_1=1;
/**
* @gwt.export
*/
public static final int FIELD_2=20;
private int origin;
public MyClass(int origin) {
this.origin=origin;
}
/**
* @gwt.exportConstructor
*/
public static MyClass createConstructor(int origin) {
return new MyClass(origin);
}
/**
* @gwt.export
*/
public int add(int amt) {
return origin+amt;
}
}
and then in your entry point method:
Exporter exporter = (Exporter)GWT.create(MyClass.class);
exporter.export(); // this line will create a bunch of bridge method/
fields with $wnd scope
The @gwt.export annotation signals to the generator that a bridge
method should be created. @gwt.exportConstructor tells it that the
static factory method is to be used for the JS constructor to obtain
an instance.
I will be distributing the open-source code on http://code.google.com/p/gwt-exporter/
probably in the next day or so.
For those interested in chatting about GWT charting and vector
graphics, look for the guys in the black "Timepedia" t-shirts at the
San Jose/Mountain View Google Developer Day.
-Ray
And I would add to that, 4 or 5 uses cases which cannot be solved by composition (which was done for ImageBundle) or for which such composition would tend to be ugly/unwieldy.