Soap Box On:
So, I admit it. I'm biased. I gave the presentation on Deferred Binding at the GWT Conference. It's hard explaining to people why this is such a powerful and needed feature in GWT. End users especially won't really be able to grok why, but I think Microsoft provides the best evidence in the form of Microsoft Volta, the GWT competitor from Microsoft that was supposed to blow GWT away.
Microsoft's test application certainly blows away my browser: http://labs.live.com/volta/samples/WordWorm.html
It made over 171 HTTP requests to load up all of its generated Javascript, over 2 megabytes of code, it took 20 seconds to startup, ran slow once it did, threw exceptions and sent me into the debugger, and when I looked at the code, I noticed that it had compatibility code for other browsers in my download, code chewing up space and network bandwidth that are useless to my Firefox instance.
I realize that this is a prototype, but come on. Microsoft should not be talking smack about GWT until they've got something to show that doesn't have so many easy to criticize flaws.
-Ray
Thursday, December 6, 2007
Editorial: Proof of why GWT Deferred Binding rocks
Posted by
Timepedia
at
5:02 PM
2
comments
Wednesday, November 28, 2007
Chronoscope in Swing and Servlet environments
After pushing out the open source release of Chronoscope, I finally went back to work on Timelord, which is our all-purpose GWT application for exploring our time series database, data mining, annotating visualizations, and tons more. Hopefully I can get it patched up to show something at the Pearson GWT Conference
Anyway, when data mining, Timelord shows icons to the user of interesting patterns which are server-side generated Chronoscope charts. The intense refactoring for the open source release broke the server-side implementation, so I spent most of yesterday and today, re-merging in and fixing the Java2D Canvas implementation layer.
I just finished getting a prototype up and running, and decided to put up a demo of Chronoscope running as an Applet (it's alittle beefy to download at the moment, I was able to pack200 it down to 120kbytes, but haven't gotten the webserver reconfigured yet to serve pack200 files.) This brings to 4 the number of environments the Chronoscope codebase can exist in: Browser-based Javascript, Swing desktop applications and Applets, Servlet-generators, and the Google Android phone SDK.
After the GWT Conference, I'll push to get a Flash implementation done, in which case, you'll have the choice of generating charts via Canvas, Applet, Flash, or Server. That will leave only J2ME as the final target to crack.
I'll commit the Java2D layer after the conference and things settle down. We've been working on Timepedia slowly for years now, and I'm anxious to start showing some of the real site, so I want to get Chronoscope development stabilized soon. (code-freeze)
-Ray
Posted by
Timepedia
at
4:04 PM
0
comments
Saturday, November 24, 2007
Chronoscope responsiveness increased
Yesterday, we received reports of slowness in Chronoscope on low end PCs. Admittedly, we didn't do testing on any PCs from yesteryear, but we will do so in the future.
In any case, we made some changes to Chronoscope that should make it feel faster on low end PCs:
- Animation was uninterruptible and fixed at 8 frames. On a slower PC that takes longer than 300ms or so to render these frames, there is a distinct feeling of lag when you press a key. Animations in progress are now interruptible.
- Key frame interpolation was frame count based instead of wall clock based. Interpolation frames are now parameterized based on time, and maximum animation time is capped at 300ms. Faster computers just generate a higher framerate for smoother, less jumpy, rendering.
- Lowered the resolution of the dataset further when animating. Future versions will auto-adapt this to platform speed.
- The final 'full resolution' dataset used to be displayed, no matter what, after an animation sequence finished (between keypresses). Now, it is delayed a short time until the user stops navigating.
The changed version has been deployed to timepedia.org for testing, but not committed to the source code repository yet. Check it out and let us know if you still have performance problems.
The only known issue at the moment is that mouse dragging on some platforms is jerky and laggy. We are looking into fixing this next.
-Timepedia Team
Posted by
Timepedia
at
12:08 AM
2
comments
Tuesday, November 20, 2007
GWT and Android: A marriage made in heaven?
The Google Web Toolkit has many awesome advantages for developing AJAX applications: Reuse of your favorite toolchain features (IDE, codeassist, debugger, refactor, build, etc), as well as producing much more compact Javascript code than any JS compiler/obfuscator can ever hope for. But one feature that initially caught our eye was the ability to reuse code in multiple environments.
Chronoscope started as two separate projects. The first, a prototype server-side renderer for Timepedia using the very capable JFreeChart. The second, a pure-JS canvas version written to test the ability to do AJAX charts without Flash. The JFreeChart version then became the version which would be used for static chart icons, sparklines, fallback for older browsers, and export to PDF/SVG.
Immediately, we encountered the problem that the two code bases had different features, different rendering style, which required laborious coding to keep them matched as close as possible. Over time, as the feature sets evolved, it became harder and harder to keep the JS client charts and server-side charts in sync.
Then Google released GWT and it immediately offered a solution: Write one chart library, in Java, and deploy to Servlet, Applet, Browser JS, and maybe J2ME and Flash. It was an enormous promise, and we initially adopted GWT for this purpose without realizing the other tremendous benefits that GWT provides for developing large JS codebases.
Early on, we produced prototypes of GWT Chronoscope running in servlet and applet environments, but with the release of the Android SDK, the initial promise has been fulfilled: GWT code running in a mobile environment.
The following is a screencast demo showing Chronoscope, with no changes to the core codebase running in the Android SDK emulator natively (not in the web browser).
It required about 8 hours to get this working. Most of the time was spent finding the Android equivalents of Java2D calls, and writing 6 Java classes (the Chronoscope Canvas abstraction layered over Android Graphics API)
At this point, we've only touched the tip of the iceberg. Future enhancements in GWT may allow this portability to go even further, such as compiling to ActionScript.
If your attending the GWT Conference on December 3-6, feel free to track down Ray Cromwell or Shawn O'Connor for a live demo.
p.s. There are no ticks or axis labels being shown in the sceencast to maximize screen real estate as well as performance. Android SDK text rendering is a drag on performance at the moment.
Posted by
Timepedia
at
11:41 AM
5
comments
Tuesday, November 13, 2007
Chronoscope Released
Timepedia is happy to announce the first beta release of Chronoscope, our charting and visualization platform for Google Web Toolkit, as open source. Chronoscope provides several features for the AJAX developer:
- Canvas abstraction for drawing vector graphs
- Graph Style Sheets abstraction for configuring the look-and-feel of charts
- Scalable multiresolution rendering supporting up to tens of thousands of points
- Zoom and pan at interactive frame rates, from centuries to milliseconds
- Auto-ranging, auto-layout of chart axes and ticks.
- Auto-legend, and mini-chart Overview
- Add pushpin markers, domain and range markers, and overlays like Google Maps
- Bookmarkable chart state, works with Back button
- JS interopability. GWT API can be used by pure Javascript programmers
- Microformat support. Charts can be configured without programming.
- Server-side Font assistance. Render rotated text.
- Portable, Chronoscope is not tied to GWT, can be used to render from servlets, applets, or other environments.
You can see a demo of the chart in action on our demo site. WARNING: Chronoscope currently supports only Firefox, Safari, and Opera (with a few caveats) for the beta release. Internet Explorer is scheduled to be available soon through a Flash version.
Many of our readers have been eagerly awaiting the release, and we have been burning the midnight oil the last few weeks reorganizing, documenting, and cleaning up the code base for the public.
Chronoscope is free of charge, and is distributed under the LGPL. We hope that many people interested in charting and graphics within GWT will join the Chronoscope project at http://code.google.com/p/gwt-chronoscope and help us build an awesome visualization platform.
Timepedia has been working over the last two years on a search engine which indexes time-related quantitative data, and provides users tools to play with visualizing data, find interesting patterns, and communicating insights. We want to make Chronoscope the best visualization tool, but we need your help to make it better.
There are four ways you can help us:
1) Chronoscope contains a small unobstrustive credit "Powered by Timepedia Chronoscope" which can be switched off. If you use Chronoscope, and want to help us promote Chronoscope, you can choose to leave it switched on.
2) You can become active in contributing code to the project. See the project page.
3) You can choose to donate a small sum of money, whatever you deem appropriate.
4) If you are a commercial company, and interested in official technical support, we sell support licenses, as well as a non-LGPL licensed version. See http://timepedia.org/chronoscope/license if interested.
We thank everyone for their patience over the last month, and hope you think this project is as cool as we do.
For those interested in meeting in person to discuss GWT based visualization and vector graphics, Ray Cromwell will be presenting at the upcoming Voices that Matter: Google Web Toolkit conference. During Breakfast with the Speakers, or after the conference, feel free to hunt him down if you want to chat. For those who wish to register, you can use a code of "GW-CROM" during registration to get $100 off the registration price.
Posted by
Timepedia
at
2:09 PM
2
comments
Thursday, October 4, 2007
Errata for AccordionPanel
There was an issue with IE7 (and probably IE6) with the Accordion shown in the previous article. The problem is, IE7 doesn't treat an element with overflow: hidden, height: 0px as expected (by making it invisible), instead, it shows it in full.
This is fixed by forcing standards mode with the following declaration in your HTML:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
Posted by
Timepedia
at
3:22 PM
0
comments
Wednesday, October 3, 2007
Designing a really simple GWT Accordion control
Yesterday, we started implementing some neat context-sensitive information features to Timepedia's "Timelord" GWT application, which integrates Chronoscope, Everett, and several other backend services, and I found myself in great need of an Accordion-like control.
Now, there are a great many accordion controls in third party JS libraries, many of them very slick and full featured, but I found that I didn't need so many features, and I'm trying to limit the number of pure-JS library wrappers I use in GWT because you lose alot of the benefits of the GWT Compiler when you wrap external JS libraries.
How hard could it be to cook up one in GWT? It turns out, not very hard it all.
What I want is a VerticalPanel or HorizontalPanel with the ability to open/close the nested widgets, preferably in a cool animated style. That means, we'll create either an Vertical or Horizontal Panel, store it in a Composite, and use even-numbered widget positions to store a Label, which when clicked, will expand odd-numbered widget positions from 0 to their desired width or height. We'll also simultaneously close any currently expanded widgets, back down to zero width/height. The only trick is to figure out what expanded width/height of a widget is.
First, let's create a Composite to house a Vertical or Horizontal Panel.
public class AccordionPanel extends Composite {
private Panel aPanel;
private String animField;
private String animBounds;
final private static int NUM_FRAMES = 8;
private Widget currentlyExpanded = null;
private Label currentlyExpandedLabel = null;
public AccordionPanel(boolean horizontal) {
if (horizontal) {
aPanel = new HorizontalPanel();
animField = "width";
animBounds = "scrollWidth";
} else {
aPanel = new VerticalPanel();
animField = "height";
animBounds = "scrollHeight";
}
initWidget(aPanel);
setStylePrimaryName("accordion");
}
public AccordionPanel() {
this(false);
}
I don't really need a horizontal accordion, but I threw in support for it (untested) just in case. Here, if we are using a Vertical accordion, we are animating the height field, and the desired expansion size is in the "scrollHeight" field.
Next, we need a method for adding new widgets to an accordion.
public void add(String label, final Widget content) {
final Label l = new Label(label);
l.setStylePrimaryName(getStylePrimaryName()+"-title");
final SimplePanel sp=new SimplePanel();
sp.setWidget(content);
l.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
expand(l, sp);
}
});
aPanel.add(l);
sp.setStylePrimaryName(getStylePrimaryName()+"-content");
DOM.setStyleAttribute(sp.getElement(), animField, "0px");
DOM.setStyleAttribute(sp.getElement(), "overflow", "hidden");
aPanel.add(sp);
}
Given a string label, and a widget, we do two things. First, we create a Label widget, and add a ClickListener to it. The ClickListener simple calls the expand() function with the label, and the content. Secondly, we wrap the content being added in a SimplePanel, to ensure we get a DIV around it which can be animated.
Finally, we add both the Label and the content wrapper to the underlying Vertical or Horizontal panel, set the primary style name of the label/content to be that of the AccordionPanel + "-title"/"-content", and then collapse the newly added component (height/width: 0, overflow: hidden)
Now all we have to do is implement the expand() function. We essentially want to run an animation loop, linearly interpolating between 0 and the max dimensions (for expansion) or the opposite for collapse.
Let's look at the implementation:
private void expand(final Label label, final Widget c) {
if(currentlyExpanded != null)
DOM.setStyleAttribute(currentlyExpanded.getElement(),
"overflow", "hidden");
Here we make sure that any previous expanded section is changed from overflow: auto back to overflow: hidden. Continuing further...
final Timer t = new Timer() {
int frame = 0;
public void run() {
if (currentlyExpanded != null) {
Widget w = currentlyExpanded;
Element elem = w.getElement();
int oSh = DOM.getIntAttribute(elem, animBounds);
DOM.setStyleAttribute(elem, animField, ""+(( NUM_FRAMES -
frame ) * oSh / NUM_FRAMES)+"px");
}
We create a Timer, whose run method will animate the collapse/expansion. We simultaneously collapse any currently expanded Widget and expand the target widget. All we have to do, is fetch the max dimensions from scrollHeight/scrollWidth, and then interpolate them down to zero for collapse.
if (currentlyExpanded != c) {
Widget w = c;
Element elem = w.getElement();
int oSh = DOM.getIntAttribute(elem, animBounds);
DOM.setStyleAttribute(elem, animField, ""+
(frame * oSh / NUM_FRAMES)+"px");
}
frame++;
Likewise for expansion, we simply interpolate from 0 to the maximum dimensions. Finally, we increment the frame, and we take care not to try and collapse and expand the same widget at the same time.
if (frame <= NUM_FRAMES) {
schedule(10);
} else {
if(currentlyExpanded != null) {
currentlyExpanded.removeStyleDependentName("selected");
currentlyExpandedLabel.removeStyleDependentName("selected");
}
c.addStyleDependentName("selected");
if(currentlyExpanded != c) {
currentlyExpanded = c;
currentlyExpandedLabel = label;
currentlyExpandedLabel.addStyleDependentName("selected");
Element elem = c.getElement();
DOM.setStyleAttribute(elem, "overflow", "auto");
DOM.setStyleAttribute(elem, animField, "auto");
} else {
currentlyExpanded = null;
}
}
Finally, we keep rescheduling our timer as long as we haven't reached our maximum number of frames. To finish, we add a final bit of polish, by adding a "selected" CSS class to the Label which is currently expanded. We also change the width/height and overflow fields back to auto.
}
};
t.schedule(10);
The last lines of the expand() function simply kick off our timer.
Here is the simple GWT Module to test
public class AccordionDemo implements EntryPoint {
/**
* This is the entry point method.
*/
public void onModuleLoad() {
AccordionPanel ap=new AccordionPanel();
AccordionPanel ap2=new AccordionPanel();
ap.add("Label 1", new HTML("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nam luctus urna vitae urna. Sed nisl. Praesent nisi nulla, malesuada quis, bibendum quis, egestas nec, pede. Donec ipsum. Duis nulla nisi, tristique eget, fermentum et, gravida non, lorem. Praesent mollis, arcu sed suscipit venenatis, velit erat sollicitudin quam, eget vestibulum odio enim nec libero. Praesent tellus. Vestibulum non justo. Aliquam semper. Nulla mauris ipsum, semper ut, dapibus quis, ultrices nec, est. Mauris nec nisl ut est posuere dignissim. Sed nec magna non purus eleifend mollis. Pellentesque orci. Integer sapien. Cras aliquam."));
ap.add("Label 2", new HTML("Ut tristique convallis nibh. Vestibulum eget nunc eget tellus varius sollicitudin. Vestibulum vestibulum ligula ac nulla. Nulla risus urna, euismod eget, accumsan vitae, posuere sit amet, eros. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean rhoncus pellentesque justo. Sed purus diam, bibendum ut, posuere a, feugiat sit amet, justo. Donec urna nulla, blandit in, gravida non, mattis a, turpis. Phasellus feugiat leo et justo. Maecenas quam nisl, consectetuer nec, auctor et, pharetra vel, tortor. Nunc justo nulla, tincidunt a, tempor id, viverra eget, sem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin sagittis nonummy urna. Aenean quis massa ac massa rutrum ornare."));
ap2.setStylePrimaryName("accordion2");
ap2.add("Nested Label 1", new HTML("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nam luctus urna vitae urna. Sed nisl. Praesent nisi nulla, malesuada quis, bibendum quis, egestas nec, pede. Donec ipsum. Duis nulla nisi, tristique eget, fermentum et, gravida non, lorem. Praesent mollis, arcu sed suscipit venenatis, velit erat sollicitudin quam, eget vestibulum odio enim nec libero. Praesent tellus. Vestibulum non justo. Aliquam semper. Nulla mauris ipsum, semper ut, dapibus quis, ultrices nec, est. Mauris nec nisl ut est posuere dignissim. Sed nec magna non purus eleifend mollis. Pellentesque orci. Integer sapien. Cras aliquam."));
ap2.add("Nested Label 2", new HTML("Ut tristique convallis nibh. Vestibulum eget nunc eget tellus varius sollicitudin. Vestibulum vestibulum ligula ac nulla. Nulla risus urna, euismod eget, accumsan vitae, posuere sit amet, eros. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean rhoncus pellentesque justo. Sed purus diam, bibendum ut, posuere a, feugiat sit amet, justo. Donec urna nulla, blandit in, gravida non, mattis a, turpis. Phasellus feugiat leo et justo. Maecenas quam nisl, consectetuer nec, auctor et, pharetra vel, tortor. Nunc justo nulla, tincidunt a, tempor id, viverra eget, sem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin sagittis nonummy urna. Aenean quis massa ac massa rutrum ornare."));
ap.add("Nested", ap2);
ap.add("Label 3", new HTML("Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..."));
RootPanel.get("slot1").add(ap);
}
}
and the CSS rules used.
.accordion-title {
background: #EFEFE3 url(gray-bg.gif) repeat-x scroll 0%;
border: 0pt none;
padding: 3px;
color: white;
font-weight: bold;
}
.accordion-title-selected {
background: coral none;
}
.accordion {
width: 300px;
}
.accordion2-title {
background: #EFEFE3 url(gray-bg.gif) repeat-x scroll 0%;
border: 0pt none;
padding: 3px;
padding-left: 10px;
color: white;
font-weight: bold;
}
.accordion2-title-selected {
background: blueviolet none;
}
.accordion2 {
width: 300px;
}
-Ray
p.s. caveats. First, scrollHeight/scrollWidth don't always work. See quirksmode. Secondly, there is a chance you could click another label while an expansion is in progress, so you'll need to add an "isAnimating" flag so that expand() will do nothing if another expansion is in progress. Third, you may want ease-in/ease-out in the animation, so instead of a linear interpolation, drop in your favorite easein/out function (sine, 2x^3-3x^2, etc)
Posted by
Timepedia
at
2:04 PM
4
comments