001/* 002 * Copyright 2006 - 2013 003 * Stefan Balev <stefan.balev@graphstream-project.org> 004 * Julien Baudry <julien.baudry@graphstream-project.org> 005 * Antoine Dutot <antoine.dutot@graphstream-project.org> 006 * Yoann Pigné <yoann.pigne@graphstream-project.org> 007 * Guilhelm Savin <guilhelm.savin@graphstream-project.org> 008 * 009 * This file is part of GraphStream <http://graphstream-project.org>. 010 * 011 * GraphStream is a library whose purpose is to handle static or dynamic 012 * graph, create them from scratch, file or any source and display them. 013 * 014 * This program is free software distributed under the terms of two licenses, the 015 * CeCILL-C license that fits European law, and the GNU Lesser General Public 016 * License. You can use, modify and/ or redistribute the software under the terms 017 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following 018 * URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by 019 * the Free Software Foundation, either version 3 of the License, or (at your 020 * option) any later version. 021 * 022 * This program is distributed in the hope that it will be useful, but WITHOUT ANY 023 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 024 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 025 * 026 * You should have received a copy of the GNU Lesser General Public License 027 * along with this program. If not, see <http://www.gnu.org/licenses/>. 028 * 029 * The fact that you are presently reading this means that you have had 030 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms. 031 */ 032package org.graphstream.stream.file; 033 034import java.io.IOException; 035import java.io.PrintWriter; 036import java.util.HashMap; 037import java.util.Iterator; 038 039import org.graphstream.ui.geom.Point3; 040import org.graphstream.ui.graphicGraph.stylesheet.Rule; 041import org.graphstream.ui.graphicGraph.stylesheet.StyleSheet; 042 043/** 044 * Transforms a graph into a SVG description. 045 * 046 * <p> 047 * Do not confuse this with the SVG export capabilities of the graph viewer. The 048 * SVG export of the viewer provides the most exact copy of what you see on 049 * screen. This class is made to export only nodes and edges without styling to 050 * SVG. 051 * </p> 052 * 053 * 054 * <p> 055 * Although there is no styling, each node and edge is put in a SVG group with 056 * the identifier of the corresponding element in the graph. A minimal CSS style 057 * sheet is included in the generated file and it is easy to add another. 058 * </p> 059 */ 060public class FileSinkSVG extends FileSinkBase { 061 // Attribute 062 063 /** 064 * The output. 065 */ 066 protected PrintWriter out; 067 068 /** 069 * What element ?. 070 */ 071 protected enum What { 072 NODE, EDGE, OTHER 073 }; 074 075 /** 076 * The positions of each node. 077 */ 078 protected HashMap<String, Point3> nodePos = new HashMap<String, Point3>(); 079 080 // Construction 081 082 public FileSinkSVG() { 083 // NOP. 084 } 085 086 // Command 087 088 @Override 089 public void end() throws IOException { 090 if (out != null) { 091 out.flush(); 092 out.close(); 093 out = null; 094 } 095 } 096 097 // Command 098 099 @Override 100 protected void outputHeader() throws IOException { 101 out = (PrintWriter) output; 102 103 out.printf("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>%n"); 104 out.printf("<svg" + " xmlns:svg=\"http://www.w3.org/2000/svg\"" 105 + " width=\"100%%\"" + " height=\"100%%\"" + ">%n"); 106 107 // TODO 108 // outputStyle( styleSheet ); 109 } 110 111 @Override 112 protected void outputEndOfFile() throws IOException { 113 outputNodes(); 114 out.printf("</svg>%n"); 115 } 116 117 public void edgeAttributeAdded(String graphId, long timeId, String edgeId, 118 String attribute, Object value) { 119 // NOP 120 } 121 122 public void edgeAttributeChanged(String graphId, long timeId, 123 String edgeId, String attribute, Object oldValue, Object newValue) { 124 // NOP 125 } 126 127 public void edgeAttributeRemoved(String graphId, long timeId, 128 String edgeId, String attribute) { 129 // NOP 130 } 131 132 public void graphAttributeAdded(String graphId, long timeId, 133 String attribute, Object value) { 134 // NOP 135 } 136 137 public void graphAttributeChanged(String graphId, long timeId, 138 String attribute, Object oldValue, Object newValue) { 139 // NOP 140 } 141 142 public void graphAttributeRemoved(String graphId, long timeId, 143 String attribute) { 144 // NOP 145 } 146 147 public void nodeAttributeAdded(String graphId, long timeId, String nodeId, 148 String attribute, Object value) { 149 setNodePos(nodeId, attribute, value); 150 } 151 152 public void nodeAttributeChanged(String graphId, long timeId, 153 String nodeId, String attribute, Object oldValue, Object newValue) { 154 setNodePos(nodeId, attribute, newValue); 155 } 156 157 public void nodeAttributeRemoved(String graphId, long timeId, 158 String nodeId, String attribute) { 159 // NOP 160 } 161 162 public void edgeAdded(String graphId, long timeId, String edgeId, 163 String fromNodeId, String toNodeId, boolean directed) { 164 Point3 p0 = nodePos.get(fromNodeId); 165 Point3 p1 = nodePos.get(toNodeId); 166 167 if (p0 != null && p1 != null) { 168 out.printf(" <g id=\"%s\">%n", edgeId); 169 out.printf(" <line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\"/>%n", 170 p0.x, p0.y, p1.x, p1.y); 171 out.printf(" </g>%n"); 172 } 173 } 174 175 public void edgeRemoved(String graphId, long timeId, String edgeId) { 176 // NOP 177 } 178 179 public void graphCleared(String graphId, long timeId) { 180 // NOP 181 } 182 183 public void nodeAdded(String graphId, long timeId, String nodeId) { 184 nodePos.put(nodeId, new Point3()); 185 } 186 187 public void nodeRemoved(String graphId, long timeId, String nodeId) { 188 nodePos.remove(nodeId); 189 } 190 191 public void stepBegins(String graphId, long timeId, double time) { 192 // NOP 193 } 194 195 // Utility 196 197 protected void setNodePos(String nodeId, String attribute, Object value) { 198 Point3 p = nodePos.get(nodeId); 199 200 if (p == null) { 201 p = new Point3((float) Math.random(), (float) Math.random(), 0f); 202 nodePos.put(nodeId, p); 203 } 204 205 if (attribute.equals("x")) { 206 if (value instanceof Number) 207 p.x = ((Number) value).floatValue(); 208 } else if (attribute.equals("y")) { 209 if (value instanceof Number) 210 p.y = ((Number) value).floatValue(); 211 } else if (attribute.equals("z")) { 212 if (value instanceof Number) 213 p.z = ((Number) value).floatValue(); 214 } 215 216 else if (attribute.equals("xy")) { 217 if (value instanceof Object[]) { 218 Object xy[] = ((Object[]) value); 219 220 if (xy.length > 1) { 221 p.x = ((Number) xy[0]).floatValue(); 222 p.y = ((Number) xy[1]).floatValue(); 223 } 224 } 225 } else if (attribute.equals("xyz")) { 226 if (value instanceof Object[]) { 227 Object xyz[] = ((Object[]) value); 228 229 if (xyz.length > 1) { 230 p.x = ((Number) xyz[0]).floatValue(); 231 p.y = ((Number) xyz[1]).floatValue(); 232 } 233 234 if (xyz.length > 2) { 235 p.z = ((Number) xyz[2]).floatValue(); 236 } 237 } 238 } 239 } 240 241 protected void outputStyle(String styleSheet) { 242 String style = null; 243 244 if (styleSheet != null) { 245 StyleSheet ssheet = new StyleSheet(); 246 247 try { 248 if (styleSheet.startsWith("url(")) { 249 styleSheet = styleSheet.substring(5); 250 251 int pos = styleSheet.lastIndexOf(')'); 252 253 styleSheet = styleSheet.substring(0, pos); 254 255 ssheet.parseFromFile(styleSheet); 256 } else { 257 ssheet.parseFromString(styleSheet); 258 } 259 260 style = styleSheetToSVG(ssheet); 261 } catch (IOException e) { 262 e.printStackTrace(); 263 ssheet = null; 264 } 265 } 266 267 if (style == null) 268 style = "circle { fill: grey; stroke: none; } line { stroke-width: 1; stroke: black; }"; 269 270 out.printf("<defs><style type=\"text/css\"><![CDATA[%n"); 271 out.printf(" %s%n", style); 272 out.printf("]]></style></defs>%n"); 273 } 274 275 protected void outputNodes() { 276 Iterator<? extends String> keys = nodePos.keySet().iterator(); 277 278 while (keys.hasNext()) { 279 String key = keys.next(); 280 Point3 pos = nodePos.get(key); 281 282 out.printf(" <g id=\"%s\">%n", key); 283 out.printf(" <circle cx=\"%f\" cy=\"%f\" r=\"4\"/>%n", pos.x, 284 pos.y); 285 out.printf(" </g>%n"); 286 } 287 } 288 289 protected String styleSheetToSVG(StyleSheet sheet) { 290 StringBuilder out = new StringBuilder(); 291 292 addRule(out, sheet.getDefaultGraphRule()); 293 294 return out.toString(); 295 } 296 297 protected void addRule(StringBuilder out, Rule rule) { 298 // Style style = rule.getStyle(); 299 300 // TODO 301 } 302}