javaxmlapachesvgbatik

How I can repaint a JSVGCanvas after editing the SVGDocument? using Apache Batik


I'm trying to modify the SVG document in runtime and go repainting the modifications performed to the SVG:

I need your help, i'm trying with repaint method, but is not posible refresh the SVG Canvas.

this is the code:

import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.*;
import java.io.StringReader;

import javax.swing.*;
import org.apache.batik.dom.svg.SAXSVGDocumentFactory;

import org.apache.batik.swing.*;
import org.apache.batik.svggen.*;
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.batik.util.XMLResourceDescriptor;

import org.w3c.dom.*;
import org.w3c.dom.svg.*;

public class BatikViewGeneratedSVGDemo extends JFrame implements MouseListener, MouseMotionListener{

    String xmlSVG;
    SVGDocument svgDoc;
    Element svgRoot;
    JSVGCanvas canvas;

    public BatikViewGeneratedSVGDemo() throws HeadlessException {
        setLayout(new BorderLayout());
        setPreferredSize(new Dimension(600, 600));
        setMinimumSize(new Dimension(600, 600));

        String xmlSVG = ""
                + "<?xml version=\"1.0\" standalone=\"no\"?>\n" +
                "<svg "
                + "contentScriptType=\"text/ecmascript\" "
                + "xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
                + "xmlns=\"http://www.w3.org/2000/svg\"\n"
                + "baseProfile=\"full\"\n "
                + "zoomAndPan=\"magnify\" "
                + "contentStyleType=\"text/css\" "
                + "preserveAspectRatio=\"xMidYMid meet\" "
                + "width=\"600\"  "
                + "height=\"600.0px\"  "
                + "viewBox='0 0 716.3783 753.51105'"
                + " version=\"1.0\"  >\n "
                + " <ellipse id='circulo1' fill-opacity=\"0.5\" fill=\"#ff0033\" rx=\"58.0\" cx=\"238.0\" ry=\"45.5\" cy=\"180.5\" stroke=\"#000000\"/>\n "
                + "</svg>";

        StringReader reader = new StringReader(xmlSVG);
        String uri = "nothing";
        try {
            String parser = XMLResourceDescriptor.getXMLParserClassName();
            SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
            svgDoc = f.createSVGDocument(uri, reader);
            Element circulo = svgDoc.getElementById("circulo1");
            System.out.println("opacidad: " + circulo.getAttribute("fill-opacity"));

            svgRoot = svgDoc.getDocumentElement();
            // Display the document.
            canvas = new JSVGCanvas();
            System.out.println("doc.width: " + svgRoot.getAttribute("width"));
            getContentPane().add(canvas, BorderLayout.CENTER);
            canvas.setSVGDocument(svgDoc);

            JButton btn = new JButton("Crear Circulo");
            btn.addMouseListener(this);
            getContentPane().add(btn, BorderLayout.SOUTH);
            System.out.println("ancho: " + canvas.getSize().width + " alto: " + canvas.getSize().height);
        } catch (Exception ex) {
            System.out.println("ocurriĆ³ un error");
        } finally {
            reader.close();
        }
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        crearCirculo();
    }

    @Override
    public void mousePressed(MouseEvent e) {}

    @Override
    public void mouseReleased(MouseEvent e) {}

    @Override
    public void mouseEntered(MouseEvent e) {}

    @Override
    public void mouseExited(MouseEvent e) {}

    @Override
    public void mouseDragged(MouseEvent e) {}

    @Override
    public void mouseMoved(MouseEvent e) {}

    public void crearCirculo() {
        Element newCircle = svgDoc.createElement("ellipse");
        newCircle.setAttribute("id", "circulo2");
        newCircle.setAttribute("fill-opacity", "0.5");
        newCircle.setAttribute("fill", "#990055");
        newCircle.setAttribute("rx", "100");
        newCircle.setAttribute("cx", "150");
        newCircle.setAttribute("ry", "100");
        newCircle.setAttribute("cy", "150");
        newCircle.setAttribute("stroke", "#990055");
        System.out.println("XML: "+svgDoc.getRootElement().getXMLbase());

        svgRoot.appendChild(newCircle);
        canvas.setSVGDocument(svgDoc);
        System.out.println("opacidad2: " + svgDoc.getElementById("circulo2").getAttribute("fill-opacity"));
        System.out.println("entra");
    }


    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                BatikViewGeneratedSVGDemo obj = new BatikViewGeneratedSVGDemo();
                obj.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                obj.setVisible(true);
            }
        });
    }
}

Solution

  • You should create a Runnable with all modifications to the SVG document and then use JSVGCanvas Update Manager's Runnable Queue to call this Runnable and all changes to take effect.

    public Runnable r = new Runnable() {
    
            @Override
            public void run() {
                value = value + 10;
                svgCanvas.evaluate("setlevel(" + value + ",'Text')");
            }
        };
    

    And then,

    svgCanvas.getUpdateManager().getUpdateRunnableQueue().invokeLater(r);
    

    Everything done outside this queue will not take effect inmediatly.