Using the Google Web Toolkit (GWT) to create an HTML5 Canvas that uses (almost) all available space

Post to Twitter

A few weeks ago I had written an article in regards to getting the HTML5 Canvas to take up the entire browser available area and to take into consideration scrollbars as well as mobile devices. The code works pretty decent but any feedback is appreciated in the comments section. Keep in mind I have a Droid X so that is the only mobile device I’ve tested my code on thus far – see here for a live demo.

I wanted to take the code I had written and modify it to work with the Google Web Toolkit or GWT as most people call it. Today I’ll show you the code I came up with. I can’t say this is the way to do it because this code was the result of some trial and error so improvements most likely are needed but its at least a stepping stone.


Article Updated March 7, 2011 – Thanks to John Munsch.

Here are the steps I did to make this example.

Create a new Google Web Application Project (using the Google plug-in for Eclipse). I called my project: GWTCanvasResize

Remove the Servlets XML from the web.xml file as we won’t need any of that.

Here is what my web.xml looks like after removing the XML:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
  
  <!-- Servlets -->

</web-app>

Remove/delete the following files from the project:

  • GreetingService.java
  • GreetingServiceAsync.java
  • GreetingServiceImpl.java
  • FieldVerifier.java

In the GWTCanvasResize.html file remove all the code between the closing noscript and closing body tag so your file looks like this:

<!doctype html>
<!-- The DOCTYPE declaration above will set the    -->
<!-- browser's rendering engine into               -->
<!-- "Standards Mode". Replacing this declaration  -->
<!-- with a "Quirks Mode" doctype may lead to some -->
<!-- differences in layout.                        -->

<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">

    <!--                                                               -->
    <!-- Consider inlining CSS to reduce the number of requested files -->
    <!--                                                               -->
    <link type="text/css" rel="stylesheet" href="GWTCanvasResize.css">

    <!--                                           -->
    <!-- Any title is fine                         -->
    <!--                                           -->
    <title>Web Application Starter Project</title>
    
    <!--                                           -->
    <!-- This script loads your compiled module.   -->
    <!-- If you add any GWT meta tags, they must   -->
    <!-- be added before this line.                -->
    <!--                                           -->
    <script type="text/javascript" language="javascript" src="gwtcanvasresize/gwtcanvasresize.nocache.js"></script>
  </head>

  <!--                                           -->
  <!-- The body can have arbitrary html, or      -->
  <!-- you can leave the body empty if you want  -->
  <!-- to create a completely dynamic UI.        -->
  <!--                                           -->
  <body>

    <!-- OPTIONAL: include this if you want history support -->
    <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
    
    <!-- RECOMMENDED if your web app will not function without JavaScript enabled -->
    <noscript>
      <div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif">
        Your web browser must have JavaScript enabled
        in order for this application to display correctly.
      </div>
    </noscript>
  </body>
</html>

Add the following to the GWTCanvasResize.css file:

.mainCanvas {
   background-color: #000;
   border: solid 3px #0F0;
}
 
.body {
   background: #000;
   overflow-y: hidden;
   overflow-x: hidden;
}
 
.contentHolder {
   width: 100%;
   height: 100%;
   margin: auto;
}

The last thing is to modify the GWTCanvasResize.java file:

package com.giantflyingsaucer.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Label;


public class GWTCanvasResize implements EntryPoint
{
	Canvas canvas;
    Context2d context;
    HTMLPanel panel;
    static final String id = "contentholder";
    
	public void onModuleLoad()
	{
		// Cheesy way to add a DIV but it works for this demo
		panel = new HTMLPanel("<div class=\"content\" id=\"" + id + "\"></div>");
		panel.setStyleName("contentHolder");
		
		Window.addResizeHandler(new ResizeHandler() {

			@Override
			public void onResize(ResizeEvent event)
			{				
				resizeCanvas(event.getWidth(), event.getHeight());
			}
		});

		// Call the resize event for the first time
		resizeCanvas(Window.getClientWidth(), Window.getClientHeight());
		RootPanel.get().setStyleName("body");
		RootPanel.get().add(panel);
	}
	
	private void resizeCanvas(int width, int height)
	{
		// Adjust the width and height by 6 to fit into the viewable area (tested in FireFox and Chrome only)
		width = width - 6;
		height = height - 6;
		
		// Remove the old Canvas
		panel.clear();
		canvas = null;
	    canvas = Canvas.createIfSupported();
	    
        if (canvas == null)
        {
              RootPanel.get().add(new Label("Sorry, your browser doesn't support the HTML5 Canvas element"));
              return;
        }
        
        context = canvas.getContext2d();
        
        canvas.setStyleName("mainCanvas");
        // Add the new Canvas back inside the DIV
		panel.add(canvas, id);
        
        canvas.setWidth(width + "px");
        canvas.setCoordinateSpaceWidth(width);
 
        canvas.setHeight(height + "px");
        canvas.setCoordinateSpaceHeight(height);

        // Don't need to erase first since this is always on a new canvas
        context.setFont("20pt serif");
        context.setFillStyle("#0f0");
        context.fillText("Width: " + width + "   Height: " + height, 25, 100);
	}
}

Not a lot of magic in there. The trick I’ve found that works best for me is when the browser is resized (which I catch with the Window.addResizeHandler) I simply remove the current Canvas and replace it with a new one. This way I’ve been able to avoid some of the redrawing/scaling issues I found with redrawing on the existing but resized Canvas. It ended up just being easier to add the new properly resized Canvas and redraw on that. As you resize your browser the code writes out the dimensions on the Canvas.

I’ve only tested this out on Chrome and Firefox so far.

Here are the results in Chrome and Firefox:

Note: Keep in mind that as of GWT 2.2 the Canvas support is experimental, this code might change in the future as the API changes.

Post to Twitter

This entry was posted in GWT, HTML5. Bookmark the permalink.

4 Responses to Using the Google Web Toolkit (GWT) to create an HTML5 Canvas that uses (almost) all available space

  1. John Munsch says:

    You mention that you avoid making the canvas too large to avoid the scrollbars showing up. I think you could just use the overflow-x and overflow-y CSS properties to make both scrollbars hidden and just crank the size up to the full browser viewable area.

    With those set to hidden the browser is just supposed to clip its contents.

  2. Chad Lung says:

    @John,

    Thanks for the tip. I’ve put the overflow x and y in some test code but the right hand side and then the bottom borders were extending beyond the browser’s viewable area. So I set the container to take up 100% of the space and then took off 6 pixels from the height and width of the canvas, its really close to using all the available space now.

    I’m updating the article with these enhancements.

    Thanks,

    Chad

  3. Jayachandran says:

    hi,
    I am new to GWT i need to draw a image in canvas. I draw image in canvas code is,
    public class TestCanvas implements EntryPoint{

    Canvas canvasScreen;
    Context2d contextScreen;
    static final int canvasHeight = 500;
    static final int canvasWidth = 500;

    public void onModuleLoad() {
    canvasScreen = Canvas.createIfSupported();

    if(canvasScreen == null) {
    RootPanel.get().add(new Label(“Sorry, your browser doesn’t support the HTML5 Canvas element”));
    }
    canvasScreen.setHeight(canvasHeight+”px”);
    canvasScreen.setWidth(canvasWidth+”px”);
    canvasScreen.setCoordinateSpaceHeight(canvasHeight);
    canvasScreen.setCoordinateSpaceWidth(canvasWidth);
    RootPanel.get().add(canvasScreen);
    contextScreen = canvasScreen.getContext2d();
    loadImage();
    }

    private void loadImage() {
    Image img = new Image(/home/jayachandran/Desktop/vss.jpg);

    ImageElement imageElement = ImageElement.as(img.getElement());
    contextScreen.drawImage(imageElement, 110,110, imageElement.getWidth(), imageElement.getHeight());
    }

    }

    if i execute this, only canvas is shown but not image drawn in side the canvas.
    But after refreshing the browser second time the image show on browser in mozilla firefox.

    i need to show on browser on first time itself.

  4. Pingback: Developer Sharing June Edition « GWT Buzz

Comments are closed.