/* * CCVisu is a tool for visual graph clustering * and general force-directed graph layout. * This file is part of CCVisu. * * Copyright (C) 2005-2007 Dirk Beyer * * CCVisu is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * CCVisu is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with CCVisu; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Please find the GNU Lesser General Public License in file * license_lgpl.txt or http://www.gnu.org/licenses/lgpl.txt * * Dirk Beyer (firstname.lastname@sfu.ca) * Simon Fraser University (SFU), B.C., Canada */ package ccvisu; import java.awt.Color; import java.io.PrintWriter; import java.text.DateFormat; import java.util.Date; /***************************************************************** * Writer for layouts in SVG format (Scalable Vector Graphs, XML, W3C). * @version $Revision$; $Date$ * @author Dirk Beyer *****************************************************************/ public class WriterDataGraphicsSVG extends WriterDataGraphics { private PrintWriter out; private float scalePos; private String inputName; /** used to build uniq id for the edges */ private int edgeNumber = 0; /** * Constructor. * @param graph Graph representation, contains the positions of the vertices. * @param out Output stream writer. * @param minVert Diameter of the smallest vertex. * @param fontSize Font size of vertex annotations. * @param backColor Background color. * @param blackCircle If true, draw black circle around each vertex. * @param showEdges If true, draw the edges between the vertices (if possible). * @param scalePos Scaling factor for the layout to adjust to drawing area. */ public WriterDataGraphicsSVG(GraphData graph, PrintWriter out, float minVert, int fontSize, Color backColor, boolean blackCircle, boolean showEdges, boolean openURL, float scalePos, String inputName) { super(graph, minVert, fontSize, backColor, blackCircle, showEdges, openURL); this.out = out; this.scalePos = scalePos; this.inputName = inputName; } /***************************************************************** * Writes the layout in graphics format SVG. *****************************************************************/ public void write() { int size = (int) (1000 * scalePos); // Header. out.print( "<?xml version=\"1.0\" standalone=\"no\"?>" + endl + " " + endl + "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"" + endl + " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">" + endl + " " + endl + "<!-- Generated by CCVisu, a tool for visual graph clustering " + endl + " and general force-directed graph layout. " + endl + " " + DateFormat.getDateTimeInstance().format(new Date()) + " -->" + endl + " " + endl + "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\"" + endl + " xmlns:xlink=\"http://www.w3.org/1999/xlink\"" + endl + " width=\"100%\" height=\"100%\"" + endl + " viewBox=\"0 0 " + size + " " + size + "\">" + endl + " " + endl + " <title>Visualization " + inputName + "</title>" + endl + " " + endl + " <script><![CDATA[ " + endl + " " + endl + " /* " + endl + " * Returns the innermost SVG object that triggered the event " + endl + " * and that has a non-null id attribute. This can be either the event's " + endl + " * target itself, or its parent node, or the first ancestor of the target " + endl + " * with a non-null id. " + endl + " * " + endl + " * Input Parameters: " + endl + " * evt - The JavaScript object describing the triggering event. " + endl + " * Return Value: " + endl + " * The target node or first target's ancestor with a non-null id. " + endl + " */ " + endl + " function get_target(evt) { " + endl + " var target = evt.target; " + endl + " while (target && !target.getAttribute('id')) { " + endl + " target = target.parentNode; " + endl + " } " + endl + " return target; " + endl + " } " + endl + " " + endl + " /* " + endl + " * Adds or removes a duplicate of the text object that " + endl + " * corresponds to the circle that was clicked on / pointed to: " + endl + " * The circle node is the evt.target. " + endl + " * If the text node is already there, the node gets removed. " + endl + " * Otherwise the text node is cloned. The cloned node's id is changed. " + endl + " * The cloned node is appended to the 'contents' group. " + endl + " * " + endl + " * Input Parameters: " + endl + " * evt - JavaScript object describing the triggering event. " + endl + " * postfix - String to distinguish between click and move. " + endl + " */ " + endl + " function annot_toggle(evt, postfix) { " + endl + " // Retrieve node of object that was clicked on. " + endl + " var target = get_target(evt); " + endl + " var svgdoc = target.ownerDocument; " + endl + " " + endl + " // Retrieve annotation node. " + endl + " var annotNode = svgdoc.getElementById(target.getAttribute('id') " + endl + " + '__text' + postfix); " + endl + " // Check whether annotation is already set. " + endl + " if (annotNode) { " + endl + " // Remove object's node from its group node. " + endl + " var groupnode = annotNode.parentNode; " + endl + " groupnode.removeChild (annotNode); " + endl + " } else { " + endl + " // Clone the text object and set its attributes. " + endl + " var text = svgdoc.getElementById(target.getAttribute('id') + '__text'); " + endl + " annotNode = text.cloneNode(true); " + endl + " annotNode.setAttribute('id', target.getAttribute('id') + '__text' + postfix); " + endl + " // Retrieve the node for 'contents' group. " + endl + " var contents = svgdoc.getElementById('contents'); " + endl + " // Insert the cloned object into the contents group node. " + endl + " contents.parentNode.appendChild(annotNode); " + endl + " window.status = target.getAttribute('id'); " + endl + " } " + endl + " } " + endl + " " + endl + " ]]></script> " + endl + endl ); // Body. writeGraphicsLayout(size); // Footer. out.print("</svg> " + endl); } /** * Writes a vertex in SVG format. * @param curVertex The vertex object, to access vertex attributes. * @param xPos x coordinate of the vertex. * @param yPos y coordinate of the vertex. * @param zPos z coordinate of the vertex. * @param radius Radius of the vertex. */ public void writeVertex(GraphVertex curVertex, int xPos, int yPos, int zPos, int radius) { String name = curVertex.name; //remove double quote if(name.startsWith("\"") && name.endsWith("\"")){ name = name.substring(1,name.length()-1); } // Prepare color string for vertex. // Convert to hex RGB value and get rid of the alpha value. String colorStr = Integer.toHexString(curVertex.color.getRGB() & 0x00FFFFFF); // Fill up to 6 digits. colorStr = "000000" + colorStr; colorStr = colorStr.substring(colorStr.length() - 6, colorStr.length()); // Prepare color string for annotation text. Color textColor = new Color( 0xffffffff - backColor.getRGB() ); // Convert to hex RGB value and get rid of the alpha value. String textColStr = Integer.toHexString(textColor.getRGB() & 0x00FFFFFF); // Fill up to 6 digits. textColStr = "000000" + textColStr; textColStr = textColStr.substring(textColStr.length() - 6, textColStr.length()); // Write the definition for the annotation. out.print( " <defs>" + " <text" + " id=\"" + name + "__text\"" + " x=\"" + (xPos + radius + 3) + "\"" + " y=\"" + (yPos + 3) + "\"" + " style=\"font-size:" + fontSize + "pt;fill:#" + textColStr + "\"> " + name + " </text>" + " </defs> " + endl ); // Write graphical objects. out.print(" <g id=\"contents\"> " + endl); // Write vertex. String strokeString = ""; if (blackCircle) { strokeString = " stroke=\"black\""; } //link information if(openURL){ out.println(" <a xlink:href=\"" + name + "\">"); } out.print( " <circle" + " id=\"" + name + "\"" + " cx=\"" + xPos + "\"" + " cy=\"" + yPos + "\"" + " r=\"" + radius + "\"" + " fill=\"#" + colorStr + "\"" + strokeString + " onmouseover=\"annot_toggle(evt, '_move')\"" + " onmouseout=\"annot_toggle(evt, '_move')\"" + " onclick=\"annot_toggle(evt, '_click')\"" + " /> " + endl ); if(openURL){ out.println(" </a>"); } // Write annotation, only if required. if (curVertex.showName) { out.print(" <text" + " id=\"" + name + "__text_click\"" + " x=\"" + (xPos + radius + 3) + "\"" + " y=\"" + (yPos + 3) + "\"" + " style=\"font-size:" + fontSize + "pt;fill:#" + textColStr + "\"> " + name + " </text> " + endl ); } out.print(" </g> " + endl); } /** * Writes an edge. * @param index index of the edge in graph.edges * @param xPos1 x coordinate of the first point. * @param yPos1 y coordinate of the first point. * @param zPos1 z coordinate of the first point. * @param xPos2 x coordinate of the second point. * @param yPos2 y coordinate of the second point. * @param zPos2 z coordinate of the second point. */ public void writeEdge(int index, int xPos1, int yPos1, int zPos1, int xPos2, int yPos2, int zPos2){ String edgeName = graph.edges.get(index).relName; //Prepare color string for annotation text. Color textColor = new Color( 0xffffffff - backColor.getRGB() ); // Convert to hex RGB value and get rid of the alpha value. String textColStr = Integer.toHexString(textColor.getRGB() & 0x00FFFFFF); // Fill up to 6 digits. textColStr = "000000" + textColStr; textColStr = textColStr.substring(textColStr.length() - 6, textColStr.length()); // Write the definition for the annotation. out.print( " <defs>" + " <text" + " id=\"" + edgeName + edgeNumber + "__text\"" + " x=\"" + ((xPos1 + xPos2)/2 + fontSize + 3) + "\"" + " y=\"" + ((yPos1 + yPos2)/2 + fontSize + 3) + "\"" + " style=\"font-size:" + fontSize + "pt;fill:#" + textColStr + "\"> " + edgeName + " </text>" + " </defs> " + endl ); //Write graphical objects. out.print(" <g id=\"contents\"> " + endl); out.print("<line id=\""+ edgeName + edgeNumber +"\" style=\"stroke:rgb(0,0,0);stroke-width:1;fill:none;\" " + "y1=\""+yPos1+"\" y2=\""+yPos2+"\" x1=\""+xPos1+"\" x2=\""+xPos2+"\" " + " onmouseover=\"annot_toggle(evt, '_move')\"" + " onmouseout=\"annot_toggle(evt, '_move')\"" + " onclick=\"annot_toggle(evt, '_click')\" />" + endl); out.print(" </g> " + endl); ++edgeNumber; } };