Articles / A Common Design for Vector …

A Common Design for Vector Graphics GUI Components

There are many GUI components available which can be used to display vector graphics and animation. Most of them are dedicated to particular classes of vector images such as graphs, business diagrams, SVG images, geographic maps, technical drawings, and financial charts. Unfortunately, it is not yet always possible to find a suitable component for a particular application which satisfies price, licensing, scalability, performance, stability, feature availability, and other requirements. And if one wants to add vector-based visualization to an existing application, additional requirements of integration ability arise.

1. Introduction

So, from time to time, developers have to implement their own components. A good way to create a new component is to get an existing one and adapt it. If the original component is clearly designed and not too complex, the modifications should be quite simple. But in the real world, this way is not always acceptable. The license of the component may prohibit modifications, source code might not be available, or its quality may not be good enough. Even if the component is clearly designed and its license permits you to modify the source code, it is not always possible to satisfy all the requirements using only small changes. Scalability, performance, stability, or integration ability cannot be easily improved in most cases. In the worst case, the developer has no option but to create a totally new component from scratch.

The goal of this article is to present a common design for GUI components that are intended to display vector-based images. A public domain implementation of this design written in the Java language can be obtained from http://jdrawing.sourceforge.net/. This implementation can be used as a starting point for development of custom components.

2. Overview

In this article, the term "vector-based image" means an image that is a result of a known sequence of simple painting operations. The set of allowed simple operations depends on concrete application.

When image areas affected by several painting operations overlap each other, the sequential order of execution of such operations can be important. However, in some cases, the same set of operations executed in different sequential orders can produce the same image. This makes it possible to use a weakly-ordered set of painting operations to represent a vector-based image rather than the exact sequence.

The easiest way to display a vector-based image is to perform all corresponding painting operations one by one in a suitable order. While this approach is widely used, it is not effective. Let's consider a large vector-based image displayed inside a small scrollable window. When a user scrolls the window, small pieces of the image should be updated frequently. Performing all painting operations at every update, while most of them do not affect the wasted region at all, can produce significant overhead. The design presented in this article makes it possible to use different caching techniques to speed screen updates. These techniques can be implemented independently from the data model of the image and can be replaced at runtime.

An important question is how to represent painting operations in terms of a programming language. Many of the object-oriented graphics frameworks use the following approach: They define a special interface that contains all methods necessary to perform painting operations, such as "draw", "getBounds", etc. Each painting operation is represented by an object that implements this interface. This kind of representation of painting operations is called self-renderable because the representation itself can perform the corresponding operation. The main disadvantage of this approach is that all information necessary to perform an operation should be available via its representation. While this sounds like an obvious solution, it can be inconvenient in some cases. Let's consider a GIS application, which displays geographic maps. A map data model consists of objects that represent geographical entities such as roads, cities, etc. Each object stores the location of the corresponding entity using a geographical coordinate system based on latitude and longitude values. To paint a map on a plain surface such as a computer screen, some kind of projection from geographical coordinates into plain rectangular coordinates should be used. So, the information about attributes of the projection is necessary to paint a geographical entity. If this information will be available via the representing object of the entity, then it will be hard to display the same map in different projections simultaneously, because the same objects should use different projection settings while being rendered in different views.

The following approach can help in the case described above. The projection attributes are stored inside an additional object that is not a part of the data model of the map. This object implements a special interface that contains methods like "draw" and "getBounds". These methods accept an additional argument that specifies a painting operation in the subject. For each view of the map, a separate object with its own projection settings can be used. In this article, such an additional object is called an "element renderer". The design of the component presented in this article is based on the second approach, but the first approach can still be emulated via a special element renderer.

3. Design basics

All functions of the component are distributed between the following objects: control, data model, data model cache, and element renderer. The control is responsible for the flow of execution of all other elements and the communication with the GUI framework. The data model maintains information about vector-based images. The same data model object can be shared between several control elements. The data model cache encapsulates optimization algorithms. The element renderer is responsible for the execution of painting operations in the process of image construction. All listed objects communicate via simple interfaces and can be independently replaced. Below, you shall find a description of all interfaces and the structure of the named objects.

3.1 Control

The interfaces implemented by this object depend on the underlying GUI framework. For example, if the underlying GUI framework is Swing for Java, control should inherit the class JComponent. When some part of the image should be updated, control refers to the data model cache to determine which painting operations affect the wasted region, as well as to the element renderer to perform these operations.

3.2 Data model

The data model is a wrapper for storage of image data. It allows one to obtain all painting operations of the image and to sort a given set of operations in such a way that all overlapping operations are properly arranged. The Java implementation requires the following methods to be implemented by the data model object:

  Enumeration elements ()
  void sortElements (Object [] elements)

Upon changes applied to the set of operations or their execution order, the data model sends appropriate signals to the data model cache.

3.3 Data model cache

The data model cache is an object that encapsulates optimization algorithms. It allows one to perform the following operations effectively:

  • Find all painting operations affecting a given point
  • Find all painting operations affecting a given rectangle
  • Compute the bounding box for the whole image

The Java implementation requires the following methods to be implemented by the data model cache:

  Object[] getElementsForPoint (Point2D point)
  Object[] getElementsForRectangle (Rectangle2D rectangle)
  Rectangle getModelBounds ()
  Rectangle2D getModelBounds2D ()

In the process of execution of these methods, all the required information is retrieved from the data model and the element renderer objects. To increase performance, some information may be cached inside the data model cache.

Upon receiving a notification about changes inside the data model, the data model cache calculates the boundary of the region to be redrawn, updates cached information, and sends an appropriate signal to the control.

3.4 The element renderer

This object is responsible for execution of operations required for the construction of the image. Besides that, it is capable of calculating the boundary boxes of given operations and checking whether an operation affects a given point or rectangle. This functionality is implemented via the following methods:

  boolean elementContains (Object element, Point2D point)
  boolean elementIntersects (Object element, Rectangle2D rectangle)
  Rectangle getElementBounds (Object element)
  Rectangle2D getElementBounds2D (Object element)
  void paintDrawingElement (Graphics graphics, Object element)

4. How it works

In this section, we shall demonstrate the use of the component in a Java program. First and foremost, the structure of the data model has to be determined. The elements of the model have to be determined, as well as a means of their storage. The selection of a set of elements is a key step in the development of data models. An ideal element set selection will provide elements that:

  • Are atomic in terms of the subject area
  • Are relatively small in size to provide more effective repainting

In cases in which the two criteria cannot be simultaneously satisfied, it may be possible to apply to notion of compound elements (see below).

4.1 Model structure

The storage of elements inside a data model can have different implementation approaches. The existing implementation contains the following standard models: DefaultDrawingModel, responsible for storing the elements in an unsorted fashion, and LayeredDrawingModel, which allows one to assign a layer index to each element.

4.2 The element painting process

Once the model structure is given, one has to decide how the elements shall be displayed. The following possibilities exist:

  • To use self-renderable elements
  • To use an external element renderer
  • To use compound elements

4.2.1 Self-renderable elements

In this case, the functionality required for the output of an element is encapsulated inside the element. In Java, the implementation requires that an interface DrawingElement is implemented by the object. This interface includes the following methods:

  boolean contains (Point2D point)
  Rectangle getBounds ()
  Rectangle2D getBounds2D ()
  boolean intersects (Rectangle2D rectangle)
  void paint (Graphics graphics)

This approach is applicable in cases in which the output procedure of an element is uniquely determined by its type and attributes. This usually holds for elements which represent graphical constructs, i.e. geometrical figures.

4.2.2 An element renderer

In this case, the element renderer incorporates the functionality required for the painting of all elements of arbitrary types. This approach is most useful when the data stored inside an element does not contain enough to paint the element, or when an off-memory model is used.

4.2.3 Compound elements

In this case, the set of operations required to paint an element is distributed between several smaller objects. In Java, one should implement the interface CompoundDrawingElement inside the object; this interface includes one method:

  Enumeration elements ()

This method allows one to obtain a list of all elements which form the compound element. This approach should be used when the graphical representation of the object is complex. The painting operations related to each element in the compound object may be implemented in any of the described ways.

4.3 Optimization

Once the data model is built and the painting operations are implemented, one should think about optimization. The Java implementation offers two standard optimization algorithms inside the classes GridDrawingModelCache and QuadTreeDrawingModelCache. When used, these algorithms can significantly increase the execution speed of the component at the cost of more memory consumption. The implementation architecture allows one to replace the optimization algorithm on the fly, as well as to use new algorithms.

4.4 Off-memory and indexed models

In GIS and some other applications, very big images consisting of millions of elements can be used. Storing the complete description of such images in virtual memory is not reasonable. A relational database or some other external storage can be used instead. In this case, operations will be represented by the identifiers of the corresponding records in the storage. The element renderer retrieves the actual data record when it has to perform an operation.

This approach can make standard optimization algorithms ineffective because they cannot utilize advanced features of the external storage such as database indexes. The Java implementation supports a concept of indexed data models that helps to deal with this problem. An indexed data model is a data model which implements two additional methods:

  Enumeration elements (Point2D point)
  Enumeration elements (Rectangle2D rectangle)

These methods are used to enumerate operations that affect given point or rectangle, respectively. These methods can use all the features of the external storage.

5. Conclusion

The main advantages of the proposed design are the following:

  • Data storage, image rendering, and optimization are clearly separated.
  • It is possible to share the same data storage between several views.
  • The component can be easily integrated into existing applications because there are no limitations applied to representation of image data.
  • It is possible to optimize updates of large and complex images.

This design was implemented in the Java language using the Swing GUI framework. The implementation is a JDrawing component. The documentation and source code of this component can be used as an additional source of information about the design described in this article.

6. Similar projects

6.1 JGraph

http://freshmeat.net/projects/jgraph/

JGraph is the most powerful, lightweight, feature-rich, and thoroughly documented Open Source graph component available for Java. It is accompanied by JGraphpad, the first free diagram editor for Java that offers XML, Drag-and-Drop, and much more!

With the JGraph zoomable component, you can display objects and relations (networks) in any Swing UI. JGraph can also be used on the server side, for example to read a GXL graph, apply a custom layout algorithm, and return the result as an HTML image map.

6.2 OpenJGraph

http://freshmeat.net/projects/openjgraph/

OpenJGraph is an Open Source Java library for creating and manipulating graphs and graph drawings.

Its current features include:

  • Directed, undirected, directed acyclic, and weighted graphs.
  • Simple graph algorithms, such as graph traversal, minimum spanning tree, and shortest path spanning trees for weighted graphs.
  • Basic graph drawing, including straight line and orthogonal graph drawing. (However, more work still needs to be done here.)
  • User interaction, such as creating and removing a vertex, creating and removing an edge, dragging a vertex, and changing some of the vertex and edge properties.

6.3 Magelan

http://freshmeat.net/projects/magelan/

Magelan provides a library of easy-to-use 2D graphics editor tools and a functional and extensible stand-alone graphics editor.

6.4 JChart

http://www.ilpiola.it/roberto/jchart/index_e.html

JChart is a good piece of code by Roberto Piola. It was born as an applet for displaying some data on a Web page, in a manner similar to what gnuplot does on any machine (and MS Excel does on a PC): histograms, plots, etc.

It was later extended, reducing the core of JChart to a reusable component and obtaining an applet and a stand-alone application as by-products. Data can be passed to it as a filename, as a data structure, or as a URL, and can be visualized in several ways.

6.5 Batik

http://freshmeat.net/projects/batik/

Batik is a Java-based toolkit for applications or applets that want to use images in the Scalable Vector Graphics (SVG) format for various purposes, such as viewing, generation, or manipulation.

The project's ambition is to give developers a set of core modules which can be used together or individually to support specific SVG solutions. Examples of modules are the SVG Parser, the SVG Generator, and the SVG DOM. Another ambition is to make it highly extensible (for example, Batik allows the developer to handle custom SVG tags). Even though the goal of the project is to provide a set of core modules, one of the deliverables is a full-fledged SVG browser implementation which validates the various modules and their interoperability.

Recent comments

11 Oct 2004 14:16 Avatar botik32

Some more vector toolkits

Piccolo is a nice zooming vector graphics toolkit. However, it is not free for business use.

Another zooming graphics toolkit is cZUI (http://czui.sourceforge.net), it is written in C++ and subject to GPL.

11 Oct 2004 13:45 Avatar billcarlson

Re: License


> README.txt file inside package contains

> this information.

The point is that licensing information should be on the site. Having to download and then examine the distribution/package just to find out the licensing terms wastes time and bandwidth.

09 Oct 2004 14:54 Avatar mvladimirov

Re: License


> I could not find the license of the

> stuff on http://jdrawing.sourceforge.net

> ---even if it is said in the article

> that the material is in the public

> domain.

README.txt file inside package contains this information.

09 Oct 2004 07:34 Avatar FilippoRusconi

license (follow up)
And now I stumble on this:

Using JChart

The component classes are released in Java byte-code form for personal use, and NOT for commercial use. If you need the source code for personal use, you MUST sign a non-disclosure agreement and send it via fax at +39(0)11 3473522. If you want to use my program for making money, it will cost you 200 US$; in this case, or if you need a modified version, you should contact me.

(from one of the examples mentioned by the author of parent article: http://www.ilpiola.it/roberto/jchart/index_e.html).

How about Free Software?

FR

09 Oct 2004 01:23 Avatar FilippoRusconi

License
It should not take more than one minute to find the licensing of a piece of software from that software's web page.

I could not find the license of the stuff on http://jdrawing.sourceforge.net ---even if it is said in the article that the material is in the public domain.

See http://www.polyxmass.org/ for an example :-)

FR

Screenshot

Project Spotlight

Kigo Video Converter Ultimate for Mac

A tool for converting and editing videos.

Screenshot

Project Spotlight

Kid3

An efficient tagger for MP3, Ogg/Vorbis, and FLAC files.