blob: 970b2207277b1dbf1b51af6c8948ea0ce970e40b [file] [log] [blame]
<?xml version="1.0"?>
<!DOCTYPE document SYSTEM "./dtd/document-v10.dtd">
<!-- ========================================================================= -->
<!-- Copyright (C) The Apache Software Foundation. All rights reserved. -->
<!-- -->
<!-- This software is published under the terms of the Apache Software License -->
<!-- version 1.1, a copy of which has been included with this distribution in -->
<!-- the LICENSE file. -->
<!-- ========================================================================= -->
<!-- ========================================================================= -->
<!-- author cjolif@ilog.fr -->
<!-- version $Id$ -->
<!-- ========================================================================= -->
<document>
<header>
<title>How to use scripting in Batik?</title>
<authors>
<person name="Christophe Jolif" email="cjolif@ilog.fr"/>
</authors>
</header>
<body>
<s1 title="Introduction">
<p>
Batik 1.1 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.
</p>
</s1>
<s1 title="Scripting Basics">
<p>
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.
</p>
<p>
There are two places in an SVG file where you can put scripts.
</p>
<p>
The first one is in the &lt;script&gt; element where you can put the
definition of your functions or some general code to be executed when the
element will be read.
</p>
<source>
&lt;svg width="100" height="100"&gt;
&lt;script type="text/ecmascript"&gt;
// ECMAScript code to be executed
&lt;/script&gt;
&lt;!-- Your SVG elements --&gt;
&lt;/svg&gt;</source>
<p>
You can also put script in response to user or document events using attributes on SVG elements. As shown in the previous example, the scripting language must be set on the &lt;script&gt; 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 &lt;svg&gt; element.
</p>
<p>
In most cases, the event attribute will only call a function defined in a &lt;script&gt; section, however as you can see below it can also contains regular code.
</p>
<source>
&lt;svg width="100" height="100"&gt;
&lt;rect x="0" y="0" width="10" height="10"
onclick="evt.target.setAttribute('fill', 'blue')"/&gt;
&lt;!-- Your SVG elements --&gt;
&lt;/svg&gt;</source>
<p>For more information on using scripting in SVG you can have a look at:</p>
<ul>
<li><link href="http://www.w3.org/TR/SVG/script.html">scripting chapter of SVG specification</link> for advanced information on scripting in SVG.</li>
<li><link href="http://www.ecma.ch/ecma1/stand/ecma-262.htm">ECMAScript specification</link> for advanced information on ECMAScript language.</li>
</ul>
</s1>
<s1 title="Scripting Uses in Batik">
<p>Batik release 1.1 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.</p>
<p>The following simplified example that you can find in your Batik distribution displays a simple message in response to user events:</p>
<source>
&lt;svg width="450" height="500" viewBox="0 0 450 500"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;script type="text/ecmascript"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;function showDialog(msg) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(msg);
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&lt;g&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;circle cx="137.5" cy="110" r="20" style="fill:crimson" onmousedown="showDialog('onmousedown')"/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;circle cx="312.5" cy="110" r="20" style="fill:crimson" onmouseup="showDialog('onmouseup')"/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/g&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;g transform="translate(0 80)"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;circle cx="137.5" cy="110" r="20" style="fill:crimson" onmouseover="showDialog('onmouseover')"/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;circle cx="312.5" cy="110" r="20" style="fill:crimson" onmouseout="showDialog('onmouseout')"/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/g&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;g transform="translate(0 160)"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;circle cx="137.5" cy="110" r="20" style="fill:crimson" onmousemove="showDialog('onmousemove')"/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;circle cx="312.5" cy="110" r="20" style="fill:crimson" onclick="showDialog('onclick')"/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/g&gt;
&lt;/svg&gt;
</source>
<p>
You can see in the above example that the &lt;script&gt; element contains
the definition of a single function: <code>showDialog</code>.
</p>
<p>
This function will be called thanks to the Batik event handling mechanism in answer to
user events. The function is registered to listen to mouse events on the various &lt;circle&gt;
elements.
</p>
</s1>
<s1 title="Going Further">
<p>
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.
</p>
<s2 title="Customize the Rhino interpreter">
<p>
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 to interact with
the console . However it is very common for ECMAScript compatible languages to provide
a function named <code>print</code> 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.
</p>
<p>
You should first subclass the default Batik ECMAScript interpreter to add the functionality
to it as below.
</p>
<source>
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 &lt; args.length; i++) {
if (i &gt; 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();
}
}</source>
<p>
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.
</p>
<source>
public class ExtendedRhinoInterpreterFactory
implements InterpreterFactory {
public Interpreter createInterpreter() {
return new ExtendedRhinoInterpreter();
}
}</source>
<p>
Then, you should build an <code>IntepreterPool</code> that will use this factory
and set the pool on the <code>BridgeContext</code> of your application.
</p>
<source>
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);</source>
<p>
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 <code>JSVGCanvas</code> class
in the <code>createBridgeContext()</code> method.
</p>
</s2>
<s2 title="Have your own interpreter">
<p>
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 <code>Interpreter</code> and register it
to the <code>InterpreterPool</code> with the right type for the language as in the example
above.
</p>
</s2>
</s1>
</body>
</document>