ruby-graphviz 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,323 @@
1
+ # Copyright (C) 2003, 2004, 2005, 2006, 2007 Gregoire Lejeune <gregoire.lejeune@free.fr>
2
+ #
3
+ # This program is free software; you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation; either version 2 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program; if not, write to the Free Software
15
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
+
17
+ require 'tempfile'
18
+ require 'mkmf'
19
+
20
+ require 'graphviz/node'
21
+ require 'graphviz/edge'
22
+ require 'graphviz/attrs'
23
+ require 'graphviz/constants'
24
+
25
+ class GraphViz
26
+ include Constants
27
+
28
+ public
29
+
30
+ ## Var: Output format (dot, png, jpeg, ...)
31
+ @format
32
+ ## Var: Output file name
33
+ @filename
34
+ ## Var: program to use (dot|twopi)
35
+ @prog
36
+ ## Var: program path
37
+ @path
38
+
39
+ ## Var: Graph name
40
+ @name
41
+
42
+ ## Var: defined attributs
43
+ @graph
44
+ @node
45
+ @edge
46
+ attr_accessor :node, :edge
47
+
48
+ @elements_order
49
+
50
+ ##
51
+ # In:
52
+ # - xNodeName : Name of the new node
53
+ # - *hOpt : Node options
54
+ # Out:
55
+ # - xNodeName as In
56
+ #
57
+ def add_node( xNodeName, *hOpt )
58
+ @hoNodes[xNodeName] = GraphViz::Node::new( xNodeName )
59
+
60
+ if hOpt.nil? == false and hOpt[0].nil? == false
61
+ hOpt[0].each do |xKey, xValue|
62
+ @hoNodes[xNodeName][xKey.to_s] = xValue
63
+ end
64
+ end
65
+
66
+ @elements_order.push( {
67
+ "type" => "node",
68
+ "name" => xNodeName,
69
+ "value" => @hoNodes[xNodeName]
70
+ } )
71
+
72
+ return( @hoNodes[xNodeName] )
73
+ end
74
+
75
+ def add_edge( oNodeOne, oNodeTwo, *hOpt )
76
+ oEdge = GraphViz::Edge::new( oNodeOne, oNodeTwo )
77
+
78
+ if hOpt.nil? == false and hOpt[0].nil? == false
79
+ hOpt[0].each do |xKey, xValue|
80
+ oEdge[xKey.to_s] = xValue
81
+ end
82
+ end
83
+
84
+ @elements_order.push( {
85
+ "type" => "edge",
86
+ "value" => oEdge
87
+ } )
88
+
89
+ @loEdges.push( oEdge )
90
+ return( oEdge )
91
+ end
92
+
93
+ def add_graph( xGraphName, *hOpt )
94
+ @hoGraphs[xGraphName] = GraphViz::new( xGraphName, "parent" => self, "type" => @oGraphType )
95
+
96
+ if hOpt.nil? == false and hOpt[0].nil? == false
97
+ hOpt[0].each do |xKey, xValue|
98
+ @hoGraphs[xGraphName][xKey.to_s] = xValue
99
+ end
100
+ end
101
+
102
+ @elements_order.push( {
103
+ "type" => "graph",
104
+ "name" => xGraphName,
105
+ "value" => @hoGraphs[xGraphName]
106
+ } )
107
+
108
+ return( @hoGraphs[xGraphName] )
109
+ end
110
+
111
+ def []=( xAttrName, xValue )
112
+ @graph[xAttrName] = xValue
113
+ end
114
+
115
+ def []( xAttrName )
116
+ return( @graph[xAttrName].clone )
117
+ end
118
+
119
+ def output( *hOpt )
120
+ xDOTScript = ""
121
+ xLastType = nil
122
+ xSeparator = ""
123
+ xData = ""
124
+
125
+ @elements_order.each { |kElement|
126
+ if xLastType.nil? == true or xLastType != kElement["type"]
127
+
128
+ if xData.length > 0
129
+ case xLastType
130
+ when "graph_attr"
131
+ xDOTScript << " " + xData + ";\n"
132
+
133
+ when "node_attr"
134
+ xDOTScript << " node [" + xData + "];\n"
135
+
136
+ when "edge_attr"
137
+ xDOTScript << " edge [" + xData + "];\n"
138
+ end
139
+ end
140
+
141
+ xSeparator = ""
142
+ xData = ""
143
+ end
144
+
145
+ xLastType = kElement["type"]
146
+
147
+ case kElement["type"]
148
+ when "graph_attr"
149
+ xData << xSeparator + kElement["name"] + " = \"" + kElement["value"] + "\""
150
+ xSeparator = "; "
151
+
152
+ when "node_attr"
153
+ xData << xSeparator + kElement["name"] + " = \"" + kElement["value"] + "\""
154
+ xSeparator = ", "
155
+
156
+ when "edge_attr"
157
+ xData << xSeparator + kElement["name"] + " = \"" + kElement["value"] + "\""
158
+ xSeparator = ", "
159
+
160
+ when "node"
161
+ xDOTScript << " " + kElement["value"].output() + "\n"
162
+
163
+ when "edge"
164
+ xDOTScript << " " + kElement["value"].output( @oGraphType ) + "\n"
165
+
166
+ when "graph"
167
+ xDOTScript << kElement["value"].output() + "\n"
168
+
169
+ else
170
+ raise ArgumentError, "Don't know what to do with element type '#{kElement['type']}'"
171
+ end
172
+ }
173
+
174
+ xDOTScript << "}"
175
+
176
+ if @oParentGraph.nil? == false
177
+ xDOTScript = "subgraph #{@name} {\n" << xDOTScript
178
+
179
+ return( xDOTScript )
180
+ else
181
+ if hOpt.nil? == false and hOpt[0].nil? == false
182
+ hOpt[0].each do |xKey, xValue|
183
+ case xKey.to_s
184
+ when "output"
185
+ if FORMATS.index( xValue ).nil? == true
186
+ raise ArgumentError, "output format '#{xValue}' invalid"
187
+ end
188
+ @format = xValue
189
+ when "file"
190
+ @filename = xValue
191
+ when "use"
192
+ if PROGRAMS.index( xValue ).nil? == true
193
+ raise ArgumentError, "can't use '#{xValue}'"
194
+ end
195
+ @prog = xValue
196
+ when "path"
197
+ @path = xValue
198
+ else
199
+ raise ArgumentError, "option #{xKey.to_s} unknown"
200
+ end
201
+ end
202
+ end
203
+
204
+ xDOTScript = "#{@oGraphType} #{@name} {\n" << xDOTScript
205
+
206
+ if @format != "none"
207
+ ## Act: Save script and send it to dot
208
+ t = Tempfile::open( File.basename($0) + "." )
209
+ t.print( xDOTScript )
210
+ t.close
211
+
212
+ #cmd = find_executable( @prog )
213
+ #cmd = find_executable0( @prog )
214
+ cmd = find_executable( )
215
+ if cmd == nil
216
+ raise StandardError, "GraphViz not installed or #{@prog} not in PATH. Install GraphViz or use the 'path' option"
217
+ end
218
+
219
+ xFile = ""
220
+ xFile = "-o #{@filename}" if @filename.nil? == false
221
+ xCmd = "#{cmd} -T#{@format} #{xFile} #{t.path}"
222
+
223
+ f = IO.popen( xCmd )
224
+ print f.readlines
225
+ f.close
226
+ else
227
+ puts xDOTScript
228
+ end
229
+ end
230
+ end
231
+
232
+ def set_position( xType, xKey, xValue )
233
+ @elements_order.push( {
234
+ "type" => "#{xType}_attr",
235
+ "name" => xKey,
236
+ "value" => xValue
237
+ } )
238
+ end
239
+
240
+ ## ----------------------------------------------------------------------------
241
+
242
+ private
243
+
244
+ ## Var: Nodes, Edges and Graphs tables
245
+ @hoNodes
246
+ @loEdges
247
+ @hoGraphs
248
+
249
+ ## Var: Parent graph
250
+ @oParentGraph
251
+
252
+ ## Var: Type de graphe (orient� ou non)
253
+ @oGraphType
254
+
255
+ def initialize( xGraphName, *hOpt )
256
+ @format = "dot"
257
+ @filename = nil
258
+ @prog = "dot"
259
+ @path = nil
260
+ @name = xGraphName
261
+
262
+ @elements_order = Array::new()
263
+
264
+ @oParentGraph = nil
265
+ @oGraphType = "digraph"
266
+
267
+ @hoNodes = Hash::new()
268
+ @loEdges = Array::new()
269
+ @hoGraphs = Hash::new()
270
+
271
+ @node = GraphViz::Attrs::new( self, "node", NODESATTRS )
272
+ @edge = GraphViz::Attrs::new( self, "edge", EDGESATTRS )
273
+ @graph = GraphViz::Attrs::new( self, "graph", GRAPHSATTRS )
274
+
275
+ if hOpt.nil? == false and hOpt[0].nil? == false
276
+ hOpt[0].each do |xKey, xValue|
277
+ case xKey.to_s
278
+ when "output"
279
+ if FORMATS.index( xValue ).nil? == true
280
+ raise ArgumentError, "output format '#{xValue}' invalid"
281
+ end
282
+ @format = xValue
283
+ when "use"
284
+ if PROGRAMS.index( xValue ).nil? == true
285
+ raise ArgumentError, "can't use '#{xValue}'"
286
+ end
287
+ @prog = xValue
288
+ when "file"
289
+ @filename = xValue
290
+ when "parent"
291
+ @oParentGraph = xValue
292
+ when "type"
293
+ if GRAPHTYPE.index( xValue ).nil? == true
294
+ raise ArgumentError, "graph type '#{xValue}' unknow"
295
+ end
296
+ @oGraphType = xValue
297
+ when "path"
298
+ @path = xValue
299
+ else
300
+ self[xKey.to_s] = xValue
301
+ end
302
+ end
303
+ end
304
+ end
305
+
306
+ def find_executable( )
307
+ cmd = find_executable0( @prog )
308
+ if cmd == nil and @path != nil
309
+ __cmd = File.join( @path, @prog )
310
+ cmd = __cmd if File.executable?( __cmd )
311
+ end
312
+ return cmd
313
+ end
314
+ # def find_executable(bin, path = nil)
315
+ # path = (path || ENV['PATH']).split(File::PATH_SEPARATOR)
316
+ # file = nil
317
+ # path.each do |dir|
318
+ # return file if File.executable?(file = File.join(dir, bin))
319
+ # end
320
+ # nil
321
+ # end
322
+ end
323
+
@@ -0,0 +1,51 @@
1
+ # Copyright (C) 2004, 2005, 2006, 2007 Gregoire Lejeune <gregoire.lejeune@free.fr>
2
+ #
3
+ # This program is free software; you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation; either version 2 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program; if not, write to the Free Software
15
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
+
17
+ class GraphViz
18
+ class Attrs
19
+ @data
20
+ @name
21
+ @attributs
22
+ @graphviz
23
+
24
+ attr_accessor :data
25
+
26
+ def initialize( gviz, name, attributs )
27
+ @name = name
28
+ @attributs = attributs
29
+ @data = Hash::new( )
30
+ @graphviz = gviz
31
+ end
32
+
33
+ def []( xKey )
34
+ if @data.key?( xKey.to_s ) == false
35
+ nil
36
+ end
37
+ @data[xKey.to_s]
38
+ end
39
+
40
+ def []=( xKey, xValue )
41
+ if @attributs.index( xKey.to_s ).nil? == true
42
+ raise ArgumentError, "#{@name} attribut '#{xKey.to_s}' invalid"
43
+ end
44
+ @data[xKey.to_s] = xValue
45
+
46
+ if @graphviz.nil? == false
47
+ @graphviz.set_position( @name, xKey.to_s, xValue )
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,290 @@
1
+ # Copyright (C) 2004, 2005, 2006, 2007 Gregoire Lejeune <gregoire.lejeune@free.fr>
2
+ #
3
+ # This program is free software; you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation; either version 2 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program; if not, write to the Free Software
15
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
+
17
+ module Constants
18
+ ## Const: Output formats
19
+ FORMATS = [
20
+ "dot",
21
+ "ps",
22
+ "mif",
23
+ "hpgl",
24
+ "pcl",
25
+ "gif",
26
+ "imap",
27
+ "ismap",
28
+ "cmap",
29
+ "jpeg",
30
+ "png",
31
+ "xpm",
32
+ "pic",
33
+ "gd",
34
+ "gd2",
35
+ "wbmp",
36
+ "vrml",
37
+ "vtx",
38
+ "mp",
39
+ "fig",
40
+ "svg",
41
+ "plain",
42
+ "text",
43
+ "canon",
44
+ "none"
45
+ ]
46
+
47
+ ## Const: programs
48
+ PROGRAMS = [
49
+ "dot",
50
+ "neato",
51
+ "twopi"
52
+ ]
53
+
54
+ ## Const: type de graphs
55
+ GRAPHTYPE = [
56
+ "digraph",
57
+ "graph"
58
+ ]
59
+
60
+ # E, N, G, S and C represent edges, nodes, the root graph, subgraphs and cluster subgraphs, respectively
61
+ GENCS_ATTRS = {
62
+ "Damping" => { "UseBy" => "G", "Type" => "double" },
63
+ "URL" => { "UseBy" => "ENGC", "Type" => "escString, string" },
64
+ "arrowhead" => { "UseBy" => "E", "Type" => "arrowType" },
65
+ "arrowsize" => { "UseBy" => "E", "Type" => "double" },
66
+ "arrowtail" => { "UseBy" => "E", "Type" => "arrowType" },
67
+ "bb" => { "UseBy" => "G", "Type" => "rect" },
68
+ "bgcolor" => { "UseBy" => "GC", "Type" => "color" },
69
+ "bottomlabel" => { "UseBy" => "N", "Type" => "string" },
70
+ "center" => { "UseBy" => "G", "Type" => "bool" },
71
+ "clusterrank" => { "UseBy" => "G", "Type" => "clusterMode" },
72
+ "color" => { "UseBy" => "ENC", "Type" => "color, colorList" },
73
+ "comment" => { "UseBy" => "ENG", "Type" => "string" },
74
+ "compound" => { "UseBy" => "G", "Type" => "bool" },
75
+ "concentrate" => { "UseBy" => "G", "Type" => "bool" },
76
+ "constraint" => { "UseBy" => "E", "Type" => "bool" },
77
+ "decorate" => { "UseBy" => "E", "Type" => "bool" },
78
+ "defaultdist" => { "UseBy" => "G", "Type" => "double" },
79
+ "dim" => { "UseBy" => "G", "Type" => "int" },
80
+ "dir" => { "UseBy" => "E", "Type" => "dirType" },
81
+ "distortion" => { "UseBy" => "N", "Type" => "double" },
82
+ "dpi" => { "UseBy" => "G", "Type" => "double" },
83
+ "epsilon" => { "UseBy" => "G", "Type" => "double" },
84
+ "fillcolor" => { "UseBy" => "NC", "Type" => "color" },
85
+ "fixedsize" => { "UseBy" => "N", "Type" => "bool" },
86
+ "fontcolor" => { "UseBy" => "ENGC", "Type" => "color" },
87
+ "fontname" => { "UseBy" => "ENGC", "Type" => "string" },
88
+ "fontpath" => { "UseBy" => "G", "Type" => "string" },
89
+ "fontsize" => { "UseBy" => "ENGC", "Type" => "double" },
90
+ "group" => { "UseBy" => "N", "Type" => "string" },
91
+ "headURL" => { "UseBy" => "E", "Type" => "escString" },
92
+ "headclip" => { "UseBy" => "E", "Type" => "bool" },
93
+ "headhref" => { "UseBy" => "E", "Type" => "escString" },
94
+ "headlabel" => { "UseBy" => "E", "Type" => "lblString" },
95
+ "headport" => { "UseBy" => "E", "Type" => "portPos" },
96
+ "headtarget" => { "UseBy" => "E", "Type" => "escString" },
97
+ "headtooltip" => { "UseBy" => "E", "Type" => "escString" },
98
+ "height" => { "UseBy" => "N", "Type" => "double" },
99
+ "href" => { "UseBy" => "E", "Type" => "escString" },
100
+ "label" => { "UseBy" => "ENGC", "Type" => "lblString" },
101
+ "html" => { "UseBy" => "N", "Type" => "lblString" }, # API extension
102
+ "labelangle" => { "UseBy" => "E", "Type" => "double" },
103
+ "labeldistance" => { "UseBy" => "E", "Type" => "double" },
104
+ "labelfloat" => { "UseBy" => "E", "Type" => "bool" },
105
+ "labelfontcolor" => { "UseBy" => "E", "Type" => "color" },
106
+ "labelfontname" => { "UseBy" => "E", "Type" => "string" },
107
+ "labelfontsize" => { "UseBy" => "E", "Type" => "double" },
108
+ "labeljust" => { "UseBy" => "GC", "Type" => "string" },
109
+ "labelloc" => { "UseBy" => "GC", "Type" => "string" },
110
+ "layer" => { "UseBy" => "EN", "Type" => "layerRange" },
111
+ "layers" => { "UseBy" => "G", "Type" => "layerList" },
112
+ "layersep" => { "UseBy" => "G", "Type" => "string" },
113
+ "len" => { "UseBy" => "E", "Type" => "double" },
114
+ "lhead" => { "UseBy" => "E", "Type" => "string" },
115
+ "lp" => { "UseBy" => "EGC", "Type" => "point" },
116
+ "ltail" => { "UseBy" => "E", "Type" => "string" },
117
+ "margin" => { "UseBy" => "NG", "Type" => "double, pointf" },
118
+ "maxiter" => { "UseBy" => "G", "Type" => "int" },
119
+ "mclimit" => { "UseBy" => "G", "Type" => "double" },
120
+ "mindist" => { "UseBy" => "G", "Type" => "double" },
121
+ "minlen" => { "UseBy" => "E", "Type" => "int" },
122
+ "mode" => { "UseBy" => "G", "Type" => "string" },
123
+ "model" => { "UseBy" => "G", "Type" => "string" },
124
+ "nodesep" => { "UseBy" => "G", "Type" => "double" },
125
+ "nojustify" => { "UseBy" => "GCNE", "Type" => "bool" },
126
+ "normalize" => { "UseBy" => "G", "Type" => "bool" },
127
+ "nslimitnslimit1" => { "UseBy" => "G", "Type" => "double" },
128
+ "ordering" => { "UseBy" => "G", "Type" => "string" },
129
+ "orientation" => { "UseBy" => "N", "Type" => "double" },
130
+ "orientation" => { "UseBy" => "G", "Type" => "string" },
131
+ "outputorder" => { "UseBy" => "G", "Type" => "outputMode" },
132
+ "overlap" => { "UseBy" => "G", "Type" => "string, bool" },
133
+ "pack" => { "UseBy" => "G", "Type" => "bool, int" },
134
+ "packmode" => { "UseBy" => "G", "Type" => "packMode" },
135
+ "page" => { "UseBy" => "G", "Type" => "pointf" },
136
+ "pagedir" => { "UseBy" => "G", "Type" => "pagedir" },
137
+ "pencolor" => { "UseBy" => "C", "Type" => "color" },
138
+ "peripheries" => { "UseBy" => "NC", "Type" => "int" },
139
+ "pin" => { "UseBy" => "N", "Type" => "bool" },
140
+ "pos" => { "UseBy" => "EN", "Type" => "point, splineType" },
141
+ "quantum" => { "UseBy" => "G", "Type" => "double" },
142
+ "rank" => { "UseBy" => "S", "Type" => "rankType" },
143
+ "rankdir" => { "UseBy" => "G", "Type" => "rankdir" },
144
+ "ranksep" => { "UseBy" => "G", "Type" => "double" },
145
+ "ratio" => { "UseBy" => "G", "Type" => "double, string" },
146
+ "rects" => { "UseBy" => "N", "Type" => "rect" },
147
+ "regular" => { "UseBy" => "N", "Type" => "bool" },
148
+ "remincross" => { "UseBy" => "G", "Type" => "bool" },
149
+ "resolution" => { "UseBy" => "G", "Type" => "double" },
150
+ "root" => { "UseBy" => "GN", "Type" => "string, bool" },
151
+ "rotate" => { "UseBy" => "G", "Type" => "int" },
152
+ "samehead" => { "UseBy" => "E", "Type" => "string" },
153
+ "sametail" => { "UseBy" => "E", "Type" => "string" },
154
+ "samplepoints" => { "UseBy" => "G", "Type" => "int" },
155
+ "searchsize" => { "UseBy" => "G", "Type" => "int" },
156
+ "sep" => { "UseBy" => "G", "Type" => "double" },
157
+ "shape" => { "UseBy" => "N", "Type" => "shape" },
158
+ "shapefile" => { "UseBy" => "N", "Type" => "string" },
159
+ "showboxes" => { "UseBy" => "ENG", "Type" => "int" },
160
+ "sides" => { "UseBy" => "N", "Type" => "int" },
161
+ "size" => { "UseBy" => "G", "Type" => "pointf" },
162
+ "skew" => { "UseBy" => "N", "Type" => "double" },
163
+ "splines" => { "UseBy" => "G", "Type" => "bool, string" },
164
+ "start" => { "UseBy" => "G", "Type" => "startType" },
165
+ "style" => { "UseBy" => "ENC", "Type" => "style" },
166
+ "stylesheet" => { "UseBy" => "G", "Type" => "string" },
167
+ "tailURL" => { "UseBy" => "E", "Type" => "escString" },
168
+ "tailclip" => { "UseBy" => "E", "Type" => "bool" },
169
+ "tailhref" => { "UseBy" => "E", "Type" => "escString" },
170
+ "taillabel" => { "UseBy" => "E", "Type" => "lblString" },
171
+ "tailport" => { "UseBy" => "E", "Type" => "portPos" },
172
+ "tailtarget" => { "UseBy" => "E", "Type" => "escString" },
173
+ "tailtooltip" => { "UseBy" => "E", "Type" => "escString" },
174
+ "target" => { "UseBy" => "ENGC", "Type" => "escString, string" },
175
+ "tooltip" => { "UseBy" => "NE", "Type" => "escString" },
176
+ "toplabel" => { "UseBy" => "N", "Type" => "string" },
177
+ "truecolor" => { "UseBy" => "G", "Type" => "bool" },
178
+ "vertices" => { "UseBy" => "N", "Type" => "pointfList" },
179
+ "viewport" => { "UseBy" => "G", "Type" => "viewPort" },
180
+ "voro_margin" => { "UseBy" => "G", "Type" => "double" },
181
+ "weight" => { "UseBy" => "E", "Type" => "double" },
182
+ "width" => { "UseBy" => "N", "Type" => "double" },
183
+ "z" => { "UseBy" => "N", "Type" => "double" }
184
+ }
185
+
186
+ ## Const: Graph attributs
187
+ GRAPHSATTRS = [
188
+ "bgcolor",
189
+ "center",
190
+ "clusterrank",
191
+ "color",
192
+ "comment",
193
+ "compound",
194
+ "concentrate",
195
+ "fillcolor",
196
+ "fontcolor",
197
+ "fontname",
198
+ "fontpath",
199
+ "fontsize",
200
+ "label",
201
+ "labeljust",
202
+ "labelloc",
203
+ "layer",
204
+ "margin",
205
+ "mclimit",
206
+ "nodesep",
207
+ "nslimit",
208
+ "nslimit1",
209
+ "ordering",
210
+ "orientation",
211
+ "page",
212
+ "pagedir",
213
+ "quantum",
214
+ "rank",
215
+ "rankdir",
216
+ "ranksep",
217
+ "ratio",
218
+ "remincross",
219
+ "rotate",
220
+ "samplepoints",
221
+ "searchsize",
222
+ "size",
223
+ "style",
224
+ "URL"
225
+ ]
226
+
227
+ ## Const: Node attributs
228
+ NODESATTRS = [
229
+ "bottomlabel",
230
+ "color",
231
+ "comment",
232
+ "distortion",
233
+ "fillcolor",
234
+ "fixedsize",
235
+ "fontcolor",
236
+ "fontname",
237
+ "fontsize",
238
+ "group",
239
+ "height",
240
+ "label", "html",
241
+ "layer",
242
+ "orientation",
243
+ "peripheries",
244
+ "regular",
245
+ "shape",
246
+ "shapefile",
247
+ "sides",
248
+ "skew",
249
+ "style",
250
+ "toplabel",
251
+ "URL",
252
+ "width",
253
+ "z"
254
+ ]
255
+
256
+ ## Const: Edge attributs
257
+ EDGESATTRS = [
258
+ "arrowhead",
259
+ "arrowsize",
260
+ "arrowtail",
261
+ "color",
262
+ "constraint",
263
+ "decorate",
264
+ "dir",
265
+ "fontcolor",
266
+ "fontname",
267
+ "fontsize",
268
+ "headlabel",
269
+ "headport",
270
+ "hearURL",
271
+ "label",
272
+ "labelangle",
273
+ "labeldistance",
274
+ "labelfloat",
275
+ "labelfontcolor",
276
+ "labelfontname",
277
+ "labelfontsize",
278
+ "layer",
279
+ "lhead",
280
+ "ltail",
281
+ "minlen",
282
+ "samehead",
283
+ "sametail",
284
+ "style",
285
+ "taillael",
286
+ "tailport",
287
+ "tailURL",
288
+ "weight"
289
+ ]
290
+ end