






































|
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.
|
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...).
|
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.
|
|
|
|