| <?xml version="1.0"?> |
| <!DOCTYPE document SYSTEM "./dtd/document-v10.dtd"> |
| |
| <!-- |
| |
| Copyright 2002-2004 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 shillion@ilog.fr --> |
| <!-- version $Id$ --> |
| <!-- ========================================================================= --> |
| <document> |
| <header> |
| <title>Scripting With Java</title> |
| <authors> |
| <person name="Stephane Hillion" email="shillion@ilog.fr"/> |
| <person name="Thomas DeWeese" email="deweese@apache.org"/> |
| </authors> |
| </header> |
| |
| <body> |
| <s1 title="Introduction"> |
| <p> |
| This section explains how to manipulate the DOM tree of an SVG |
| document from a Java program. It contains the following |
| sub-sections: |
| </p> |
| |
| <ul> |
| <li><link href="#Swing" |
| >How to manipulate a JSVGCanvas' document?</link></li> |
| <li><link href="#Threads" |
| >How to write thread-safe code?</link></li> |
| <li><link href="#SVGDOM" |
| >Using the SVG DOM</link></li> |
| <li><link href="#Extension"> |
| How to run Java code using a <script> element?</link></li> |
| </ul> |
| </s1> |
| |
| <anchor id="Swing"/> |
| <s1 title="How to manipulate a JSVGCanvas DOM document"> |
| <p> |
| The follow code template demonstrates how to manipulate an SVG |
| document displayed in a JSVGCanvas directly from a Java program. |
| </p> |
| <note>You don't have to worry about graphics updates: |
| after each event listener invocation the canvas is updated |
| if needed.</note> |
| <source> |
| import java.awt.event.WindowAdapter; |
| import java.awt.event.WindowEvent; |
| import javax.swing.JFrame; |
| import org.apache.batik.swing.JSVGCanvas; |
| import org.apache.batik.swing.svg.SVGLoadEventDispatcherAdapter; |
| import org.apache.batik.swing.svg.SVGLoadEventDispatcherEvent; |
| import org.apache.batik.script.Window; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.events.Event; |
| import org.w3c.dom.events.EventListener; |
| import org.w3c.dom.events.EventTarget; |
| |
| public class SVGApplication { |
| public static void main(String[] args) { |
| new SVGApplication(); |
| } |
| |
| JFrame frame; |
| JSVGCanvas canvas; |
| Document document; |
| Window window; |
| |
| public SVGApplication() { |
| frame = new JFrame(); |
| canvas = new JSVGCanvas(); |
| // Forces the canvas to always be dynamic even if the current |
| // document does not contain scripting or animation. |
| canvas.setDocumentState(JSVGCanvas.ALWAYS_DYNAMIC); |
| canvas.addSVGLoadEventDispatcherListener |
| (new SVGLoadEventDispatcherAdapter() { |
| public void svgLoadEventDispatchStarted |
| (SVGLoadEventDispatcherEvent e) { |
| // At this time the document is available... |
| document = canvas.getSVGDocument(); |
| // ...and the window object too. |
| window = canvas.getUpdateManager(). |
| getScriptingEnvironment().createWindow(); |
| // Registers the listeners on the document |
| // just before the SVGLoad event is |
| // dispatched. |
| registerListeners(); |
| // It is time to pack the frame. |
| frame.pack(); |
| } |
| }); |
| |
| frame.addWindowListener(new WindowAdapter() { |
| public void windowOpened(WindowEvent e) { |
| // The canvas is ready to load the base document |
| // now, from the AWT thread. |
| canvas.setURI("doc.svg"); |
| } |
| }); |
| |
| frame.getContentPane().add(canvas); |
| frame.setSize(800, 600); |
| frame.show(); |
| } |
| |
| public void registerListeners() { |
| // Gets an element from the loaded document. |
| Element elt = document.getElementById("elt-id"); |
| EventTarget t = (EventTarget)elt; |
| |
| // Adds a 'onload' listener |
| t.addEventListener("SVGLoad", new OnLoadAction(), false); |
| |
| // Adds a 'onclick' listener |
| t.addEventListener("click", new OnClickAction(), false); |
| } |
| |
| public class OnLoadAction implements EventListener { |
| public void handleEvent(Event evt) { |
| // Make some actions here... |
| |
| // ...for example start an animation loop: |
| window.setInterval(new Animation(), 50); |
| } |
| } |
| |
| public class OnClickAction implements EventListener { |
| public void handleEvent(Event evt) { |
| // Make some actions here... |
| |
| // ...for example schedule an action for later: |
| window.setTimeout(new DelayedTask(), 500); |
| } |
| } |
| |
| public class Animation implements Runnable { |
| public void run() { |
| // Insert animation code here... |
| } |
| } |
| |
| public class DelayedTask implements Runnable { |
| public void run() { |
| // Make some actions here... |
| |
| // ...for example displays an alert dialog: |
| window.alert("Delayed Action invoked!"); |
| } |
| } |
| } |
| </source> |
| </s1> |
| |
| <!-- #################################################### --> |
| |
| <anchor id="Threads"/> |
| <s1 title="Writing thread-safe code"> |
| <p> |
| The DOM listeners registered on the SVG document are called from |
| the canvas update thread. To avoid race conditions do not manipulate |
| the DOM tree from another thread.<br/> |
| The way to switch from an external thread to the canvas update |
| thread is to use the following code: |
| </p> |
| <source> |
| // Returns immediately |
| canvas.getUpdateManager().getUpdateRunnableQueue(). |
| invokeLater(new Runnable() { |
| public void run() { |
| // Insert some actions on the DOM here |
| } |
| }); |
| |
| - or - |
| |
| // Waits until the Runnable is invoked |
| canvas.getUpdateManager().getUpdateRunnableQueue(). |
| invokeAndWait(new Runnable() { |
| public void run() { |
| // Insert some actions on the DOM here |
| } |
| }); |
| </source> |
| <p>Like with event listeners, when a Runnable is invoked from the |
| update thread, the graphics are updated. |
| </p> |
| <note>It is very dangerous to call 'invokeAndWait' from the |
| Swing Event thread. This is the only thread that can be |
| used to interact with Swing components. In some cases |
| DOM calls may need to query the canvas for information |
| (such as actual Swing component size etc). If this |
| happens you will get a thread deadlock. You should |
| only make invokeAndWait calls from 'third party' threads. |
| </note> |
| </s1> |
| |
| <!-- #################################################### --> |
| |
| <anchor id="SVGDOM"/> |
| <s1 title="Using the SVG DOM"> |
| <p> |
| Batik provides a fairly complete implementation of the |
| SVG DOM. The SVG DOM provides all the functionality most |
| applications require. In particular the DOM implements |
| DOM Events including mutation and UI Events. |
| </p> |
| <p> |
| DOM events allow you to get notified when the cursor |
| moves over elements of interest: |
| </p> |
| <source> |
| // Element of Interest. |
| Element theElem; |
| ((EventTarget)theElem).addEventListener("mouseover", mouseOverListener, true); |
| </source> |
| <p> |
| Where <tt>mouseOverListener</tt> implements the |
| <tt>org.w3c.dom.events.EventListener</tt> interface. |
| This interface consists of the method: |
| </p> |
| <source> |
| public void handleEvent(Event evt); |
| </source> |
| <p> |
| This is called whenever the event occurs with the |
| element it is registered on. It is worth reviewing the |
| DOM Events specification as there are many useful features |
| to this interface that are not immediately obvious. |
| </p> |
| <p> |
| It is also worth looking at the DOM interfaces defined |
| by the SVG specification as they provide a large number |
| of useful methods, in particular the SVGLocatable: |
| </p> |
| <source> |
| // Returns Bounding box of SVG Element. |
| public SVGRect getBBox ( ); |
| // Returns the transformation matrix to the screen. |
| public SVGMatrix getScreenCTM ( ); |
| // Returns the transformation matrix to the given element. |
| public SVGMatrix getTransformToElement ( SVGElement element ) |
| throws SVGException; |
| </source> |
| <p> |
| In particular <tt>getScreenCTM</tt> is very useful for |
| taking the 'clientX', 'clientY' attributes of the |
| DOM UIEvent and mapping them to the coordinate system |
| of an element in the SVG document: |
| </p> |
| <source> |
| SVGMatrix mat = elem.getScreenCTM(); |
| SVGMatrix imat = mat.inverse(); |
| SVGPoint cPt = document.getRootElement().createSVGPoint(); |
| cPt.setX(uiEvt.clientX); |
| cPt.setY(uiEvt.clientY); |
| cPt = cPt.matrixTransform(imat); |
| </source> |
| </s1> |
| |
| <!-- #################################################### --> |
| |
| <anchor id="Extension"/> |
| <s1 title="Alternate way to manipulate an SVG document"> |
| <p> |
| Batik provides an extension of the SVG |
| <code><script></code> element which allows Java programs |
| to be called from an SVG document. |
| |
| This feature is available to any application of Batik that uses |
| the bridge module (for example the Swing component and the |
| transcoders). |
| </p> |
| |
| <p> |
| |
| In order to use this extension, the <code>type</code> attribute |
| of a <script> element must be set to |
| <code>application/java-archive</code>. In addition the |
| <code>xlink:href</code> attribute must be the URI of a jar file |
| which contains the program to run. |
| |
| The manifest of this jar file must contains an entry of the form: |
| <br/><br/> |
| <code>SVG-Handler-Class: </code><em>classname</em><br/><br/> |
| |
| Where <em>classname</em> must be the name of a class which |
| implements the |
| <code>org.w3c.dom.svg.EventListenerInitializer</code> interface. |
| See the javadoc of this interface for more details. |
| <br/> |
| |
| The class can be contained directly in the jar file, but it is |
| also possible for it to be contained in a jar file added to the |
| classpath using the <code>Class-Path</code> entry of the |
| manifest. |
| |
| </p> |
| </s1> |
| |
| </body> |
| </document> |