import org.simantics.g2d.diagram.DiagramHints;
import org.simantics.g2d.diagram.IDiagram;
import org.simantics.g2d.diagram.handler.DataElementMap;
+import org.simantics.g2d.diagram.participant.ElementPainter.SelectionShapeNode;
import org.simantics.g2d.diagram.participant.Selection;
import org.simantics.g2d.element.IElement;
import org.simantics.g2d.scenegraph.ICanvasSceneGraphProvider;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class SCLScenegraph {
result.append(ALL_SECTIONS, "</g>");
StringBuilder res = new StringBuilder();
- res.append("<svg width=\"100%\" height=\"100%\" stroke=\"black\">");
+ if (width > 0 && height > 0 ) {
+ res.append("<svg width=\"" + width +"px\" height=\""+height+"px\" stroke=\"black\" xmlns=\"http://www.w3.org/2000/svg\">");
+ } else {
+ res.append("<svg width=\"100%\" height=\"100%\" stroke=\"black\" xmlns=\"http://www.w3.org/2000/svg\">");
+ }
res.append("<g transform=\"matrix(").append(matrix[0]).append(",").append(matrix[1]).append(",").append(matrix[2]).append(",").append(matrix[3]).append(",").append(matrix[4]).append(",").append(matrix[5]).append(")\">");
res.append(result.get(MAIN_SECTION));
res.append(result.get(SELECTION_SECTION));
private String getKey(SingleElementNode node) {
String key;
if(node.getKey() != null) {
- if (mappings.containsKey(node.getKey()))
+ if (mappings.containsKey(node.getKey())) {
key = mappings.get(node.getKey()).toString();
- else
+ key = escape(key);
+ } else {
key = node.getKey().toString();
+ key = escape(key);
+ }
} else {
key = Long.toString(node.getId());
}
return key;
}
+
+ private String escape(String key) {
+ // Keys may contain '<' '>' characters, which causes errors in browser SVG handling.
+ return org.apache.commons.lang.StringEscapeUtils.escapeHtml(key);
+ }
+
+ private String removeElem(String xml, String elemStart) {
+ // FIXME: This is rather nasty and error prone way of removing elements from XML string.
+ // This only supports elements with /> end element tag. Elements ends with </elem name> are not supported!
+ int start = xml.indexOf("<"+elemStart);
+ if (start>=0) {
+ int end = xml.indexOf(">",start);
+ if (end >= 0) {
+ if (start > 0)
+ return xml.substring(0,start)+xml.substring(end+1);
+ else
+ return xml.substring(end+1);
+ }
+ }
+ return null;
+ }
@Override
public void enter(IG2DNode node) {
parentBuilder.append(MAIN_SECTION, "\n<g transform=\"" + m + "\">");
}
}
- parentBuilder.append(MAIN_SECTION, svg.getSVGText());
+ String svgContent = svg.getSVGText();
+ // SVGNode content may contain SVG/XML elements, which break browser compatibility
+ int start = svgContent.indexOf("<svg");
+ if (start >= 0)
+ svgContent = svgContent.substring(start);
+ else {
+ String s = removeElem(svgContent, "?xml");
+ if (s != null) {
+ svgContent = "<g>"+s+"</g>";
+ s = removeElem(svgContent, "!DOCTYPE");
+ if (s != null)
+ svgContent = s;
+ }
+ }
+ parentBuilder.append(MAIN_SECTION, svgContent);
if (!at.isIdentity()) {
parentBuilder.append(MAIN_SECTION, "\n</g>");
}
parentBuilder.append(ALL_SECTIONS, "\n<g transform=\"" + m + "\">");
}
}
+ } else if (node instanceof TextNode) {
+ TextNode text = (TextNode)node;
+
+ SingleElementNode parentSEN = (SingleElementNode)NodeUtil.getNearestParentOfType(node, SingleElementNode.class);
+ if(parentSEN != null) {
+
+ text.setShowSelection(false);
+ Element doc = renderSVGNode(svgGenerator, (IG2DNode)node);
+ String svg = printSVGDocument(doc);
+ parentBuilder.append(MAIN_SECTION, svg);
+
+ RenderSVGContext parentBuilder2 = getParentBuilder(parentSEN);
+
+ String key = getKey(parentSEN);
+ text.setShowSelection(true);
+ doc = renderSVGNode(svgGenerator, (IG2DNode)node);
+ svg = printSVGDocument(doc);
+
+ parentBuilder2.append(SELECTION_SECTION, "\n<g style=\"visibility:hidden\" class=\"selection\" id=\"" + key + "\">");
+ parentBuilder2.append(SELECTION_SECTION, svg);
+ parentBuilder2.append(SELECTION_SECTION, "\n</g>");
+ parentBuilder2.append(SELECTION_MASK_SECTION, "\n<g class=\"selectionMask\" id=\"" + key /*+ "\" transform=\"" + matrixString + "\"*/+ "\">");
+ Rectangle2D rect = text.getBounds();
+ // NaN
+ if(rect.getHeight() == rect.getHeight() && rect.getWidth() == rect.getWidth()) {
+ parentBuilder2.append(SELECTION_MASK_SECTION,"<rect style=\"fill:#fff\" opacity=\"" + OPACITY + "\"");
+ parentBuilder2.append(SELECTION_MASK_SECTION," x=\"" + rect.getX() + "\" y=\"" + rect.getY() + "\"");
+ parentBuilder2.append(SELECTION_MASK_SECTION," width=\"" + rect.getWidth() + "\" height=\"" + rect.getHeight() + "\"");
+ parentBuilder2.append(SELECTION_MASK_SECTION,"></rect>");
+ }
+ parentBuilder2.append(SELECTION_MASK_SECTION,"\n</g>");
+
+ }
} else if (!(node instanceof RouteGraphNode) && !(node instanceof LinkNode)){
try {
Element doc = renderSVGNode(svgGenerator, (IG2DNode)node);
- if (doc.getElementsByTagName("g").getLength() == 0)
+ NodeList gList = doc.getElementsByTagName("g");
+ if (gList.getLength() == 0)
return;
+ boolean hasContent = false;
+ for (int i = 0; i < gList.getLength(); i++) {
+ Node gNode = gList.item(i);
+ if (gNode.hasChildNodes()) {
+ hasContent = true;
+ break;
+ }
+ }
+ if (!hasContent)
+ return;
String svg = printSVGDocument(doc);
- parentBuilder.append(MAIN_SECTION, "<g>");
- parentBuilder.append(MAIN_SECTION, svg);
- parentBuilder.append(MAIN_SECTION, "\n</g>");
+ if (node instanceof SelectionShapeNode) {
+ SingleElementNode parentSEN = (SingleElementNode)NodeUtil.getNearestParentOfType(node, SingleElementNode.class);
+ if(parentSEN != null) {
+ String key = getKey(parentSEN);
+ RenderSVGContext parentBuilder2 = getParentBuilder(parentSEN);
+ parentBuilder2.append(SELECTION_SECTION, "\n<g style=\"visibility:hidden\" class=\"selection\" id=\"" + key + "\">");
+ parentBuilder2.append(SELECTION_SECTION, svg);
+ parentBuilder2.append(SELECTION_SECTION, "\n</g>");
+
+ parentBuilder2.append(SELECTION_MASK_SECTION, "\n<g class=\"selectionMask\" id=\"" + key /*+ "\" transform=\"" + matrixString + "\"*/+ "\">");
+ Rectangle2D rect = node.getBounds();
+ // NaN
+ if(rect.getHeight() == rect.getHeight() && rect.getWidth() == rect.getWidth()) {
+ parentBuilder2.append(SELECTION_MASK_SECTION,"<rect style=\"fill:#fff\" opacity=\"" + OPACITY + "\"");
+ parentBuilder2.append(SELECTION_MASK_SECTION," x=\"" + rect.getX() + "\" y=\"" + rect.getY() + "\"");
+ parentBuilder2.append(SELECTION_MASK_SECTION," width=\"" + rect.getWidth() + "\" height=\"" + rect.getHeight() + "\"");
+ parentBuilder2.append(SELECTION_MASK_SECTION,"></rect>");
+ }
+ parentBuilder2.append(SELECTION_MASK_SECTION,"\n</g>");
+ }
+ } else {
+ parentBuilder.append(MAIN_SECTION, "<g class=\"" +node.getSimpleClassName() +"\">");
+ parentBuilder.append(MAIN_SECTION, svg);
+ parentBuilder.append(MAIN_SECTION, "\n</g>");
+ }
} catch (Exception e) {
// TODO: There are nodes that do not behave well when rendered to SVG. For backwards compatibility, we don't handle the exceptions.
}