ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


Data-Driven SVG Apps: A Rapid Development Approach

by Pramod Jain
02/13/2002

Scalable Vector Graphics (SVG) is a W3C-recommended standard for Web graphics. It is an XML-based standard for specifying both graphics and content. SVG replaces server-side image file creation or applet-based graphics with client-based rendering of images, and is likely to revolutionize the way Web graphics are rendered, stored, manipulated, and associated with content. This article will focus on a rapid development framework for creating SVG applications that are driven by data supplied from relational databases, EJBs, and/or Java objects.

Although current popular browsers like IE and Netscape do not directly render SVG, Adobe's SVG Viewer, among other plug-ins, will render SVG documents inside of browsers. Since SVG is a W3C standard, it is likely to be supported by future releases of browsers.

The appeal of SVG is that it is data-driven, meaning data contained in an SVG file is used by the Web browser to render graphics and store non-graphical business properties of objects. The article will present a declarative approach to creating such SVG applications. Our sample application will populate the SVG files with data from relational databases, EJBs, and/or Java objects, and update databases with data from SVG files. The declarative approach requires no coding in Java or VB; instead, the application is composed by specifying the data sources, data access, and update methods (SQL, Stored procedures, Java objects), and tag-based, XSL-based, or JSP-based transformations for converting data into an SVG file. This approach can be used for such applications as Web simulation, Web charting, Web reporting, and Web-based image annotation.

The Appeal of SVG

There are several aspects of SVG worth noting. These aspects are presented below with simple examples.

  1. SVG is XML-based, hence data-driven. Take, for example, this simple code to draw a circle:

       <?xml version="1.0" encoding="iso-8859-1"?> ...
       <svg width="800" height="440">
          <circle cx="200" cy="200" r="100"/>
       </svg>

    SVG is data-driven in that, in this example, the center of the circle and its radius are explicitly specified. Unlike bitmap formats such as GIF or JPEG, an SVG file declaratively specifies the properties of a drawing element. In addition, SVG code, like HTML code, is freely browsable. Just right-click on an SVG object, select View Source, and you can view, copy, and edit the code.

  2. SVG is interpreted and rendered by the browser (via a plug-in). Thus a dynamically-updated chart of sales numbers, for instance, can be generated as an SVG XML declaration instead of a GIF or JPEG bitmap. This leads to efficient storage and transfer of Web graphics. SVG also has advantages over applets and ActiveX controls for graphics rendering, since extensive programming is not involved. Generating XML to draw a graphic is a lot simpler than coding graphical elements in a procedural language.

  3. Business content can be associated with a graphic and delivered in XML to the browser. A simple SVG file will illustrate this:

    <svg width="800" height="440">
       <g id="ball">
          <circle cx="200" cy="200" r="100"/>
          <g style="visibility:hidden" 
             desc="ObjectProperty">
             <text>
               <tspan desc="weight">33.0 ounce</tspan>
               <tspan desc="material">rubber</tspan>
               <tspan desc="price">$0.50</tspan>
             </text>   
          </g>
       </g>
    </svg>

    The ball object is rendered in 2D by the browser, and three properties are associated with the ball object. <g> is a group tag. The three properties are accessible through JavaScript by walking through the DOM of SVG. So for example, a JavaScript can display the three values in a input text box when user clicks on the circle; when the user makes a change in the input box, the user-entered data can be updated in the DOM.

    In SVG, therefore, the drawing element and its business properties can be treated as a single object.

  4. Interactivity and animation can be controlled by JavaScript.

    <svg width="800" height="440">
    <g id="ball"
    onmousedown="DoOMD(evt)"
    onmouseup="DoOMU(evt)">
    <circle cx="200" cy="200" r="100"/>
    ...
    </g>
    </svg>

    In this example, when user clicks down on the ball, an event is generated that is processed by the JavaScript function DoOMD(). For animation, consider the following:

    <svg width="800" height="440">
       <g id="ball">
          <circle cx="200" cy="200" r="100">
             <animate begin="click" 
                   attributeName="r" 
                   from="100" 
                   to="200" 
                   dur=1s" 
                   fill="freeze"/>
          </circle>
       </g>
    </svg>

    Here, on mouse click, the radius of the ball increases from 100 to 200 in one second.

  5. From a browser client, a user may not only view and manipulate "business objects," but also create new business objects. The SVG API provides methods to clone elements and insert elements into an existing DOM. So with SVG, a graphics editor can be created in a Web browser and then business properties can be associated with graphic elements.

    Related Reading

    SVG Essentials
    By J. David Eisenberg

    Consider the business example of a building floor plan. The user wants to be able to pull up a digital image (GIF or JPEG file) of the floor plan; review and annotate the drawing to note locations of electrical outlets, phone jacks, and ethernet jacks; and save the changes into a database. Annotations are done by creating red rectangles for electrical outlets, blue rectangles for phone jacks, and green rectangles for Ethernet jacks. In addition to the graphics, the user can specify properties like the number of electrical outlets at the location, the number of phone jacks and the telephone numbers at each location; and the number of Ethernet jacks and the IP addresses at the location.

    For the above example, the appeal of SVG is that an XML document can be created dynamically on the server while pulling content (graphical and business) from a database, while changes made by the user can be updated in the database. This role is traditionally performed by the middle tier. The middle tier, in this case, will create the SVG file by extracting data from database, and parse the SVG file and update the database.

The focus of most SVG applications thus far has been on creating better Web pages using SVG. The focus of this article will be on creating better data-driven business applications. We will use the above example to illustrate how the declarative nature of SVG can be combined with the declarative nature of the middle tier to rapidly deliver scalable applications. With this combination there is little or no Java coding required to build SVG-based enterprise Web applications.

Creating SVG files From Data

A simplistic method of creating an SVG file would be to write Java code that makes calls to the database, gets data, and writes an SVG file. Our approach eliminates Java coding; instead, we use a framework for creating a declarative middle tier that externalizes both database calls and transformation of data from database into SVG. This approach leads to clear separation of data-access logic from presentation logic. Figure 1 depicts this framework.

Diagram.
Figure 1. Framework for SVG middle tier.

The basic tenets of the above framework are:

  1. On command from client, execute data access and update methods on the database or other data sources.
  2. Convert relational and non-relational data returned from step 1 to an Infoset (a generic data model for XML).
  3. Transform the generated infoset to target XML using XSL, JSP, or Tags.

The internals of the middle tier will be described later; however, it is completely controlled by two declarative specifications -- DDS (Declarative data source and Data access methods Specification) and DTS (Declarative Transformation Specification). DDS specifies data sources, access methods, and update methods. The current middle tier supports the following data sources: RDBMS SQL and RDBMS stored procedures, EJBs, and Java objects. Using the API of the middle tier, plug-in modules can be written to interface with other data sources. An example of DDS is provided in the "Data Sources Defined Declaratively" and "Data Access and Update Methods Defined Declaratively" sections of this article.

When the browser makes a request, a request name points to a section of the DDS XML file. This section contains data access or update methods that are executed on the database. The returned data is held in the middle tier as XML Infosets. An example of the data format is presented in the section "Format of the Retrieved Dataset."

This XML data is then transformed using DTS. Transforms currently supported by the middle tier are XSL, JSP, and Tags.

The following code demonstrates how an SVG file is created using data from a database. Our illustration will first describe the desired output, then describe the Tags transformation template file (the DTS file that declaratively specifies how this transformation will be described), and finally, the DDS file and associated XML output format.

Here is an example of a desired SVG file:

<!-- floorplan.svg -->
<svg>
<!--definitions of graphic elements that will be 
   reused
-->
   <defs> 
      <g id="power_def">
         <rect width="10" 
            height="8" 
            style="fill:red"/>
      </g>
      <g id="phone_def">
         <rect width="10" 
            height="8" 
            style="fill:blue"/>
      </g>
      <g id="ethernet_def">
         <rect width="10" 
            height="8" 
            style="fill:green"/>
      </g>
   </defs>
   <g id="drawingCanvas"> 
   <!--Start of drawing canvas -->
      <g id="power1"              <!--element 1-->
         transform="translate(410 212)"> 
         <use xlink:href="#power_def"/> 
                <!--reuse of defs, w transform -->
         <g style="visibility:hidden;" 
            desc="objectProperty">
            <text>
               <tspan desc="number">2</tspan>
            </text>
         </g>
      </g>
      <g id="phone1" 
         transform="translate(430 212)"> 
                                   <!-element 2-->
         <use xlink:href="#phone_def"/>
         <g style="visibility:hidden;" 
            desc="objectProperty">
            <text>
               <tspan desc="number">1</tspan>
               <tspan desc="phone_number">
                  904-555-1212
               </tspan>
            </text>
         </g>
      </g>
      <g id="ethernet1" 
         transform="translate(450 212)"> 
                                 <!-- element 3-->
         <use xlink:href="#ethernet_def"/>
         <g style="visibility:hidden;" 
            desc="objectProperty">
            <text>
               <tspan desc="number">1</tspan>
               <tspan desc="is_address">
                  192.168.1.5
               </tspan>
            </text>
         </g>
      </g>
   </g>
</svg>

Template SVG file

The above SVG file will be created using a tag-based transformation. Input to the tag-based transformation is the following template file.

<!-- floorplanTemplate.svg -->
<svg>
   <!--definitions of graphic elements 
      that will be reused -->
   <defs> 
      <g id="power_def">
         <rect width="10" 
            height="8" 
            style="fill:red"/>
      </g>
      <g id="phone_def">
         <rect width="10" 
            height="8" 
            style="fill:blue"/>
      </g>
      <g id="ethernet_def">
         <rect width="10" 
            height="8" 
            style="fill:green"/>
      </g>
   </defs>
   <g id="drawingCanvas"> 
                   <!--Start of drawing canvas -->
      <!--Begin Loop loop1 -->
         {{gElements}}
      <!--End loop loop1 -->
   </g>
</svg>

Compare the template file to the desired SVG file. All of the drawing elements in the canvas have been replaced with a loop tag loop1. Inside the loop tag is a replacement tag {{gElements}}. The middle tier will transform this template file by replacing loop1 and {{gElements}} with rows of data obtained from data sources. Note in this example that the entire XML code for the element is obtained from the database (a stored procedure may generate this from individual data elements in the database). An alternate method is to return individual data elements from the database and replace them in the template file. The template file, in this case, will be much larger, with all of the XML code (interspersed with replacement tags) for the drawing elements in the canvas.

Data Sources Defined Declaratively

The following is an example of the Oracle database specification in an XML definition:

<!-- section 1 of dds.xml -->
<datasource>
      <name>MyDataBase</name>
      <jdbc_url>jdbc:oracle:127.0.0.1:1521@eawp
      </jdbc_url>
      <user>ME</user>
      <pass>ANY</pass>
</datasource>

The above definition will be used every time MyDataBase is referenced in code.

Data Access and Update Methods Defined Declaratively

Next, we'll examine the data access specifications to gather data from the data source (the Oracle database).

<!-section 2 of dds.xml -->
<dataset> 
  <name>dataset1</name>
  <maindataset>
    <request>
     <javaclass>com.ai.db.DBRequestExecutor1
         </javaclass>
     <datasource>MyDataBase</datasource>
     <stmt> select image_id from annotation</stmt>
    </request>
    <request>
      <javaclass>com.ai.db.DBRequestExecutor1
      </javaclass>
      <datasource>MyDataBase</datasource>
      <stmt>select user_id 
            from users 
            where name="Jane"
            </stmt>
    </request>
    </maindataset>
    <loopdata_request>
      <name>loop1</name>
      <request>
        <javaclass>com.ai.db.DBRequestExecutor1
                                      </javaclass>
        <datasource>MyDataBase</datasource>
        <stmt> select gelements 
               from annotation_detail 
               where 
                  im_id = {image_id} 
                  and uid = {user_id} 
               </stmt>
       </request>
     </loopdata_request>
</dataset>

Notice that image_id and user_id are first obtained in maindataset, and then used in the where clause of loopdata_request select statements.

Using similar constructs, the following example describes how updates are declaratively specified. In addition, transactional guarantees are enforced across multiple requests.

<!--section 3 of dds.xml -->
<update_request>
   <name>update1</name>
     <request>
       <javaclass>com.ai.db.DBRequestExecutor1
                                      </javaclass>
      <datasource>MyDataBase</datasource>
      <stmt>update annotation_detail 
            set gelements={gelem} 
            where    
               im_id = {image_id} 
               and uid = {user_id}</stmt>
     </request>
   <!-- another request -->
     <request>
         <javaclass>com.ai.db.DBRequestExecutor1
                                      </javaclass>
      <datasource>MyDataBase</datasource>
      <stmt>update annotation_detail 
            set gelements={gelem} 
            where 
               im_id = {image_id} 
               and uid = {user_id}
               </stmt>
   </request>
       <redirect_url>http://gohere_onsuccess
                                   </redirect_url>
       <error_redirect_url_on>
           <error_code>error_code</error_code>
           <url>http://...<url>
       </error_redirect_url_on>
<update_request>

Note that gelem, image_id and user_id are passed to this request from the URL.

Format of the Retrieved Dataset

After processing the declarative specifications of data sources and data access methods, the following XML file is created by the middle tier from the data obtained by executing the data access methods.

<!-- Illustration of middle-tier XML output 
   format from data sources -->
<dataset>
   <image_id>8829</ image_id>
   <user_id>22</user_id>
   <loop name="loop1">
      <row>
            <gelements>
               <g id="power1"><use>...</use></g>
            </gelements>
      </row>
      <row>
         <gelements>
            <g id="phone1"><use>...</use></g>
         </gelements>
      </row>
      <row>
         <gelements>
            <g id="ethernet1"><use>...</use></g>
         </gelements>
      </row>
   </loop>
</dataset>

The above XML data structure reflects the way data access methods deliver rows of data. The first two elements of the XML file correspond to the first two select statements in the "Data Access and Update Methods Defined Declaratively" section of this article. The third select statement there delivers data in loop1.

XSL/Tags/JSP-based Transformations to Create SVG

Next, the generic (typeless) XML data structure above must be transformed to the target XML. Again, this is accomplished declaratively by indicating the necessary transformation to the above dataset. Here is an example of Tags-based transformation:

<!--section 3 of dts.xml -->
<target_dataset>
   <source_dataset>
      dataset1
   </source_dataset>
   <transform>
      <javaclass>com.ai.xml.TagTransform
                                      </javaclass>
      <templatefile>floorplanTemplate.svg
                                   </templatefile>
   </transform>
</target_dataset>

Note that dataset1 is the same name used in section 2 of dds.xml. So after the middle tier creates the XML document using the dataset1 specification, dts.xml transforms the XML using the dataset1 specification. As illustrated above, depending on the Java class and the template transformation file (floorplanTemplate.svg), the source data set is transformed to the appropriate output (floorplan.svg).

SVG Tools

Tools are essential for any productive development process. A set of tools that will help SVG development is presented here for each of the following phases.

Manipulate SVG from the browser--Front-end Tier
Adobe's SVGViewer plugin for browser and Adobe's SVG Editor
Retrieve and store SVG in databases--Middle Tier
Aspire/J2EE
Write tools to extend your SVG arsenal --Tool Tier
Batik

SVG Viewer & Editor from Adobe

A browser plug-in, SVG Viewer interprets and renders SVG. For our day-to-day work, the authors use the SVG plug-in from Adobe.

Adobe SVG Viewer makes the DOM representation of the SVG XML available. DOM can be manipulated using JavaScript right in the browser -- nodes in the DOM can be created, updated, or deleted.

More importantly, it allows an event model that can be responded to from JavaScript. This is how regular mouse movements can be used to manipulate graphical objects from the browser. Use SVG Editor to better understand the capabilities.

Batik from Apache

Batik is a Java toolkit for working with SVG content. For example, using Batik, Swing-based graphics can be exported to SVG, or SVG documents can be browsed in a GUI panel powered by AWT or Swing.

One of the stated goals of Batik is to be able to "manipulate SVG documents anywhere Java is available." This is a great benefit -- wherever Java is available. But for a browser environment, it may not directly help in the manipulation of the SVG by the end user. Nevertheless, it could play a role in storing and constructing of the SVG documents from other basic content. For instance, an SVG layer (or group) could be broken apart using this toolkit and saved as individual constructs.

Batik is highly applicable for standalone Java-based IDE environments and also, potentially, as a Java-based applet when the Java Plugin software fully matures and offers a viable alternative to HTML-based applications.

Aspire from INDENT

To develop SVG applications that are driven by databases, the authors' company has developed Aspire. Aspire provides an effective middle tier that is broadly available, and at the same time enables developers to be productive. Aspire is a J2EE-based Java middle tier that allows storage and retrieval of SVG documents in and out of databases with a minimal amount of coding.

Aspire streamlines and makes declarative the process of converting relational data to suitable SVG/XML, as illustrated in this article. This greatly reduces the effort and development time of projects that require the conversion of relational data to XML.

Aspire is not limited to relational data; any kind of data source can be plugged in as long as a Java adapter is written for that source. Aspire provides the APIs to write such adapters.

The target SVG/XML generation can be done using XSL, JSP, Tags, or even a Batik-based transformation. Being a J2EE-based Web development platform, Aspire automatically offers authentication, authorization, session management, and declarative Web navigation.

A high-level architecture diagram for Aspire is presented here. Note that Aspire runs as a servlet-based J2EE engine, it can collect data from multiple data sources using DDS and DTS specifications, and it converts the retrieved data to the target format using any of the user-specified transformations. A demonstration of the system for creating Web-based charts and graphs is available.

Further Reading

Pramod Jain is President of INDENT, Inc. INDENT has developed a data engine for SVG-based charting software.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.