package svg; import java.awt.BasicStroke; import java.awt.Shape; import java.awt.Stroke; import java.io.IOException; import java.io.InputStream; import org.apache.batik.svggen.DOMGroupManager; import org.apache.batik.svggen.ExtensionHandler; import org.apache.batik.svggen.ImageHandler; import org.apache.batik.svggen.SVGGraphics2D; import org.apache.commons.lang.StringEscapeUtils; import org.apache.tika.io.IOUtils; import org.w3c.dom.CDATASection; import org.w3c.dom.Document; import org.w3c.dom.Element; public class AorraSvgGraphics2D extends SVGGraphics2D { private final String SCRIPT_NAME = "tooltip.js"; private boolean inject = false; public AorraSvgGraphics2D(Document domFactory, ImageHandler imageHandler, ExtensionHandler extensionHandler, boolean textAsShapes) { super(domFactory, imageHandler, extensionHandler, textAsShapes); } @Override public Element getRoot(Element svgRoot) { svgRoot = super.getRoot(svgRoot); if(svgRoot != null && SVG_SVG_TAG.equals(svgRoot.getTagName()) && inject) { injectTooltip(svgRoot); } return svgRoot; } /** * @see #draw */ public void drawWithTooltip(Shape s, String tooltip) { // Only BasicStroke can be converted to an SVG attribute equivalent. // If the GraphicContext's Stroke is not an instance of BasicStroke, // then the stroked outline is filled. Stroke stroke = gc.getStroke(); if (stroke instanceof BasicStroke) { Element svgShape = shapeConverter.toSVG(s); if (svgShape != null) { domGroupManager.addElement(addTooltip(svgShape, tooltip), DOMGroupManager.DRAW); } } else { Shape strokedShape = stroke.createStrokedShape(s); fillWithTooltip(strokedShape, tooltip); } } /** * @see #fill */ public void fillWithTooltip(Shape s, String tooltip) { Element svgShape = shapeConverter.toSVG(s); if (svgShape != null) { domGroupManager.addElement(addTooltip(svgShape, tooltip), DOMGroupManager.FILL); } } private Element addTooltip(Element svgElement, String tooltip) { inject = true; svgElement.setAttributeNS(null, SVG_ONMOUSEMOVE_ATTRIBUTE, "showTooltip(evt, '"+StringEscapeUtils.escapeJavaScript(tooltip)+"')"); svgElement.setAttributeNS(null, SVG_ONMOUSEOUT_ATTRIBUTE, "hideTooltip(evt)"); return svgElement; } private String script() { try { InputStream in = this.getClass().getResourceAsStream(SCRIPT_NAME); if(in == null) { throw new RuntimeException(String.format("resource not found %s", SCRIPT_NAME)); } return IOUtils.toString(in); } catch(IOException e) { throw new RuntimeException(e); } } private void injectTooltip(Element svgRoot) { Document doc = svgRoot.getOwnerDocument(); Element svgScript = doc.createElementNS(null, SVG_SCRIPT_TAG); CDATASection cdata = doc.createCDATASection(script()); svgScript.appendChild(cdata); svgRoot.insertBefore(svgScript, svgRoot.getFirstChild()); svgRoot.setAttributeNS(null, SVG_ONLOAD_ATTRIBUTE, "init(evt)"); Element ttBackground = doc.createElementNS(null, SVG_RECT_TAG); ttBackground.setAttributeNS(null, "id", "tooltip_bg"); ttBackground.setAttributeNS(null, "class", "tooltip_bg"); ttBackground.setAttributeNS(null, "height", "17"); ttBackground.setAttributeNS(null, "width", "1"); ttBackground.setAttributeNS(null, "visibility", "hidden"); ttBackground.setAttributeNS(null, "style", "fill: white;stroke: black;stroke-width: 1;opacity: 0.85;"); Element ttText = doc.createElementNS(null, SVG_TEXT_TAG); ttText.setAttributeNS(null, "id", "tooltip"); ttText.setAttributeNS(null, "class", "tooltip"); ttText.setAttributeNS(null, "visibility", "hidden"); ttText.setAttributeNS(null, "style", "font-size: 10px;font-family: sans-serif;stroke: none;"); ttText.appendChild(doc.createTextNode("tooltip")); svgRoot.appendChild(ttBackground); svgRoot.appendChild(ttText); } }