My favorites | Sign in
Google
                
Search
for
Updated Sep 10, 2008 by jaime...@google.com
GWTCanvas  
Provides cross Browser Vector Graphics support in the spirit of the Javascript canvas element API.

Introduction

Vector 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 Instructions

Just 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 Images

In 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 Code

Please 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


Comment by sebastian.l.baltes, Mar 10, 2008

Would it be possible to add setGlobalCompositeOperation like

public native void setGlobalCompositeOperation(String operation) /-{
(this.@com.google.gwt.widgetideas.graphics.client.impl.GWTCanvasImplDefault::canvasContext).globalCompositeOperation = operation;
}-
/;

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.

Comment by oliver.z...@googlemail.com, Apr 01, 2008

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 ;)

Comment by markww, Apr 21, 2008

I've downloaded the latest version of the incubator to try the GWTCanvas out, but:

com.google.gwt.widgetideas.graphics

doesn't seem to appear anymore? Where is the canvas class located now?

Thanks

Comment by dirsow, Apr 23, 2008

I' like to ask the same question as markww. It doesn't look to be anywhere. And It looks an amazing job!

thanks, Dirso

Comment by markww, Apr 23, 2008

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!

Comment by dolcraith, Jun 22, 2008

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).

Comment by jaimeyap, Jul 03, 2008

@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.

Comment by sun.johnsonworld, Aug 03, 2008

I want draw line on a piece of image, how did i do?

Comment by eroberts00, Oct 20, 2008

Is it possible for a GWTCanvas to receive any events, such as mouse or click events?

Comment by nvaneijck, Oct 30, 2008

@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;
    }
}
Comment by eroberts00, Nov 03, 2008

@nvaneijck

Thanks, that worked great.

Comment by mpedzi...@stuart.iit.edu, Nov 14, 2008

How do you render/draw Text using GWTCanvas?

Comment by srfarley, Nov 21, 2008

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);
    }
  }
}
Comment by WChunming, Nov 28, 2008

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

Comment by lobais, Dec 04, 2008

Is this likely to go into 1.5, or will we have to wait for 1.6?

Comment by dobra9, Mar 06, 2009

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!

Comment by memeplex, Mar 26, 2009

Hi - I have the same question/need as stated above: can I somehow render text on the gwtcanvas? Thanks a lot! Axel

Comment by matt.d.hilliard, May 12, 2009

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.

Comment by bosang...@yahoo.com, Jun 03, 2009

Hi all,

Check out my application using gwt canvas : its http://gwt-mind-mapping.appspot.com/

Its only a alpha prototype version.

Thx


Sign in to add a comment