http://xml.apache.org/http://www.apache.org/http://www.w3.org/

Home

Overview
FAQ
License
Download
Install
Demo

In the news

Tools and Apps
Browser
Rasterizer
Font Converter
Pretty-printer

Architecture
Generator
DOM API
Scripting
JSVGCanvas
Transcoder API

Extensions

Testing

Contributors
Mail Lists

CVS Repository
Bug Database

Status

Glossary


Introduction

Batik 1.0 is a static SVG implementation, that's why scripting cannot be used to modify the rendering of the SVG elements on the screen. However you will find below a little introduction on scripting basics, on how it could be useful through an example and on how you can go a little bit further.


Scripting Basics

As it is one of the most popular scripting language and as the SVG specification states that an SVG conforming implementation should support it, the ECMAScript (JavaScript) language is supported in Batik through the Mozilla ECMAScript interpreter called Rhino. Even if it is the only scripting language provided with the Batik standart distribution, other languages such a Python or Tcl can also be supported. All examples in this section will use ECMAScript.

There are two places in an SVG file where you can put scripts.

The first one is in the <script> element where you can put the definition of your functions or some general code to be executed when the element will be read.


<svg width="100" height="100">
  <script type="text/ecmascript">
    // ECMAScript code to be executed 
  </script>
  <!-- Your SVG elements -->
</svg>

You can also put script in respond to user or document events using attributes on SVG elements. As you have seen in previous example, the scripting language must be set on the <script> element, however for event handling the default language type "text/ecmascript" is already set. If you want to change it you can use the contentScriptType attribute on the <svg> element.

In most cases, the event attribute will only call a function defined in a <script> section, however as you can see below it can also contains regular code.


<svg width="100" height="100">
  <rect x="0" y="0" width="10" height="10" 
         onclick="evt.target.setAttribute('fill', 'blue')"/>
  <!-- Your SVG elements -->
</svg>

For more information on using scripting in SVG you can have a look at:


Scripting Uses in Batik

Batik release 1.0 is a static SVG implementation, that's why in this version you can't use scripting to move or change graphic objects on the screen, however it can still be usefull for other purposes.

The following simplified example that you can find in your Batik distribution uses the Java Sound API through scripting to simulate a piano in SVG:


<svg width="420" height="64">
    <defs>
      <style type="text/css">
          #blank {fill:white;stroke:black}
	  #black {fill:black;stroke:black}
      </style>
      <script type="text/ecmascript">
	  importPackage(Packages.javax.sound.midi)
          var midiChannel
          var lastId = -1
	  synthesizer = MidiSystem.synthesizer
	  synthesizer.open()
	  var instruments = synthesizer.defaultSoundbank.instruments
	  // load the first instrument
	  synthesizer.loadInstrument(instruments[0])
          midiChannel = synthesizer.getChannels()[0]
	  midiChannel.programChange(0)

          function down(evt) {
		target = evt.currentTarget
		midiChannel.noteOn(target.id, 64)
	        lastId = target.id
          }

          function drag(evt) {
		if (lastId != -1) {
		  target = evt.currentTarget
		  midiChannel.noteOn(target.id, 64)
		  lastId = target.id
		}
          }
      </script>
      <rect id="blank" x="0" y="0" width="10" height="60"/>
      <rect id="black" x="0" y="0" width="6" height="33"/>
    </defs>
    <g>
      <use onmousedown="down(evt)" onmouseover="drag(evt)" id="24" 
          xlink:href="#blank"/>
      <use onmousedown="down(evt)" onmouseover="drag(evt)" id="26" x="10" 
          xlink:href="#blank"/>
      <use onmousedown="down(evt)" onmouseover="drag(evt)" id="25" x="7" 
          xlink:href="#black"/>
      <use onmousedown="down(evt)" onmouseover="drag(evt)" id="28" x="20" 
          xlink:href="#blank"/>
      <use onmousedown="down(evt)" onmouseover="drag(evt)" id="27" x="17" 
          xlink:href="#black"/>
      <!-- some other keys as in batikMusic.svg from the distribution -->
      <use onmousedown="down(evt)" onmouseover="drag(evt)" id="93" x="400" 
          xlink:href="#blank"/>
      <use onmousedown="down(evt)" onmouseover="drag(evt)" id="92" x="397" 
          xlink:href="#black"/>
      <use onmousedown="down(evt)" onmouseover="drag(evt)" id="95" x="410" 
          xlink:href="#blank"/>
      <use onmousedown="down(evt)" onmouseover="drag(evt)" id="94" x="407" 
          xlink:href="#black"/>
    </g>
</svg>

You can see in the above example that the <script> element contains some code that will be executed when the element is read (the loading of the first instrument in Java Sound bank for example), and also the definition of two functions: down and drag.

These functions will be called thanks to the Batik event handling mechanism in answer to user events. down is registered to listen to mouse down events on the piano keys and drag to listen to mouse over events.

When the user presses the mouse down on a piano key, the down function is called, it gets the SVG element corresponding to the key on which the event listener as been registered (evt.currentTarget) and plays the note corresponding to that key by retrieving it from the ID set on the element (target.id). A similar job is done in the drag function.

To sum up, this sample shows that the Batik 1.0 release is able to handle events and perform some actions in ECMAScript when receiving them. Here the action is to play music with the Java Sound API, it could be other kind of job (logging user actions, performing tasks in answer to user actions...).


Going Further

Batik as an extensible API provides the ability to customize the scripting module to go beyond the simple support of ECMAScript language in SVG files.

Customize the Rhino interpreter

A useful example of cutomization of the Rhino interpreter comes from the fact that the ECMAScript specification doesn't provide any I/O predefined facilities, that's why in the batikMusic.svg example of the distribution we use the Java API from scripting to output messages (System.out.println('...')). However it is very common for ECMAScript compatible languages to provide a function named print to output messages to the console. We will describe here an example of cutomization of the Batik Rhino interpreter to add such functionality to it.

You should first subclass the default Batik ECMAScript interpreter to add the functionality to it as below.


public class ExtendedRhinoInterpreter extends RhinoIntepreter {
    public ExtendedRhinoInterpreter() {
        super(); // build RhinoInterpreter
        final String[] names = { "print" }
        try {
            getGlobalObject().
	            defineFunctionProperties(names, 
	                          ExtendedRhinoIntepreter.class,
                                  ScriptableObject.DONTENUM);
        } catch (PropertyException e) {
            throw new Error(e.getMessage());
        }
    }
    
    public static void print(Context cx, Scriptable thisObj,
                             Object[] args, Function funObj) {
        for (int i=0; i < args.length; i++) {
            if (i > 0)
                System.out.print(" ");
	    
            // Convert the arbitrary JavaScript value into 
            // a string form.
            String s = Context.toString(args[i]);
	    
            System.out.print(s);
        }
        System.out.println();
    }
}

Now, you should tell to Batik to use this interpreter instead of the default one. For that, you should first define a factory to create instances of your interpreter.


public class ExtendedRhinoInterpreterFactory 
  implements InterpreterFactory {
    public Interpreter createInterpreter() {
        return new ExtendedRhinoInterpreter();
    }
}

Then, you should build an IntepreterPool that will use this factory and set the pool on the BridgeContext of your application.


org.apache.batik.bridge BridgeContext ctx = ...;
org.apache.batik.script.InterpreterPool pool =
    new org.apache.batik.script.InterpreterPool();
pool.putInterpreterFactory("text/ecmascript", 
                           new ExtendedRhinoInterpreterFactory());
ctx.setIntepreterPool(pool);

For example if you are using the Batik SVGBrowser application you should be able to use the previous piece of code on a subclass of the JSVGCanvas class in the createBridgeContext() method.


Have your own interpreter

If you want to use SVG files with your own scripting language in it, you can do it with Batik. You will need to define your own class of Interpreter and register it to the InterpreterPool with the right type for the language as in the example above.




Copyright © 2000-2001 The Apache Software Foundation. All Rights Reserved.