nl.dvberkel.svg.SvgTreeTransformer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tree.svg Show documentation
Show all versions of tree.svg Show documentation
Code to generate SVG from trees
The newest version!
package nl.dvberkel.svg;
import nl.dvberkel.box.BoundingBox;
import nl.dvberkel.tree.Configuration;
import nl.dvberkel.tree.SvgLeaf;
import nl.dvberkel.tree.SvgNode;
import nl.dvberkel.tree.SvgTree;
import org.apache.batik.anim.dom.SVGDOMImplementation;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Element;
import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.svg.SVGSVGElement;
public class SvgTreeTransformer {
private final Configuration configuration;
private final DOMImplementation dom;
private final String namespace;
public SvgTreeTransformer(Configuration configuration){
this.configuration = configuration;
dom = SVGDOMImplementation.getDOMImplementation();
namespace = SVGDOMImplementation.SVG_NAMESPACE_URI;
}
public SVGSVGElement transform(SvgTree tree) {
SVGDocument document = (SVGDocument) dom.createDocument(namespace, "svg", null);
SVGSVGElement root = document.getRootElement();
root.setAttributeNS(null, "width", Integer.toString(tree.boundingBox().width));
root.setAttributeNS(null, "height", Integer.toString(tree.boundingBox().height));
Element group = createGroup(document);
root.appendChild(group);
append(document, group, tree);
return root;
}
private Element createGroup(SVGDocument document) {
Element element = document.createElement("g");
element.setAttributeNS(null, "stroke", configuration.stroke);
element.setAttributeNS(null, "fill", configuration.fill);
element.setAttributeNS(null, "stroke-width", Integer.toString(configuration.strokeWidth));
return element;
}
private void append(SVGDocument document, Element root, SvgTree tree) {
if (tree instanceof SvgNode) {
SvgNode node = (SvgNode) tree;
Element leftEdge = createEdgeSvg(document, node, node.left());
root.appendChild(leftEdge);
Element rightEdge = createEdgeSvg(document, node, node.right());
root.appendChild(rightEdge);
append(document, root, node.left());
append(document, root, node.right());
Element nodeSvg = createNodeSvg(document, node);
root.appendChild(nodeSvg);
} else {
SvgLeaf leaf = (SvgLeaf) tree;
Element leafSvg = createLeafSvg(document, leaf);
root.appendChild(leafSvg);
}
}
private Element createEdgeSvg(SVGDocument document, SvgTree parent, SvgTree child) {
Position parentPosition = position(parent);
Position childPosition = position(child);
Element element = document.createElementNS(namespace, "line");
element.setAttributeNS(null, "x1", Integer.toString(parentPosition.x));
element.setAttributeNS(null, "y1", Integer.toString(parentPosition.y));
element.setAttributeNS(null, "x2", Integer.toString(childPosition.x));
element.setAttributeNS(null, "y2", Integer.toString(childPosition.y));
return element;
}
private Element createNodeSvg(SVGDocument document, SvgTree tree) {
return circle(document, position(tree), configuration.nodeRadius);
}
private Element circle(SVGDocument document, Position position, int radius) {
Element element = document.createElementNS(namespace, "circle");
element.setAttributeNS(null, "cx", Integer.toString(position.x));
element.setAttributeNS(null, "cy", Integer.toString(position.y));
element.setAttributeNS(null, "r", Integer.toString(radius));
return element;
}
private Element createLeafSvg(SVGDocument document, SvgTree tree) {
return circle(document, position(tree), configuration.leafRadius);
}
private Position position(SvgTree tree) {
if (tree instanceof SvgNode) {
return nodePosition((SvgNode) tree);
} else {
return leafPosition((SvgLeaf) tree);
}
}
private Position nodePosition(SvgNode node) {
BoundingBox box = node.boundingBox();
Position left = position(node.left());
Position right = position(node.right());
return new Position((left.x + right.x)/2, box.y + configuration.nodeRadius + configuration.padding);
}
private Position leafPosition(SvgLeaf leaf) {
BoundingBox box = leaf.boundingBox();
return new Position(box.x + box.width/2, box.y + configuration.nodeRadius + configuration.padding);
}
}
class Position {
public final int x;
public final int y;
public Position(int x, int y) {
this.x = x;
this.y = y;
}
}