Overview
With the JSP 2D Taglib, your web applications now have full access to the Java 2D API for dynamically rendering beautiful graphics primitives (like the shape to the right) directly in your web page without limitation. Yes, the web page itself becomes a canvas on which you can leverage the full power of the Java 2D API for graphics. Literally all browsers are supported... no Applets, JavaScript, Ajax, Flash, Plug-Ins, Cookies, Lazlo or any other hackery required on the client! (We keep our hackery on the server, thank you.)
The 2D taglib is similar in concept to the <canvas> tag pioneered by Apple in Safari 2 and later accepted by the WHATWG in one of their specs... it allows web page authors to script graphics primitives directly in the HTML source of a page using JavaScript (although the user need not have JavaScript enabled in her browser). For example, the rounded red pentagon to the right was authored with this tag:
<twod:canvas id="polygon" width="200" height="200" alt="A polygon">
// create red gradient paint
var color1 = new java.awt.Color(0xC80021);
var color2 = new java.awt.Color(0x711928);
var x1 = 20; var y1 = 0;
var x2 = 20; var y2 = 190;
var grad = new java.awt.GradientPaint(x1,y1,color1,x2,y2,color2);
// create pentagon
var xPoints = [101,180,150, 52, 20];
var yPoints = [24 , 81,177,177, 81];
var numPoints = xPoints.length;
var pentagon = new java.awt.Polygon(xPoints,yPoints,numPoints);
// create stroke with rounded corners
var endCap = java.awt.BasicStroke.CAP_ROUND;
var join = java.awt.BasicStroke.JOIN_ROUND;
var stroke = new java.awt.BasicStroke(20,endCap,join);
// draw polygon on the current graphics context (g)
g.setPaint(grad);
g.fill(pentagon);
g.setStroke(stroke);
g.draw(pentagon);
</twod:canvas>
Wow! As you can see, the entire Java 2D API is exposed to the web author inside a <twod:canvas> tag via JavaScript. Web page authors can use all of the nice scripting features of the familiar JavaScript language (native collection types like Arrays and Object dictionaries, and dynamic typing) to harness the massively powerful Java 2D API -- and the result renders directly in the web page! The 2D Taglib is capable of rendering beautiful, high-quality, anti-aliased graphics and text.
Additionally, each <twod:canvas> tag is implicitly provided a java.awt.Graphics2D instance as a globally-scoped JavaScript variable named g. This is the graphics context for the current canvas, and the graphical effects you invoke on it will appear in an image on the web page.
But wait, there's more! Just like any JSP or JSP EL expression, the <twod:canvas> tag has access to implicit read-only JavaScript Object represenations of the applicationScope, sessionScope, requestScope, pageScope, request parameters and more! This is where the true power of the 2D Taglib becomes evident...
Imagine for a moment that you work for a web hosting company that has developed a web app to edit your client's server configurations... Objects representing those servers are stored throughout the life of the application in each of the scopes mentioned above. At runtime, using the 2D Taglib, your application could access the server objects in a given scope and render dynamic graphical representations of a given client's hardware configuration. Look ma, no Photoshop!
Source code and binaries of
version 0.1 of the JSP 2D Taglib
are available under the LGPL.
Next Tab » WTF?
WTF?
If you're like me, you're probably wondering how the heck the 2D Taglib does its thang... If not, you can safely skip ahead to the
Install tab
.
Here's how it works...
First, the 2D Taglib depends on Rhino -- the Mozilla Foundation's JavaScript implementation written in pure Java. You'll need the Rhino JAR (js.jar) in your web app's /WEB-INF/lib dir. The 2D Taglib is
available as a JAR of its own
, of course, which you must also drop into your /WEB-INF/lib directory.
When you install the 2D Taglib, a special new ServerletContextListener is automatically registered for your web app. This listener attempts to create a new directory (named org.ditchnet.taglib.2d) in the root directory of your web app when the app is reloaded. If your web app's root dir is not writable, you'll have issues. Specifically, this seems to be a problem when deploying on Windows. I have discovered a fix for this, though.... Buy a Mac. If you're not willing to buy a Mac, download the source code, find the problem and help me out. I don't have a Windows box on which to test.
When a JSP page with a <twod:canvas> tag is encountered by the web container, control is temporarily passed to the doTag method an org.ditchnet.jsp.taglib.twod.CanvasTag JSP tag handler class instance just like any other JSP tag handler. The CanvasTag instance uses Rhino to create a JavaScript runtime environment against which it executes the JavaScript code within the tag's body. Before executing the JavaScript body code, the CanvasTag instance does a few special things:
- Creates an offscreen image (an instance of java.awt.image.BufferedImage) in memory.
- Retrieves the graphics context or drawing surface of that image (an instance of java.awt.Graphics2D) and places it within the global scope of its JavaScript runtime as a variable named g. What up g?
- Places native JavaScript Object representations of all of the standard implicit EL expression objects in the JavaScript runtime's global scope. For example, the following JavaScript objects are available to JavaScript within a canvas tag much like they are within a JSP EL expression:
- applicationScope - a read-only JavaScript map of all the objects stored in the current javax.servlet.ServletContext.
- sessionScope - a read-only JavaScript map of all the objects stored in the current javax.servlet.http.HttpSession.
- requestScope - a read-only JavaScript map of all the objects stored in the current javax.servlet.http.HttpServletRequest.
- pageScope - a read-only JavaScript map of all the objects stored in the current javax.servlet.jsp.PageContext.
- pageContext - a JavaScript Object representation of the current javax.servlet.jsp.PageContext.
- pageContext.request - a JavaScript Object representation of the current javax.servlet.http.HttpServletRequest.
- param - a read-only JavaScript map of all the current request parameters (query-string args).
- paramValues - a read-only JavaScript map of all the current request's multi-valued parameters (query-string args).
- header - a read-only JavaScript map of all the current request's HTTP headers.
- headerValues - a read-only JavaScript map of all the current request's multi-valued HTTP headers.
- cookie - a read-only JavaScript map of all the current request's HTTP cookies.
- initParam - a read-only JavaScript map of all the web app's init parameters (defined in web.xml.
Basically, everything you have access to in JSP or JSF EL expressions is also available to you within a <twod:canvas> tag. Bean properties of the objects above may be accessed directly without the get prefix just as in the EL. This allows you do draw graphic representations of arbitrary objects stored in any scope at runtime.
- After the JavaScript code body has been executed to render graphics and image effects on the offscreen image, the image is written as a PNG or JPEG file (PNG by default) to the directory created earlier by the servlet context listener. The file is named according to the id attribute you give the <twod:canvas> tag, so the value of the id should be unique across your web app.
- The CanvasTag instance notes the location of the newly-created image, and writes an HTML <img> tag to the HTTP response with a src attribute corresponding to the new image.
Pretty cool, huh? You may be a bit worried about performance though... this hypothetical HTTP request has a lot going on. Don't worry, the CanvasTag is intelligent enough to know how to cache the images it generates. It only generates a new image on a given request if the current JSP file has been edited since the last time the image was generated. Otherwise, it skips steps 1-4 above, and just renders the HTML <img> tag to the response pointing to the previously generated image.
Alternatively, for those with a decadent nature, the <twod:canvas> tag has an attribute named cache which you may set to false, off, or no to cause a new image to be generated for every request. This attribute defaults to true.
Next Tab » Install
Install
Thanks to the JSP and Servlet APIs, Installation of the 2D Taglib is simple:
-
Download
the Ditchnet JSP 2D Taglib JAR file.
- Drop the JAR file into the WEB-INF/lib directory of your web application.
- Make sure that the root directory of your web app is writable (this is important).
- Make sure that Rhino -- the Mozilla Foundation's JavaScript interpreter written in pure Java -- is in your web app's classpath. This means having js.jar on your web app's classpath (preferably in WEB-INF/lib).
- Reload your web app.
The 2D Taglib is now installed. Yup, that's it.
You can now begin authoring web pages with 2D graphics primitives as
described next...
You may be wondering why the root directory of your web app must be writable... The 2D Taglib includes a ServletContextListener that will automatically be registered for your web app -- you don't need to add anything to your web.xml deployment descriptor to register this listener -- the configuration for this listener is included in the taglib tld file in the JAR, and will be registered without additional effort.
This ServletContextListener's first job is to create a directory in the root of your web app named org.ditchnet.taglib.2d. The taglib will use this directory to save the images that contain the 2D graphics that you author in your JSPs. After dropping the 2D JAR and the Rhino JAR into your WEB-INF/lib directory, and reloading your web app, you will see this directory appear.
If you do not see this directory appear upon web app reload, there may be a permission issue in writing to your web app's root directory. Try to change this, and reload the web app.
Next Tab » Author
Author
Even silly Web Monkeys will find authoring <twod:canvas> tags of their own easy and enjoyable. First, like any other JSP Taglib, you must import the 2D Taglib at the top of your JSP.
<%@ taglib prefix="twod" uri="http://ditchnet.org/jsp-2d-taglib" %>
Note that the preferred taglib prefix is twod. We suggest you stick to this. Now you can author <twod:canvas> tags anywhere in your page:
<twod:canvas id="my-canvas" width="100" height="100" alt="A cool image.">
</twod:canvas>
The id, width, height, and alt attributes are required. The id must be unique across your web app. The width and height will determine the size of the offscreen image that is created.
All of the attributes seen so far are also "pass-through" attributes in JSF terms. In other words, they will be rendered as attributes of the HTML <img> tag in the HTTP response.
You can also add style directly to the <twod:canvas> tag:
<twod:canvas id="my-canvas" width="100" height="100" alt="A cool image."
border="1" style="margin:10px;">
</twod:canvas>
These two attributes also pass-through directly to the resulting HTML <img> tag.
Use the styleClass attribute to add an HTML/CSS class to the resulting HTML <img> tag:
<twod:canvas id="my-canvas" width="100" height="100" alt="A cool image."
styleClass="my-class">
</twod:canvas>
This attribute's value will be rendered as an HTML class attribute on the <img> tag, allowing your canvas to pick up CSS styles like borders, floats, margins and absolute positioning. Note that the canvas tag will not recognize CSS colors or text styles when rendering its image. All of those features must be controlled via the canvas tag's JavaScript code body.
By default, the image that is generated is a PNG. You can produce a JPEG instead by using the imageFormat attribute:
<twod:canvas id="my-canvas" width="100" height="100" alt="A cool image."
imageFormat="jpg">
</twod:canvas>
It is not currently possible to control the compression quality of the resulting JPEG, but this will be available soon.
Now that you've got your <twod:canvas> tag all set up, it's time for the fun part... scripting the Java 2D API via JavaScript within the tag's body:
<twod:canvas id="my-canvas" width="100" height="100" alt="A cool image.">
g.setColor(java.awt.Color.red);
g.drawString("Hello from CanvasTag!",5,50);
</twod:canvas>
As you can see, you must use the fully qualified Java class name to access Java classes in the java.* packages. Alternatively, you can import entire packages using Rhino's importPackage and importClass global JavaScript functions:
<twod:canvas id="my-canvas" width="100" height="100" alt="A cool image.">
importPackage(java.awt, Packages.javax.swing);
importClass(java.lang.System);
g.setColor(Color.red);
g.drawString("Hello from CanvasTag!",5,50);
</twod:canvas>
As you can see, Java packages outside of the java.* package (such as javax.*) must be qualified with Packages. This is part of Rhino's LiveConnect feature. See the Rhino site for documenation and details.
Next Tab » FAQ
FAQ
-
Q: What browsers are supported by the Ditchnet JSP 2D Taglib?
A: The 2D Taglib has been tested on the following modern web browsers. Since the 2D Taglib is executed entirely on the server, there should be no reason why it would not be compatible any older browsers as well.
- InternetExplorer 6 for Windows
- Firefox 0.8+
- Mozilla 1.4+
- Netscape Navigator 6+
- Safari 1.0+
- Opera 7+
- OmniWeb 4.5+
- Camino 0.7+
- InternetExplorer 5.5 for Windows
- InternetExplorer 5.0 for Windows
- InternetExplorer 5+ for Mac
-
Q: What are the server-side requirements for the 2D Taglib? Which servlet containers are supported?
A: The 2D Taglib requires Rhino to be in your web app's classpath. Rhino is a JavaScript implementation written in pure Java and consists of a single jar named js.jar. Be sure to drop this in your web app's lib directory. The 2D Taglib has only been tested with the Apache Tomcat servlet container v5.0.28. A servlet container that implements at least the JSP 2.0 spec and the Servlet 2.3 spec will be required.
-
Q: Is the 2D Taglib Free software?
A: Yes. The 2D taglib is released under the LGPL.
-
Q: What is the status of the 2D Taglib?
A: The 2D Taglib is currently beta software, and not meant for production systems. All features of the 2D Taglib are subject to change before the 1.0 release, at which point the API will be stabilized for backward compatibility. I have a lot of ideas for other tags to include in the taglib. The 2D Taglib is under active development, and the 1.0 version will be released soon.
-
Q: Does the 2D Taglib produce valid XHTML?
A: Yes, the HTML produced by the 2D Taglib is XHTML 1.0 Strict, thank you.
-
Q: Is the 2D Taglib compatible with JavaServer Faces Components?
A: The Executive Summary: YES. The 2D Taglib is no more or less compatable with JSF than any other JSP taglibs (including the JSTL). There are many well-documented issues with using JSF and JSP together at this time... the JSF 1.2 spec and JSP 2.1 spec aim to fix these problems, and should be released shortly.
-
Q: Will there be a JSF version of the 2D Taglib?
A: Maybe... JSF's greatest advantage in web interface development is creating components that accept input, can validate themselves, and store their values. The 2D Taglib does not require all of these features.
-
Q: Are any java.awt.RenderingHints set on the implicit g graphics context within a <twod:canvas> tag?
A: Yes, the following are set (although you can change them yourself within the canvas tag):
- KEY_ANTIALIASING
- VALUE_ANTIALIAS_ON
- KEY_TEXT_ANTIALIASING
- VALUE_TEXT_ANTIALIAS_ON
- KEY_RENDERING
- VALUE_RENDER_QUALITY
- KEY_STROKE_CONTROL
- VALUE_STROKE_PURE
We're not really sure what that last one does, but we thought it sounded fun, so what the heck?
Next Tab » Download
Download
The 2D Taglib is Free Software released under the LGPL and is currently available as a pre-release beta package. The 2D Taglib is not considered ready for production systems just yet. Please try out the taglib and
send feedback
, so we can reach the 1.0 milestone! Certain aspects of the API documented on this webpage may change before the 1.0 release.
Binaries & Source
If you would like to make a donation to fund the future development of the 2D Taglib, you may do so by clicking the button below...
Next Tab » API
API
Credits
Documentation generated using the following excellent tools:
Next Tab » Contact