Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I add ID attribute to g element in Batik?

Tags:

java

dom

svg

batik

I am creating an SVG file using Batik, which I would like to later open in a browser and manipulate using JavaScript. I am unable to figure out how to add ID attributes to the g elements created.

svgGenerator = new SVGGraphics2D(document);
svgGenerator.setPaint(Color.black);

for (int i = 0; i < 10; i++) {
...
svgGenerator.fill(new Rectangle(p.x, p.y, 2, 2));
}

svgGenerator.setPaint(new Color(0, 0, 0, 0.2f));
for (int i = 0; i < 20; i++) {
CubicCurve2D curve = new CubicCurve2D.Float();
...
curve.setCurve(a.x, a.y, c.x, c.y, c.x, c.y, b.x, b.y);
svgGenerator.draw(curve);
}

...

OutputStream outputStream = new FileOutputStream(svgFileName);
Writer out = new OutputStreamWriter(outputStream, "UTF-8");
svgGenerator.stream(out, useCSS);
out.flush();
out.close();

gives me

<defs id="genericDefs"/>
<rect width="100%" height="100%" fill="white"/>
<g>
<g>
<rect x="699" width="2" height="2" y="350" style="stroke:none;"/>
<rect 
...
</g>
<g style="fill:rgb(0,0,0); fill-opacity:0.2; stroke-opacity:0.2; stroke:rgb(0,0,0);">
<path style="fill:none;" d="M699 350 C567 178 567 178 436 11"/>
<path 
...
</g>
</g>

I would like to give separate ID tags to the three "g" elements created by batik. How should I modify my code in order to achieve this?

edit: I got it to work by traversing the DOM after all elements are created, using the hint given by @robert. But this feels like an "ugly" solution, is there something more elegant?

Element root = svgGenerator.getRoot();
Element topG = (Element) root.getChildNodes().item(2);
topG.setAttribute("id", "allSVG");
Element rectangleG = (Element) topG.getChildNodes().item(0);
rectangleG.setAttribute("id", "rectangles");
Element pathG = (Element) topG.getChildNodes().item(1);
pathG.setAttribute("id", "paths");
...
svgGenerator.stream(root, out, useCSS, false);
like image 820
Diego Avatar asked Oct 20 '25 02:10

Diego


1 Answers

The "g" element stands for the Groups for Batik and they are managed by the DOMTreeManager.appendGroup() So each time Batik creates a new group (except the top level group) it calls the DOMTreeManager.appendGroup(). What you can do is extends the SVGGraphics2D by injecting your own custom version of the DOMTreeManager which sets the id on each group.

public class IndexedSVGGraphics2D extends SVGGraphics2D {

    private Integer index = 0;

    public IndexedSVGGraphics2D(Document domFactory) {
        super(domFactory);
    }

    @Override
    protected void setGeneratorContext(SVGGeneratorContext generatorCtx) {
        // do the default work
        super.setGeneratorContext(generatorCtx);
        // do the magic
        this.domTreeManager = new DOMTreeManager(gc,
                generatorCtx,
                DEFAULT_MAX_GC_OVERRIDES){
            @Override
            public void appendGroup(Element group, DOMGroupManager groupManager) {
                // here setting any attribute which you need (in your case the id)
                group.setAttribute("id", String.valueOf(index++));
                super.appendGroup(group, groupManager);

            }
        };
        this.domGroupManager = new DOMGroupManager(gc, domTreeManager);
        this.domTreeManager.addGroupManager(domGroupManager);
    }
}

Next just use the IndexedSVGGraphics2D in your code instead of SVGGraphics2D.

Note: If you need to access the top-level Group just use the domTreeManager.getTopLevelGroup().

like image 131
Babl Avatar answered Oct 21 '25 15:10

Babl



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!