blob: 4db2c0886e07251447a35e5bed6999fc8d7509a0 [file] [log] [blame]
<?xml version="1.0"?>
<!DOCTYPE document SYSTEM "./dtd/document-v10.dtd">
<!--
Copyright 2001-2003 The Apache Software Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- ========================================================================= -->
<!-- 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>
What follows is a little introduction to scripting
basics, an example of how it could be useful
and ways to go a little bit further.
</p>
<ul>
<li><link href="#scriptingBasics">Scripting Basics</link></li>
<li><link href="#howToUseScripting">How to use Scripting in Batik</link></li>
<li><link href="#goingFurther">Going Further</link></li>
<ul>
<li><link href="#customizeRhino">Customize the Rhino interpreter</link></li>
<li><link href="#haveYourOwn">Have your own interpreter</link></li>
</ul>
</ul>
</s1>
<anchor id="scriptingBasics"/>
<s1 title="Scripting Basics">
<p>
As the ECMAScript (JavaScript) language is one of the
most popular scripting language and as the SVG
specification states that an SVG conforming
implementation must support it, the ECMAScript language
is supported in Batik through the Mozilla ECMAScript
interpreter called
<link href="http://www.mozilla.org/rhino/bsf.html">Rhino</link>
(<code>js.jar</code> ). Even if it is the only
scripting language provided with standard with the Batik
distribution, other languages such a Python or Tcl can
also be <link href="install.html#optionalComponents">
supported</link>.
</p>
<p><strong>Note:</strong>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 <code>&lt;script&gt;</code>
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 "<code>text/ecmascript</code>" is already set.
If you want to change it you can use the <code>contentScriptType</code> attribute on the <code>&lt;svg&gt;</code> element.
</p>
<p>
In most cases, the event attribute will only call a function defined in a <code>&lt;script&gt;</code>
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>
<anchor id="howToUseScripting"/>
<s1 title="How to use Scripting in Batik">
<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;/script&gt;
&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"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;onmousedown="showDialog('onmousedown')"/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;circle cx="312.5" cy="110" r="20" style="fill:crimson"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;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"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;onmouseover="showDialog('onmouseover')"/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;circle cx="312.5" cy="110" r="20" style="fill:crimson"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;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"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;onmousemove="showDialog('onmousemove')"/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;circle cx="312.5" cy="110" r="20" style="fill:crimson"
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;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 <code>&lt;script&gt;</code> 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 <code>&lt;circle&gt;</code>
elements.
</p>
</s1>
<anchor id="goingFurther"/>
<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>
<anchor id="customizeRhino"/>
<s2 title="Customize the Rhino interpreter">
<p>
A useful example of customization 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>
<anchor id="haveYourOwn"/>
<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>