gwt: canvas gwt html5 performance visualization web application
leave a comment
Improving Canvas Performance
1. Timeout instead of Scheduler
Surprisingly, using com.google.gwt.user.client.Timer seems much faster then relying on com.google.gwt.core.client.Scheduler. I did not yet evaluate the differences in detail but the lower CPU workload speaks for itself.
2. AnimationScheduler
I am not really sure if this helps a lot, but you will find a lot of online documentation explaining that you should use this:
com.google.gwt.animation.client.AnimationScheduler.get(). requestAnimationFrame(callback, element);. The element parameter is optional but said to improve performance as the browser can decide when to render optimally.
So whenever your timer kicks in, and you are ready to render the results, use the AnimationScheduler instead of calling your rendering routines right away. It will only take very few milliseconds (depending on the users screen frame rate—which is 60 Hz or more usually) for the callback to return to your code.
3. Caching
This parts requires much more effort and depends on your software architecture and requirements. The basic idea is not to redraw things that did not change. To do so we can draw each item on a hidden canvas once and then reuse this rendering during every drawing cycle.
As the process is a bit more complicated, I will dedicate it a separate post—comming soon!
4. Save on effects
Yes, effects is what the canvas is all about, but something like a shadow can cost quite some CPU power. So if you run into problems check if some of the effects can be achieved cheaper or even be removed.
gwt java: ant code code reuse eclipse example fix gwt library tutorial web application
leave a comment
Multiple Projects and GWT
When working on several large scale projects (in Eclipse), it’s convenient and of course more efficient to share and reuse code via common libraries. While those are in an early stage they need to be changed a lot and therefore it’s handy to link projects in instead of creating new jars each time the library has been updated.
Unfortunately, this standard approach for Java development in Eclipse does not work that straight forward as with plain old Java projects, it requires three steps in total:
- Link the library project to all relevant projects (“Project Preferences” -> “Java Build Path” -> “Projects” -> “Add…”)
- Then, add the client-side code of the library (by adding it as a module.) Therefore, edit the gwt.xml of your application and add for example
<inherits name="net.svenbuschbeck.gwt.lib.SuperLib "/>where SuperLib is the file name of the gwt.xml file in you library project and before that is the package it lies in. - Add the code to the project by linking a source folder. Unfortunately, this is required if you do not want to write an Ant script to compile your application. (If you prefer Ant check this out) I don’t like the idea of using such a script because if you forget to run it each time you make changes, you will end up in confusion—let’s go for the convenient, automatic way then.
- Add a folder to your application project; open the “advanced” section in the folder creation dialog, select “Link to alternate location” and pick the source folder (usually “src”) of your library project. (Hint: if you work within a team using a versioning system, you can create a variable for that folder and use this instead. This way, each of your colleagues can put the library project in a different folder and accommodate for that by adjusting the variable
) - Right click the folder, “Build Path” -> “Use as Source Folder”. Done.
- Add a folder to your application project; open the “advanced” section in the folder creation dialog, select “Link to alternate location” and pick the source folder (usually “src”) of your library project. (Hint: if you work within a team using a versioning system, you can create a variable for that folder and use this instead. This way, each of your colleagues can put the library project in a different folder and accommodate for that by adjusting the variable
Surprisingly, the GWT plugin for Eclipse does not honor the project linking, thus all the references need to be made explicit or you will end up with lots of the following: ClassNotFoundException.
gwt java javascript: bug code error fix gwt Java Javascript web application
leave a comment
“An invalid or illegal string was specified” Exception in GWT
While working with canvas (drawing stuff on it) in GWT, suddenly and in a seemingly unpredictable manner I got following error message now and then from within the GWT framework code:
com.google.gwt.core.client.JavaScriptException: (NS_ERROR_DOM_SYNTAX_ERR): An invalid or illegal string was specified;
Again, GWT tricked me into thinking I am writing Java code and made me forget about that it is going to be compiled into Javascript. And because of the latter, a division by zero does not throw an DevisionByZeroException, no, it returns NaN even for native data types (there is no differentiation between double and Double in Javascript — there is only the object-version of double, which can be of value Double.NaN).
But also GWT was not prepared to handle Double.NaN. When calling canvas.getContext().drawImage(image,x,y) and one of x and y or both were Double.NaN I got the error message shown above. If you got the same… you know what to do now: check all devisions in your code for potential devisions by zero!!
Sorting Lists in GWT
Quick one:
Lists.sort(list, comparator) is not implemented in the GAE JVM.
But, as a replacement/alternative, Collections.sort(list, comparator) is.
How to Execute Code When the GWT Application Is Going Down
My goal was to store the UI state of my application just before it gets terminated to be able to restore it next time the way the user left it the other day.
I tried to add an addAttachHandler to the RootPanel to get informed about the root panel getting detached from the DOM so that I can finalize my application. Surprisingly, that does not work in Chrome (tested Chrome and Firefox only).
But besides that this sounds like a bug to me, I found the “proper” way of doing things before the application ends:
Window.addWindowClosingHandler(new Window.ClosingHandler() {
@Override public void onWindowClosing(ClosingEvent event) { ... }
});
In the end, I think something like Document.addUnloadHandler would be more suggestive… closing the window or reloading a page is both exiting the application by unloading the DOM — not closing the window.
Disable an Anchor in GWT
Unexpectedly, calling setEnabled(false) does not prevent a link/anchor from being clicked. That means, the click events still get triggered.
The reason is more or less a bug in GWT as it updates the list of events that are going to be triggered only at the moment when it gets attached to the DOM (Btw, in GWT, this process is called to sink and to unsink events, where the former enables a specific event to be triggered and the latter disables it).
I found a workaround by creating my own Anchor class and forcing the underlying GWT Anchor to update the list of events to be sunk.
...
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Event;
public class Anchor extends com.google.gwt.user.client.ui.Anchor {
@Override public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
if (isAttached()) {
onDetach();
if (enabled) {
sinkEvents(Event.ONCLICK);
} else {
unsinkEvents(Event.ONCLICK);
}
onAttach();
}
}
@Override protected void onLoad() {
super.onLoad();
if (isEnabled()) {
sinkEvents(Event.ONCLICK);
} else {
unsinkEvents(Event.ONCLICK);
}
}
}
Note the onLoad method, it sets up the state when the widget gets attached to the DOM the first time. It is required because setEnabled() could have been called before the anchor got attached.
If you encountered the same issue, please vote for this bug report.
Disable Context Menu in GWT
To make use of the right mouse button, it is necessary to disable the native browser context menu (the popup menu appearing on right click). This can be achieved like this:
RootLayoutPanel.get().addDomHandler(new ContextMenuHandler() {
@Override public void onContextMenu(ContextMenuEvent event) {
event.preventDefault();
event.stopPropagation();
}
}, ContextMenuEvent.getType());
Same should work for RootPanel.
After that, it is possible to make use of the right mouse button for example like this:
someWidget.addDomHandler(new MouseMoveHandler() {
@Override public void onMouseMove(MouseMoveEvent event) {
if (event.getNativeButton() == NativeEvent.BUTTON_RIGHT) {
...
GWT Error Message “Asked for attribute parser of no type”
Example:
public boolean isCollapsed() {
return panel.isVisible();
}
public void setCollapsed() {
panel.setVisible(false);
}
Seen it? Despite the complicated and cryptic error message, the mistake is rather simple: the setter method is missing a parameter, i.e. “public void setCollapsed(boolean collapsed) {“.
gwt jobs: GAE gwt tutorial virtual machine web application website
leave a comment
Testing GWT Application in Virtual Machine
I am developing on a Mac, but to test my GWT applications for cross-browser compatibility in Internet Explorer I need to use Windows, thus I got Windows 7 installed using Parallels. Just by the way, to be able to test in different Internet Explorer version, I am using a pretty handy application called IETester.
But trying to access localhost with IE in the virtual machine did not work. I got a “404 page not found” error instead of seeing my app running on the local App Engine instance. Obviously, Parallels does not automatically forward localhost requests to OSX and maybe that is actually a good idea security-wise.
To fix the issue, you need to run Google App Engine on a public network interface, or in other words, bind the App Engine server to all available IP addresses. The down side: everybody knowing your IP address can see the GWT app now, but otherwise you are not allowed to access it in the virutal machine as from your OSX’s point of view, that Windows machine is “some other guy accessing from the outside”, too. To make GAE accessible from the outside, add the parameter “-bindAddress 0.0.0.0″ when launching you local GAE. Using Eclipse you can achieve that by right clicking your project -> Run As -> Run Configurations -> Choose “(x)= Arguments” tab; add the option to the top most box titled “Program arguments” in the options area (e.g. before “-port 8888″).
The first part of the list of arguments should look something like that:
-remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -startupUrl GlocalUiPg2.html -logLevel INFO -codeServerPort 9997 -bindAddress 0.0.0.0 -port 8888 ...
Now, you can access you app using the OSX’s public IP address. (You can get to know your IP by having a look at the network preferences panel.) Launching GAE from Eclipse, you will see a different link (URL) in the “Development Mode” tab now, containing the public IP already. Using that one in, say, your Firefox on Mac, it will ask you now whether you want to allow the debugger access. That is also due to the fact, that you are now using a public address, so it is not clear to your local debug server, whether that request came from the same computer or someone else in the network.
Adding a New Service (GWT)
Adding a new servlet/service to you GWT application is quite straight forward, e.g. by copying the example “greetingService” or creating a new servlet. But it’s easy to overlook a required change/adjustment of your project’s configuration and you might end up with an error message like “Blocked attempt to access interface ‘some.package.SomeService’, which is not implemented by ‘some.other.package.SomeOtherServiceImpl’; this is either misconfiguration or a hack attempt”.
Check list (some should be replaced with whatever you want to call your new service):
- Copy or create files:
SomeService.java and SomeServiceAsync.java in client package
SomeServiceImpl.java in server package + change implementation statement to SomeService - Adjust web.xml:
<servlet> <servlet-name>someServlet</servlet-name> <servlet-class>some.package.SomeServiceImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>someServlet</servlet-name> <url-pattern>/[copy base directory name from other service declaration]/some</url-pattern> </servlet-mapping>
- Annotate interface SomeService.java:
@RemoteServiceRelativePath("some") - Connect to your new service in the client:
private final SomeServiceAsync someService = GWT.create(SomeService.class);
Definitely some possibilities to make a mistakes or miss something here.
Using the XML Parser in GWT
I tried using the XML parsing features of the GWT like that:
form.addSubmitCompleteHandler(new SubmitCompleteHandler() {
@Override
public void onSubmitComplete(SubmitCompleteEvent event) {
// One time upload only, to upload again, user needs to start the upload process from scatch – keeping it simple for now
panel.clear();
Window.alert(event.getResults());
Document result = XMLParser.parse(event.getResults());
...
});
But GWT kept telling me “No source code is available for type com.google.gwt.xml.client.Document; did you forget to inherit a required module?”. It turns out, you are required to explicitly add the XML functionalities to your project by adding following line to your .…gwt.xml file:
<inherits name='com.google.gwt.xml.XML'/>
Raises a question: What’s the point of AJAX (Asynchronous JavaScript and XML) without XML? Or in other words there is no AJAX without XML! So it’s up to you to add the AX part to GWT manually. What’s next?
GWT FileUpload: Adding Widgets to a FormPanel
If you build your first GWT form, for example something like that:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent"> <ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"> <g:HTMLPanel> <g:FormPanel ui:field="form"> <g:FileUpload ui:field="uploadField" name="file"/> <g:SubmitButton ui:field="submitButton">Upload</g:SubmitButton> </g:FormPanel> </g:HTMLPanel> </ui:UiBinder>
And your console keeps telling you during runtime something like this: “java.lang.IllegalStateException: SimplePanel can only contain one child widget”. Instead of writing a long page of explanations and complaints like I did before, it’s simply like that:
“Just put all your widgets in a panel (like HorizontalPanel) and add that panel to the FormPanel.” (Jake − cf. comment below)
Thanks Jake!
GWT Does Not Load Module in Local AppEngine
The issue arose after I renamed the module file (ending with .gwt.xml) to better represent the module functionality. I also updated all relevant files in the project (search for files containing the old name to find them) accordingly.
Starting the application after that modifications ended up in an error (“[ERROR] Unable to find ‘<old module name>.gwt.xml’ on your classpath; could be a typo, or maybe you forgot to include a classpath entry for source?”) as the AppEngine tried loading the module by its old name.
Solution: Delete the launch profile for the project (by choosing “Run As…” -> “Run Configurations…” from the context menu).
Obviously the GWT does not check nor update the automatically generated launch profile thus you need to delete it to force the GWT to create a new profile from scratch taking the project changes into account. You might also adjust the profile according to the changes made, but deleting it is the safe and easy way.
First GWT Steps
Just started to work with GWT – a pretty interesting approach for web development compared to PHP or JSF. The whole Application engine is quite impressive especially allowing you to quickly test your applications locally by supporting automatic hot deployment after each code update.
One thing that took me a while was one of that “[ERROR] Unable to find ‘[some-file].xml’ on your classpath; could be a typo, or maybe you forgot to include a classpath entry for source?” errors. If you are sure the file is in place, I realized restarting the App Engine or Eclipse mostly solves that problem.