|
GWTCanvas
Provides cross Browser Vector Graphics support in the spirit of the Javascript canvas element API.
IntroductionVector graphics have made their way to the GWT Incubator. The GWTCanvas Widget exposes an API for drawing and transforming shapes and images, as well as for defining paths to create custom shapes. GWTCanvas currently supports:
See the live demo: http://google-web-toolkit-incubator.googlecode.com/svn/trunk/demo/GWTCanvasDemo/GWTCanvasDemo.html Setup InstructionsJust add the following line to your module.gwt.xml file: <inherits name='com.google.gwt.widgetideas.GWTCanvas'/> You can specify your own stylesheet to further customize the look and feel of GWTCanvas. Using ImagesIn order for GWTCanvas to draw images, they must first be loaded by the browser. We provide an ImageLoader class in the same package as GWTCanvas to take care of this for you. Please refer to the Sample Code below for examples on how to use ImageLoader. Sample CodePlease refer to the source code of the live demo (which can be found in the incubator trunk) for more detailed examples. Drawing a rectangle using paths.
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.widgetideas.graphics.client.Color;
import com.google.gwt.widgetideas.graphics.client.GWTCanvas;
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class MyEntryPoint implements EntryPoint {
public void onModuleLoad() {
// Make a new canvas 400x400 pixels
GWTCanvas canvas = new GWTCanvas(400,400);
canvas.setLineWidth(1);
canvas.setStrokeStyle(Color.GREEN);
canvas.beginPath();
canvas.moveTo(1,1);
canvas.lineTo(1,50);
canvas.lineTo(50,50);
canvas.lineTo(50, 1);
canvas.closePath();
canvas.stroke();
RootPanel.get().add(canvas);
}
}
Drawing an image (Scaling THEN translating before drawing). Please note that you must put all drawing code involving the image in the supplied callback. Drawing order for images and paths is guaranteed only within the callback method when working with images (since they have to be loaded first, and it can not be known ahead of time how long that will take). import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.widgetideas.graphics.client.GWTCanvas;
import com.google.gwt.widgetideas.graphics.client.ImageHandle;
import com.google.gwt.widgetideas.graphics.client.ImageLoader;
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class MyEntryPoint implements EntryPoint {
public void onModuleLoad() {
// Make a new canvas 400x400 pixels
final GWTCanvas canvas = new GWTCanvas(400,400);
String[] urls = new String[] {"gwt_logo.jpg"};
ImageLoader.loadImages(urls, new ImageLoader.CallBack() {
public void onImagesLoaded(ImageHandle[] imageHandles) {
ImageHandle img = imageHandles[0];
canvas.translate(40, 40);
canvas.scale(0.5f, 0.5f);
canvas.drawImage(img, 0, 0);
}
});
RootPanel.get().add(canvas);
}
}
Drawing two rectangles, with different colors, in different locations.
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.widgetideas.graphics.client.Color;
import com.google.gwt.widgetideas.graphics.client.GWTCanvas;
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class MyEntryPoint implements EntryPoint {
public void onModuleLoad() {
// Make a new canvas 400x400 pixels
GWTCanvas canvas = new GWTCanvas(400,400);
canvas.setLineWidth(1);
canvas.setStrokeStyle(Color.GREEN);
canvas.saveContext();
canvas.setLineWidth(1);
canvas.setStrokeStyle(Color.RED);
canvas.translate(100, 100);
canvas.strokeRect(0, 0, 100, 100);
canvas.restoreContext();
canvas.strokeRect(1, 1, 80, 80);
RootPanel.get().add(canvas);
}
}
Important Caveats
|
Sign in to add a comment
Would it be possible to add setGlobalCompositeOperation like
I think this is not possible or easy for IE, but for other browsers it would be great. I use a different implementation for IE anyway. My problem is just, I have no way to set this for Firefox other than to patch GWTCanvas. If the implementation for IE just does nothing, that would be enough.
For me the IE implementation doesn't look right (at least for this demo - haven't seen the source), blurry squares, strokes too thin, etc...
I've done something similar, take a look at http://code.google.com/p/gwt-canvas/
It is not complete, however it looks almost pixel-perfect on IE for me. So please feel free to merge it into GWTCanvas (or the other way around) if it helps ;)
I've downloaded the latest version of the incubator to try the GWTCanvas out, but:
doesn't seem to appear anymore? Where is the canvas class located now?
Thanks
I' like to ask the same question as markww. It doesn't look to be anywhere. And It looks an amazing job!
thanks, Dirso
dirsow, it's not in the compiled jar they have up on the site. I had to build the whole incubator myself, it's in the trunk of the repository!
So this is dependent on the canvas element support being present correct? This will not work in hosted mode on the linux platform because GWT currently uses the antiquated mozilla 1.7 for its rendering (correct me if i'm wrong).
@dolcraith
You are correct. We are working on addressing that though :). For now, if you have access to a Mac, you should be able to develop in hosted mode just fine. Otherwise (and I realize that this is non-optimal) you will have to debug in web mode.
I want draw line on a piece of image, how did i do?
Is it possible for a GWTCanvas to receive any events, such as mouse or click events?
@eroberts00
I extended the GWTCanvas class to implement mouse listening events:
public final class Canvas extends GWTCanvas { private MouseListener listener; public Canvas() { super(620, 620); sinkEvents(Event.MOUSEEVENTS); } @Override public void onBrowserEvent(Event event) { super.onBrowserEvent(event); if (listener != null) { int x = event.getClientX() - getAbsoluteLeft(); int y = event.getClientY() - getAbsoluteTop(); switch (event.getTypeInt()) { case Event.ONMOUSEDOWN: listener.onMouseDown(this, x, y); break; case Event.ONMOUSEMOVE: listener.onMouseMove(this, x, y); break; case Event.ONMOUSEUP: listener.onMouseUp(this, x, y); break; } } } public void setListener(MouseListener listener) { this.listener = listener; } }@nvaneijck
Thanks, that worked great.
How do you render/draw Text using GWTCanvas?
I have added click events and multiple listeners to nvaneijck's contribution:
import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.ClickListener; import com.google.gwt.user.client.ui.ClickListenerCollection; import com.google.gwt.user.client.ui.MouseListener; import com.google.gwt.user.client.ui.MouseListenerCollection; import com.google.gwt.widgetideas.graphics.client.GWTCanvas; public class Canvas extends GWTCanvas { private MouseListenerCollection mouseListeners; private ClickListenerCollection clickListeners; public Canvas() { super(); } public Canvas(int coordX, int coordY) { super(coordX, coordY); } public Canvas(int coordX, int coordY, int pixelX, int pixelY) { super(coordX, coordY, pixelX, pixelY); } @Override public void onBrowserEvent(Event event) { super.onBrowserEvent(event); if ((clickListeners != null && clickListeners.size() > 0) || (mouseListeners != null && mouseListeners.size() > 0)) { int x = event.getClientX() - getAbsoluteLeft(); int y = event.getClientY() - getAbsoluteTop(); switch (event.getTypeInt()) { case Event.ONCLICK: if (clickListeners != null) { clickListeners.fireClick(this); } break; case Event.ONMOUSEDOWN: if (mouseListeners != null) { mouseListeners.fireMouseDown(this, x, y); } break; case Event.ONMOUSEMOVE: if (mouseListeners != null) { mouseListeners.fireMouseMove(this, x, y); } break; case Event.ONMOUSEUP: if (mouseListeners != null) { mouseListeners.fireMouseUp(this, x, y); } break; } } } public void addClickListener(ClickListener listener) { if (clickListeners == null) { clickListeners = new ClickListenerCollection(); sinkEvents(Event.ONCLICK); } clickListeners.add(listener); } public void addMouseListener(MouseListener listener) { if (mouseListeners == null) { mouseListeners = new MouseListenerCollection(); sinkEvents(Event.MOUSEEVENTS); } mouseListeners.add(listener); } public void removeClickListener(ClickListener listener) { if (clickListeners != null) { clickListeners.remove(listener); } } public void removeMouseListener(MouseListener listener) { if (mouseListeners != null) { mouseListeners.remove(listener); } } }Rendering on canvas is fast on firefox/chrome, but on IE it is extremely slow. I found that GWTCanvas's vml implementation on IE is the cause: passing the string to browser every time you want to render something. I suggest GWTCanvas can have some "compile list" function as OpenGL, so that we can manipulate the attribute of some compile element rather than pass string to browser every time. I think some dojo code may inspire GWTCanvas developer:
var node = document.createElement("div"); document.body.appendChild(node); var surfaceWidth = 120; var surfaceHeight = 220; var surface = dojo.gfx.createSurface(node,surfaceWidth, surfaceHeight); var rect = { x: 100, y: 0, width: 100, height: 100 }; var circle = { cx: 150, cy: 160, r: 50 }; var group = surface.createGroup(); var blueRect = group.createRect(rect) .setFill([0, 0, 255, 0.5]) .applyTransform(dojo.gfx.matrix.identity); var greenCircle = group.createCircle(circle) .setFill([0, 255, 0, 1.0]) .setStroke({color: "black", width: 4, cap: "butt", join: 4}) .applyTransform(dojo.gfx.matrix.identity);this piece of code is copy from: http://www.thinkvitamin.com/features/design/create-cross-browser-vector-graphics
Is this likely to go into 1.5, or will we have to wait for 1.6?
I would like to congratulate nvaneijck, for the mouse listner implementation, and srfarley for improving it. It helped me a lot in a college project. Thanks!
Hi - I have the same question/need as stated above: can I somehow render text on the gwtcanvas? Thanks a lot! Axel
In GWT 1.6, the classes srfarley uses are deprecated. The new event system is a lot cleaner. Here's an example for mouse down events:
import com.google.gwt.event.dom.client.HasMouseDownHandlers; import com.google.gwt.event.dom.client.MouseDownEvent; import com.google.gwt.event.dom.client.MouseDownHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.widgetideas.graphics.client.GWTCanvas; public class Canvas extends GWTCanvas implements HasMouseDownHandlers { public Canvas() { super(); } public Canvas(int coordX, int coordY) { super(coordX, coordY); } public Canvas(int coordX, int coordY, int pixelX, int pixelY) { super(coordX, coordY, pixelX, pixelY); } public HandlerRegistration addMouseDownHandler(MouseDownHandler handler) { return addDomHandler(handler, MouseDownEvent.getType()); } }Then you can add an extended handler class and it'll get fired by GWT for you. In the callback functions, use getAbsoluteLeft() and getAbsoluteTop() as in nvaneijck's original to convert from screen coordinates to canvas coordinates.
Hi all,
Check out my application using gwt canvas : its http://gwt-mind-mapping.appspot.com/
Its only a alpha prototype version.
Thx