Introduction
The Scalable Vector Graphics (SVG) specification 1.1 has been a W3C Recommendation for over three years now. Firefox 1.5 introduced a built-in SVG rendering engine, and Adobe has an SVG plug-in available for Internet Explorer. This article explains how you can use the SVG support contained in GWT Widget Library o.o.5 to render SVG elements, and how you can make your page compatible with both Firefox and Internet Explorer 6.
SVGPanel Widget
The first widget you always need to create to render SVG graphics is the SVGPanel widget. When you create this widget you need to specify the width and height or the drawing area.
SVGPanel sp = new SVGPanel(500, 300);
This panel, once created, becomes a factory for other components. This works similar to the XML DOM. In this initial release you can create circles, rectangles, ellipses, and paths.
SVGRectangle rect = p.createRectangle(x, y, width, height);
SVGCircle circle = p.createCircle(cx, cy, radius);
SVGEllipse ellipse = p.createEllipse(cx, cy, rx, ry);
SVGPath path = p.createPath(x, y);
Creating a widget this was does not add it to the drawing. You still need to add the SVGPanel via the add() method.
SVGRectangle, SVGCircle, and SVGEllipse
Once created you can set additional attributes to these objects. For all of these you may set the fill color, stroke color, fill opacity, stroke opacity, and stroke width. Each of these objects will also have attributes specific to the object type. For example, you can change the radius of a circle after it's creation, and you may extend a path by adding additional points.
Each method that sets the attribute of an object will return the object itself. This allows you to chain the setting of attributes. The only trick is that some methods belong to the super class SVGBasicShape, which will return an instance of SVGBasicShape, and not the specific subclass. So you just need to be sure to set your widget specific attributes first, followed by the attributes that belong to the super class.
Below are some concrete examples, which show off the various attributes.
p.add(p.createRectangle(0, 0, 500, 300)
.setStroke(Color.DARK_GRAY)
.setStrokeWidth(2)
.setFill(Color.LIGHT_GRAY));
p.add(p.createEllipse(250, 225, 150, 70)
.setStroke(Color.RED)
.setStrokeWidth(1)
.setFill(Color.BLUE));
p.add(p.createCircle(420, 225, 60)
.setFill(Color.BLACK)
.setStrokeWidth(15)
.setStroke(Color.WHITE));
SVGPath Widget
The path widget deserves special attention. You create a path widget by specifying the initial point on the path. From this initial point you can add additional points by drawing either straight lines or curves. You may also move the current point to include multiple lines, for example the inner and outter circles of a doughnut. You may leave the path open, or close it to create a shape. The curves may be cubic Bezier, quadratic Bezier, or elliptical arcs. Each line or curve may be specified using either absolute coordinates, or coordinates relative to the current point. I suggest reading through the path portion of the SVG specification for details on using each of the curves.
The example below draws a hexagon using relative lineTo commands, coloring the shape with red translucent fill, and an orange border.
p.add(p.createPath(150, 190)
.relLineTo(10, 0)
.relLineTo(4, 8)
.relLineTo(-4, 8)
.relLineTo(-10, 0)
.relLineTo(-4, -8)
.closePath()
.setFill(Color.RED)
.setFillOpacity(50)
.setStroke(Color.ORANGE)
.setStrokeWidth(1));
Here is another path that creates an upside-down tear-drop shape, with a translucent yellow fill.
p.add(p.createPath(250, 225)
.relMoveTo(-25, -25)
.relCurveToC(0, -25, 50, -25, 50, 0)
.relLineTo(-25, 50)
.closePath()
.setFill(Color.YELLOW)
.setFillOpacity(50)
.setStroke(Color.BLACK)
.setStrokeWidth(1));
Gradients
You may also create linear gradients that can be used to fill a widget, or in place of a stroke color. Gradients consist of one or more "stops". Each stop contains a color, and optionally an opacity . For each stop you specify the color value, and the SVG engine will transition the color/opacity between stops.
The following gradient will color a widget from red to blue. The first value of each stop is the percentage across the widget. 0% being the left-most point on the widget, to 100% being the right-most point.
SVGLinearGradient grad = p.createLinearGradient()
.addStop(0, Color.RED)
.addStop(100, Color.BLUE);
You may also change the vector of the gradient to something other then left ro right. For example, you might want to color a widget from the top to the bottom. Here is the same gradient which will color from top to bottom instead of left to right. The values are percentages of the objects width and height. Specifically this vector definition starts at 0%,0%(x,y) to 0%,100%(x.y).
SVGLinearGradient grad = p.createLinearGradient()
.addStop(0, Color.RED)
.addStop(100, Color.BLUE)
.setVector(0, 0, 0, 100);
Gradients are not widgets, so you do not add them to the SVGPanel, you just use them. Also notice that each method returns the object instance allowing you to chain method calls.
Working in the Google Hosted Browser
Good luck, it doesn't seem to work. If you are able to get this to work, I would be very interested in the solution. For development I have been compiling the Java code to JavaScript, then testing in Firefox and IE.
Setting up your HTML and Deployment
One of the trickest parts I found was trying to get the SVG content to render in both Firefox 1.5 and Internet Explorer 6. If you are using Iinternet Explorer you will need to first download and install the SVG Viewer plug-in from Adobe. I also strongly suggest reading the Inline SVG page on the SVG Wiki, it will explain in detail how to get everything working across browsers.
Below is the HTML template that I have been using.
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:svg="http://www.w3.org/2000/svg">
<head>
<title>SVG Component Example</title>
<meta name="'gwt:module'"
content="'org.gwtwidgets.examples.svg.Project'">
<object id="AdobeSVG"
classid="clsid:78156a80-c6a1-4bbf-8e6a-3cd390eeb4e2">
</object>
<?import namespace="svg" implementation="#AdobeSVG"?>
</head>
<body>
<script type="text/javascript" src="gwt.js">
</script>
</body>
</html>
Firefox requires that the page be either XML or XHTML, requiring the XHTML namespace definition. This is because Firefox uses a different parser for XML and HTML, and the XML parser is the one that understands SVG.
Internet Explorer requires the svg namespace declaration, as well as the