|
SVG support in ILOG JViews Component Suite
|
 |
As part of the SVG Working Group, ILOG is implementing SVG in the ILOG
JViews Component Suite: ILOG's Java two-dimensional graphic library. This
paper explains the technical considerations when importing and exporting SVG
documents from a two-dimensional graphic framework in Java. It also explains
how the Java 2D API helps you do this. We will also see how SVG can be generated
on the server side to create thin client applications that include map displays
or workflow and network diagrams. The benefits and limitations of this approach
are also discussed.
Introduction
ILOG has been developing the JViews Component Suite since 1997. JViews
is an object-oriented library written in Java that targets developers with
advanced needs in two-dimensional graphics. Since last year, ILOG has been
a member of the
SVG
Working Group in the W3C and has started implementing SVG in the ILOG JViews
Component Suite.
What is the ILOG JViews Component Suite?
The ILOG JViews Component Suite is composed of several packages addressing
different types of application problems:
- The Graphics Framework package is the base of all the JViews packages.
It consists of a Java library that defines classes such as rectangles, polylines,
polygons, circles, text, and images. These objects are called “graphic
objects”. It also defines a Manager
class—the data-structure that manages the graphic objects and allows
fast selection, panning, and zooming.
- The Maps package allows developers to create interfaces with custom
screen objects on top of map data. The Maps package natively imports the most
common raster and vector formats, and allows data from different sources to
be combined seamlessly.
- The Graph Layout package contains a broad set of algorithms for
automatically rearranging diagram-like graphs to produce displays such as
rings and star, bus-shaped layouts, hierarchical layouts, or radial layouts.
- The Gantt Chart package provides complete support for viewing schedules—both
resource and task oriented.
What is SVG?
SVG is a language for describing two-dimensional graphics in XML. SVG
elements are used to describe objects such as rectangles, lines, polylines,
polygons, text, paths (sets of lines and curves), and images. The SVG elements
can be styled to change their graphic appearance (color, line width, and so
on) and can be transformed, clipped, and manipulated in various ways.
Implementing SVG in JViews consists of:
- 1. Exporting the graphic objects of the library into an SVG document.
- 2. Importing SVG documents and translating the SVG elements into the
graphic objects of JViews.
This paper is divided into the following parts:
- Part 1: Exporting SVG from ILOG JViews
- Part 2: Importing SVG into ILOG JViews
- Part 3: Using JViews SVG Generation in a Thin-Client Context
Part 1: Exporting SVG from ILOG JViews
Like any graphic toolkit written in Java, ILOG JViews uses the AWT and
Java 2D libraries of the Java platform to draw the graphic objects on screen.
The Java 2D library allows developers writing a toolkit in Java to achieve
complex drawing operations. This is done using complex shapes and advanced
features such as alpha composition, gradient fill, affine transformation,
and advanced text and font support. In order to reproduce these complex drawings
in an XML format, the format must cover the advanced features of Java 2D.
The SVG format has these features as well as some others. That is why SVG
does not introduce any limitations when exporting two-dimensional graphics
written in Java 2D. The difficulty resides in the choice of the technique
to use to produce SVG documents that reflect the object-oriented structure
of the toolkit and that are optimal in terms of size and usability.
Two possible approaches were available to translate drawings from the
toolkit in SVG—the Drawing approach and the Object-oriented approach.
These approaches were evaluated in order to choose the one most appropriate
for ILOG JViews.
Part 1 of this paper is divided as follows:
- The Drawing Approach
- The Object-Oriented Approach
- Advantages and Disadvantages of the Different Approaches
- Generating SVG in ILOG JViews
- Compression Techniques
The Drawing approach
The Drawing approach consists of translating all drawings done with
Java 2D into SVG. This technique consists of sub-classing the java.awt.Graphics2D
class of the Java 2D library. It is through this class that all the drawings
are performed in Java 2D. By sub-classing and implementing all the drawing
primitives such that they produce SVG elements instead of drawing directly
on the screen, it is possible (in theory) to transform any drawing done in
Java into an SVG document.
This technique is very close to what the Java platform does when printing.
In order to print in Java 2D, the Java platform substitutes the java.awt.graphics2D
instance with an instance suitable to translate the drawing primitives into
equivalent printer commands. An example of this technique is given here:
The following Java 2D code (where g is an instance of Graphics2D):
Rectangle rectangle = new Rectangle(10,10,100,100);
//sets the current color to red
g.setPaint(new Color(255, 0, 0));
// sets the line width to 10
g.setStroke(new BasicStroke(10));
// draws the outline of the rectangle
g.draw(rectangle);
// sets the color to blue
g.setPaint(new Color(0, 0, 255));
// fills the rectangle
g.fill(rectangle);
produces the following output:

Figure 1
. A blue-filled rectangle with a red outline
of width 10
If no smart technique is used to reduce the size of the SVG output,
the produced SVG document will probably contain two SVG elements. This is
because there is one call to the Graphics.draw method and one to the Graphics.fill
method. The resulting SVG elements may look like this:
<rect x="10" y="10" width="100" height="100"
style="fill:none;stroke:red;stroke-width:10.0" />
<rect x="10" y="10" width="100" height="100" style="fill:blue" />
With this technique, exporting graphic objects from the toolkit into
an SVG document consists of calling the Draw method
of each graphic object instance with the specialized java.awt.Graphics parameter.
The Object-oriented approach
The second approach is to take advantage of the object-oriented structure
of the toolkit. The toolkit features Java classes such as rectangles, lines,
polylines, polygons, text, and images. Instead of reusing the 'draw' method
of each class, a specific translation method for each graphic object can be
created.
Since the translation process is specific for each graphic object, the
translation into SVG of a rectangle object will then consist of creating only
one SVG <rect> element (since only one SVG element is required to draw
a rectangle with SVG).
A rectangle filled with blue surrounded with a red line of thickness
10 will be translated into the following SVG element:
<rect x="10" y="10" width="100" height="100"
style="fill:blue;stroke:red;stroke-width:10.0" />
Advantages and disadvantages of the different approaches
The advantages of the first technique are that it is not limited to
a graphics toolkit such as JViews, and can be used for any type of Java tool
that uses Java 2D for drawing. Since this technique does not need to know
the classes of the toolkit, it allows users of the toolkit that define new
classes to take advantage of the SVG generation.
However, this technique leads to several major drawbacks. One such drawback
is that it is not possible to handle images using this technique. In SVG an
image will be pointed to by its URL. In Java, images are handled with the
java.awt.Image class. In many cases there is no URL associated with this image
(because the image is created by some Java code) or there is no way to know
the URL from which the image was loaded.
In addition to the problem of images, the resulting SVG document, when
using the first approach, is likely to be larger in size and more complex
than in the second technique. This is because the first approach does not
take advantage of the notion of graphic objects of the toolkit. By taking
advantage of this notion, you can produce the SVG elements that best fit the
drawings you need. It may become crucial to get the best SVG when you need
to associate scripting with the generated SVG document.
A grouping object can be used to illustrate these differences: Most
2D toolkits provide the ability to group graphic objects together using a
grouping object. This grouping object does not draw anything itself but provides
a way to logically group objects together so that a group of objects can be
manipulated as a single object. If the first technique is used without any
prior knowledge of the graphic objects, the grouping object will not produce
any SVG elements. With the second technique we can produce an SVG grouping
element (the <g> element) and thus mimic the object oriented structure
of the toolkit and allow further scripting to manipulate objects of the group
as a whole.
Another example that illustrates the differences between the two approaches
is the definition of objects that do not zoom. If an object must always keep
the same size in SVG regardless of the zoom level, its coordinates may be
expressed in pixels. This tells the SVG viewer not to zoom the object. Such
behavior cannot be achieved using the first technique, since you need to understand
the internal logic of the graphic object.
Generating SVG in ILOG JViews
The second approach has been chosen for the ILOG JViews Component Suite.
That is, we take advantage of the notion of graphic objects to produce the
most suitable SVG for each graphic object class.
Exporting a JViews drawing in SVG is implemented as a type of output
stream called the SVGOutputStream. To create an SVG document from the toolkit
the user simply creates an SVGOutputStream and writes the contents of the
manager (the JViews data structure that contains the graphic objects) to this
stream.
Compression techniques
When generating SVG documents, the JViews SVGOutputStream uses several
techniques to reduce the size of the SVG documents. The size of the resulting
SVG document is crucial because a small size will allow a fast download. Two
techniques to reduce the size of the SVG document will be discussed:
- Compression of Path Data
- Reusing Styles
Compression of path data
The ‘path’ element of SVG allows you to define any type
of shape. The shape is defined by the ‘d’ attribute of the ‘path’
element. The following example (taken from
[SVG 1.0])
specifies a path in the shape of a triangle. (The shape is expressed by a
set of command letters; the M corresponds to a
moveto, the L’s
indicate a lineto, and the z a closepath).
<path d="M 100 100 L 140 100 L 120 140 z"/>
Compression of the ‘path’ element can take place in the
definition of the path data. There are several techniques to compress the
size of the path data.
First, all non-necessary spaces can be removed. The data is then expressed
as “M100 100L140 100L120 140z”. Then, the letter for the command
can be removed when it is the same as the previous command letter, which leads
to “M100 100L140 100 120 140z”. This does not make a big difference
since a space must then be added.
The most important point for compression is to use the command letter
that will generate the smallest path. The SVG format provides relative versions
of each command (upper case means absolute coordinates, lower case means relative
coordinates). Therefore, when the coordinates are very large but the bounding
area of the shape is small, it is more interesting to use relative coordinates.
The following examples display the same triangle:
<path d="M10000 10000L10004 10004L9996 10004z"/>
<path d="M10000 10000l4 4l-8 0z"/>
Another easy way to compress the path data is to use special command
letters for the horizontal and vertical lines (H and V command letters). This
leads to the following:
<path d="M10000 10000l4 4h-8z"/>
This optimization is interesting in JViews when translating map data
with coordinates that can be expressed as ‘large’ latitudes and
longitudes and that displays only a small area of the world.
These compression techniques are not possible when using the ‘polyline’
element of SVG because the control points of this element are expressed as
a list of absolute points. However, since the ‘polyline’ element
can be easily expressed with a ‘path’ element, another way to
compress is to translate JViews polyline objects into SVG ‘path’
elements.
Reusing styles
In many two-dimensional displays we may find graphic objects that have
the same styling parameters, for example, the same color. In these cases,
the style can be reused and placed in the definition section of the SVG document.
For example, the following SVG document containing two rectangles that
have the same style:
<svg>
<defs />
<rect x="210" y="10" width="100" height="100"
style="fill:blue;stroke:red;stroke-width:2" />
<rect x="10" y="10" width="100" height="100"
style="fill:blue;stroke:red;stroke-width:2" />
</svg>
can be replaced with this one:
<svg>
<defs>
<style>
<![CDATA[
.C0 {fill:blue;stroke:red;stroke-width:2.0}
]]>
</style>
</defs>
<rect x="210" y="10" width="100" height="100" class="C0" />
<rect x="10" y="10" width="100" height="100" class="C0" />
</svg>
This reduces the size of the resulting SVG file when many objects have
the same style. Of course, this operation is optional since re-using the same
style may not be appropriate in all cases.
Part 2: Importing SVG into ILOG JViews
Other than the ability to export SVG files from JViews, it may also
be interesting to have an import feature. There are two main reasons for adding
this import feature to JViews. The first reason is interoperability. With
SVG import added to the export facility, JViews will be able to read documents
built with other software and possibly modify them for external use. The second
reason is that this feature will allow end users to develop SVG-enabled applications
with the library. This means that their web or desktop applications will display
and edit SVG documents without coding effort.
Importing an SVG file into JViews is done in three steps. These steps
are described in this part as follows:
- Create the graphic objects that match the SVG graphic elements.
- Apply a style to these objects.
- Add these graphic objects to the JViews object manager to be able
to display them on the screen.
The first two steps are distinct because SVG separates styles from shapes.
Style is expressed with the CSS syntax while graphic elements are described
using an XML grammar.
Creating JViews graphic objects from SVG Elements
SVG uses an XML grammar to describe its graphic elements. The SVG document
must first be parsed and then the parsed elements must be mapped to JViews
graphic objects.
Parsing an SVG file as an XML file
There are two ways of achieving the parsing. The first one is to parse
the SVG file using a SAX parser and to create JViews graphic objects during
the parsing. The second solution is to parse the SVG file using a DOM parser
that creates a document tree, and then walk on the resulting tree of the document
to create JViews graphic objects.
Although the DOM solution may be slower because it requires two separate
parsings, it has the advantage that it easily allows you to go back and forth
within the document to reach elements referenced by the one currently being
parsed.
This is illustrated in the following example:
<svg>
<use x="0" y="0" width="100" height="100" xlink:href="#ref"/>
<!-- Many other elements -->
<rect id="ref" x="10" y="10" width="100" height="100"/>
</svg>
When creating JViews graphic objects directly during the SAX parsing,
the ‘rect’ element with the ‘ref’ id is not yet available.
With the DOM parser approach, we already have access to the entire tree when
creating the graphic objects. That is why this solution has been chosen as
the import feature for ILOG JViews.
Mapping the parsed elements
This section describes how SVG graphic elements can be mapped to JViews
graphic objects. These graphic objects are drawn using Java 2D primitives.
The following elements are discussed:
- Simple SVG Graphic Elements
- The <text> Element
- The <path> Element
Simple SVG graphic elements
For most SVG graphic elements the translation is very simple.
- <rect> (rectangle) elements can be translated to JViews IlvRectangle.
For example:
<rect x="0" y="0" width="64" height="48"/>
can be translated to the following in Java:
IlvGraphic object = new IlvRectangle(new IlvRect(0, 0, 64, 48));
- <line> to IlvLine
- <polyline> to IlvPolyline
For example:
<polyline points="0 0 64 48 100 100"/>
can be translated to the following in Java:
IlvPoint[] array = new IlvPoint[3];
array[0] = new IlvPoint(0, 0);
array[1] = new IlvPoint(64, 48);
array[2] = new IlvPoint(100, 100);
IlvGraphic object = new IlvPolyline(array);
- <polygon> to IlvPolygon
- <circle> and <ellipse> to IlvEllipse
For example:
<circle cx="0" cy="0" r="10"/>
can be translated to the following in Java:
IlvGraphic object = new IlvEllipse(new IlvPoint(0, 0), 10);
For example:
<image x="0" y="0" width="64" height="48" xlink:href="image.png"/>
can be translated to the following in Java:
IlvGraphic object = new IlvIcon("image.png", new IlvRect(0,0, 64, 48));
- <g> (group of other graphic elements) to IlvGraphicSet
The <text> element
- A default SVG <text> element can be translated to a JViews IlvLabel
object. However the SVG <text> element offers other possibilities not provided
by Java 2D or the ILOG JViews 2D toolkit. For example, <text> objects can
be drawn along an arbitrary path formed by other graphic elements. That is
why the JViews object must be improved to support all <text> capabilities.
- An interesting approach for drawing text on a path in Java 2D is
to define a new java.awt.Stroke object that draws a text stroke on any arbitrary
Java 2D path.
The <path> element
The <path> element also has a counterpart in the JViews library:
the IlvGeneralPath object. This object is based on the Java 2D java.awt.geom.GeneralPath
object.
Here is a simple example of how to create a Java 2D java.awt.geom.GeneralPath
corresponding to an SVG <path> element.
<path d="M100 100L200 200l10 50v10C210 260 180 310 130 300z"/>
can be translated to the following in Java 2D code:
GeneralPath path = new java.awt.geom.GeneralPath();
path.moveTo(100, 100);
path.lineTo(200, 200);
path.lineTo(200+10, 200+50);
path.lineTo(210, 250+10);
path.curveTo(210, 260, 180, 310, 130 300);
path.closePath();
In this example, it appears that the Java 2D matches the <path> element
perfectly. However, in some cases the grammar for defining SVG <path> elements
does not exactly match the attributes necessary to build a Java 2D GeneralPath
object. This is the case for arc segments for example. The start and end points
and the ellipse radii define an SVG arc segment. Java 2D expects the following
parameters to draw an arc segment: the center of the ellipse, the radii, the
start angles, and the delta angles. This is why some computations are necessary
for a correct translation. The equations are available in Appendix F of
[SVG 1.0].
Applying a style to imported graphic elements
The second step when importing an SVG file into JViews is to apply a
style to the imported graphic elements.
Implementing styling is more difficult than simply importing graphic
elements that are described in a pure XML grammar. Style is defined with the
CSS syntax instead of the XML syntax. That is why the first requirement for
importing style is to have a CSS parser in the toolkit to read the CSS syntax.
This is described first. Then, the styles that have been parsed are applied
to the JViews objects using Java 2D.
Parsing styles described with a CSS syntax
Just as a SAX API has been defined for parsing XML, the W3C is currently
defining a SAC API for CSS parsers. However, although reliable SAX implementations
are available (Sun, IBM), SAC implementations are not currently widespread.
That is why ILOG JViews has first implemented its own limited CSS parser
to parse CSS syntax in SVG files. This parser currently implements a limited
set of CSS selectors (selectors allow you to associate a style with an XML
element): the universal selector, the type selector, the ID selector, the
simple class selector, as well as the adjacent, child, and descendant selectors.
Not supported are the attribute selector, the pseudo class selector, the import
rules, and @ rules in general. Consequently, there is no way to include an
external style sheet in the current implementation.
Once read, CSS rule selectors must be compared to SVG graphic elements
to see if they match them. Finally, a cascade must be completed for each matching
CSS rule to determine the final style of each SVG graphic element. These complex
computations are described in
[CSS 2].
Applying the styles to the JViews Object using Java 2D
Once the style of a graphic element has been computed using the cascade,
some style properties will be easy to apply to JViews graphic objects. This
is the case for basic fill options such as the color and its transparency,
basic stroke options such as the width of the stroke, the dash array, and
the join and cap styles. JViews graphic objects already support these features
thanks to the Java 2D API.
For example:
<path d="..." style="fill:red;
fill-opacity:0.5;stroke:blue;
stroke-width:4;stroke-dasharray:2 4;
stroke-linecap:round"/>
This SVG element will be styled using two java.awt.Paint objects and
a java.awt.Stroke object.
Paint fillPaint = new Color(1f, 0f, 0f, 0.5f);
Paint strokePaint = Color.blue;
float[] dasharray = new float[2];
float[0] = 2; float[1] = 4;
Stroke stroke =
new BasicStroke(4,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_MITER,
8, dasharray, 0);
Then the previous pure Java 2D objects are applied to the JViews IlvGeneralPath
object:
path.setFillPaint(fillPaint);
path.setStrokePaint(strokePaint);
path.setStroke(stroke);
More complex styling possibilities require extensions of the JViews
toolkit or even extensions of Java 2D. Both these cases will now be described.
Extension of the JViews Toolkit
Some styling properties require an update of graphic objects to support
already existing Java 2D features not already implemented in the toolkit.
This is the case for clipping of graphic objects for example. In SVG, a graphic
element can be clipped by another one. This feature is available in Java 2D
but not in the JViews toolkit. In this case, it can be implemented by adding
a setClip method on JViews graphic objects.
Extension of Java 2D
However, some other possibilities such as the radial color gradients,
the multiple color linear gradients, or the image filters are not present
in Java 2D and thus cannot simply be added to the JViews objects.
Both gradients have been implemented using the Java 2D java.awt.Paint
interface and return a raster filled with the correct color gradient.
Some SVG image filters can be achieved by implementing the Java 2D java.image.RasterOp
interface. However, the Java 2D filtering mechanism has some limitations.
For example, this mechanism does not support multiple sources. In conclusion,
it is better to use the Java Advanced Imaging API, which is an extension of
the Java Platform and has more filtering capabilities.
Adding the results of parsing to the JViews Object Manager
Once JViews objects have been created and styled from SVG elements,
they are added to the JViews object manager. This manager will draw them on
a Java view in an optimized way. This is the third and final step when importing
an SVG file into JViews.
Some SVG features are very meaningful in an SVG viewer or Internet browser
context, but are not applicable to our import context. Among these requirements,
some can be adapted to the import context while others should be ignored.
For example, the ILOG JViews import feature ignores declared animations
or scripts included in the SVG files. It also ignores metadata or third party
namespace elements.
However, the linking mechanism can be dealt with through the <a>
element. For example:
<a xlink:href="http://www.sample.org/myfile.svg">
<rect x="0" y="0" width="100" height="100"
style="fill:red"/>
</a>
This adds a red rectangle to the JViews manager. When the user clicks
on the rectangle, an object interactor is called and tries to load the referenced
file in the manager.
However, even elements that are ignored should be memorized so that
they can be re-exported later. A user that imports an SVG file into JViews
and modifies it (for example by applying a layout algorithm) does not want
to lose non-recognized elements (for example a piece of script allowing to
interact with the elements) when re-exporting them.
Part 3: Using JViews SVG generation in a thin-client context
The ability to export SVG documents from a two-dimensional framework
in Java (such as JViews) is very interesting in a thin-client context. In
such an architecture, the JViews library is used on the server side to collect
the data of the application and create the appropriate display for the application.
This is done, for example, using the Map package to import map data and the
Graph Layout package to place network information on top of a map. The SVG
generation is then used to publish the graphic to a client.

Figure 2
. Thin-client application using SVG generation
So far, such applications have been done by generating raster images
for the client (JPEG images for example). With SVG, such applications will
get the benefit of vector graphics on the client side. This means a better
drawing quality, the ability to zoom and pan on the client side without requesting
new data from the server, and the ability to interact with individual graphic
objects on the client side.
However, using SVG on the client side raises some problems and questions
for applications that use structured graphics very intensively, such as mapping
applications.
Today, most applications that show maps on the web use images generated
by a map server. Using SVG to draw maps that contain a lot of information
can be difficult because the size of the SVG file may become too big (compared
to an image that has a predictable size). That is why for an application that
needs to display the vectorial information of a map, a mix of images and SVG
will probably be the best solution. The SVG part of the map will then be limited
to elements that require interaction with the user on the client side.
Another difficult problem with applications that display maps is that
the amount of data at different zoom levels is not usually the same. In fact,
the data might be completely different (if your application can zoom from
a world map to the street level for example). In this type of application,
you cannot take full advantage of the zooming capabilities of SVG on the client
side; you have to query the server again when zooming.
The last problem is the notion of layers. This is lacking in SVG. Map
data is always organized in terms of ‘themes’ or ‘layers’.
A layer contains map data of the same type, for example rivers or towns. This
notion gives the ability to hide or show a specific layer easily. Although
this notion does not natively exist in SVG, there are means to implement it.
Objects of the same layer may be grouped in the same SVG group element ‘g’,
allowing you to turn the visibility of the group on or off. They can also
share a common style, which also allows you to turn on or off the visibility
of all elements at once. Finally, another solution can be to generate an SVG
document for each layer and superpose them in the browser.
Since SVG allows us to manipulate individual graphic objects on the
client side, it is natural to think that in applications that display information
that varies over time, such as weather information or alarms in a network
management system, only the dynamic information would need to be updated and
not the static part. This also raises the complex problem of keeping in sync
the SVG document and the server side objects without reloading the full SVG.
In conclusion, we see that the SVG format opens many new opportunities
for applications with complex needs in vector graphics. There are still many
possibilities to explore.
Bibliography