Hello,
I want to have an object moved along a path using the animateMotion element. This works pretty well, but if I extend the path during animation the modification is not recognized and the object keeps on moving the original path.

Here's the code:
package scripting.java;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;

import org.apache.batik.bridge.UpdateManager;
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.batik.dom.svg.SVGOMAnimateMotionElement;
import org.apache.batik.dom.svg.SVGOMAnimatedPathData;
import org.apache.batik.dom.svg.SVGOMDocument;
import org.apache.batik.dom.svg.SVGOMElement;
import org.apache.batik.dom.svg.SVGOMPathElement;
import org.apache.batik.dom.svg.SVGOMSVGElement;
import org.apache.batik.swing.JSVGCanvas;
import org.apache.batik.swing.gvt.GVTTreeRendererAdapter;
import org.apache.batik.swing.gvt.GVTTreeRendererEvent;
import org.apache.batik.util.RunnableQueue;
import org.apache.batik.util.XMLConstants;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.svg.SVGPathSeg;
import org.w3c.dom.svg.SVGPathSegList;

/**
*
*/

/**
* @author Nicky Nubbel
*
*/
public class Test2 extends JFrame implements MouseListener {

/**
* serial version uid
*/
private static final long serialVersionUID = 1L;

/**
* @param args
*/
public static void main(String[] args) {
new Test2();
}

private JSVGCanvas canvas;
protected SVGOMDocument doc;
final DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
final String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
final String xlinkNS = XMLConstants.XLINK_NAMESPACE_URI;
protected UpdateManager updateManager;
private SVGOMElement plane;
private SVGOMPathElement path;
private SVGOMAnimateMotionElement anim;
private SVGOMSVGElement svgRoot;
protected RunnableQueue queue;

/**
* constructor
*/
public Test2() {
super("Test 2: Animation along an extensible path");
setDefaultCloseOperation(EXIT_ON_CLOSE);

canvas = new JSVGCanvas();
canvas.setDocumentState(JSVGCanvas.ALWAYS_DYNAMIC);

addWindowListener(new WindowAdapter() {
public void windowOpened(WindowEvent e) {
System.out.println("window opened");
createDocument();
canvas.setDocument(doc);
}
});

canvas.addGVTTreeRendererListener(new GVTTreeRendererAdapter() {
public void gvtRenderingCompleted(GVTTreeRendererEvent e) {
System.out.println("renderering completed");

updateManager = canvas.getUpdateManager();
queue = updateManager.getUpdateRunnableQueue();
System.out.println("update manager initialized");

pack();
}
});

canvas.addMouseListener(this);

getContentPane().add(canvas);
setSize(400, 400);
setVisible(true);
}

protected void createDocument() {
System.out.println("creating doc...");

doc = (SVGOMDocument) impl.createDocument(svgNS, "svg", null);

svgRoot = (SVGOMSVGElement) doc.getDocumentElement();

svgRoot.setAttributeNS(null, "viewbox", "0 0 400 400");
// Set the width and height attributes on the root 'svg' element.
svgRoot.setAttributeNS(null, "width", "400");
svgRoot.setAttributeNS(null, "height", "400");

// Create the plane.
plane = (SVGOMElement) doc.createElementNS(svgNS, "circle");
plane.setAttributeNS(null, "id", "plane");
plane.setAttributeNS(null, "cx", "0");
plane.setAttributeNS(null, "cy", "0");
plane.setAttributeNS(null, "r", "5");
plane.setAttributeNS(null, "fill", "red");

// path
path = (SVGOMPathElement) doc.createElementNS(svgNS, "path");
path.setAttributeNS(null, "id", "path");
path.setAttributeNS(null, "fill", "none");
path.setAttributeNS(null, "stroke", "green");
path.setAttributeNS(null, "stroke-width", "3px");
path.setAttributeNS(null, "d", "M50,50 h10 v10 h10 v10 h10 v10");

// animation element
anim = (SVGOMAnimateMotionElement) doc.createElementNS(svgNS, "animateMotion");
anim.setAttributeNS(null, "id", "anim");
anim.setAttributeNS(null, "repeatCount", "indefinite");
anim.setAttributeNS(null, "begin", "0s");
anim.setAttributeNS(null, "dur", "3s");
anim.setAttributeNS(null, "rotate", "auto");
anim.setAttributeNS(null, "restart", "always");
anim.setAttributeNS(null, "path", path.getAttributeNS(null, "d"));


svgRoot.appendChild(path);
plane.appendChild(anim);
svgRoot.appendChild(plane);
}

@Override
public void mouseClicked(MouseEvent me) {
System.out.println("clicked");

queue.invokeLater(new Runnable() {
public void run() {
SVGOMAnimatedPathData data = path.getAnimatedPathData();
SVGPathSegList segs = data.getPathSegList();
int length = segs.getNumberOfItems();

SVGPathSeg seg;
if (length % 2 == 0) {
seg = path.createSVGPathSegLinetoVerticalRel(10);
} else {
seg = path.createSVGPathSegLinetoHorizontalRel(10);
}
segs.appendItem(seg);

//anim.putLiveAttributeValue(null, "path", data); no idea what a live attr is?!

anim.setAttributeNS(null, "path", path.getAttributeNS(null, "d"));

}
});
}

@Override
public void mouseEntered(MouseEvent me) {
}

@Override
public void mouseExited(MouseEvent me) {
}

@Override
public void mousePressed(MouseEvent me) {
}

@Override
public void mouseReleased(MouseEvent me) {
}
}

I actually got it working by removing the animation element from the doc and in turn append a copy of it:
float timeOffset = anim.getCurrentTime();
float dur = path.getTotalLength() / VELOCITY;

SVGOMAnimateMotionElement tmp = (SVGOMAnimateMotionElement) anim.cloneNode(true);
tmp.setAttributeNS(null, "dur", String.valueOf(dur) + "s");
plane.replaceChild(tmp, anim);
tmp.beginElementAt(-timeOffset);
anim = tmp;

Problem here is that I don't want the animation to restart, so I started the animation at an time offset, but this solution is not satisfactory due to lagging.

Another next problem would be to determine the prosition of the moving object and to detect a collition with an other element.

Thanks for your help.

Regards Nicky Nubbel

Reply via email to