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);
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()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With