class GraphVizML
Attributes
css[RW]
fill[RW]
g[R]
stroke[RW]
text_color[RW]
Public Class Methods
new(obj=nil, debug: false, fill: 'transparent', stroke: '
click to toggle source
# File lib/graphvizml.rb, line 32 def initialize(obj=nil, debug: false, fill: 'transparent', stroke: '#000', text_color: '#000') @debug = debug @fill, @stroke, @text_color = fill, stroke, text_color if obj then xml = if obj.is_a? Rexle or obj.is_a? Rexle::Element obj.xml else s = RXFHelper.read(obj).first if s =~ /<\?graphvizml\b/ then import_string s else if @debug then #File.write '/tmp/graphviz.xml', xml puts('graphvizml xml: ' + s.inspect) end s end end @g = build_from_nodes Domle.new(xml) end @css = " .node ellipse {stroke: #{stroke}; fill: #{fill}} .node text {fill: #{text_color}} .edge path {stroke: #{stroke}} .edge polygon {stroke: #{stroke}; fill: #{stroke}} " end
Public Instance Methods
import(obj)
click to toggle source
# File lib/graphvizml.rb, line 78 def import(obj) s = RXFHelper.read(obj).first xml = import_string s puts('graphvizml/import xml: ' + xml.inspect).debug if @debug @g = build_from_nodes Domle.new(xml) self end
to_dot()
click to toggle source
# File lib/graphvizml.rb, line 89 def to_dot() @g.to_dot end
to_svg()
click to toggle source
returns an SVG blob
# File lib/graphvizml.rb, line 96 def to_svg() f = Tempfile.new('graphvizml') Graphviz::output(@g, format: 'svg', path: f.path) s = File.read f.path #s.sub!('xmlns:xlink="http://www.w3.org/1999/xlink"','') #s.sub!('xlink:','') # not yet implemented because of a local namespace issue s.lines.insert(8, css_code()).join end
Private Instance Methods
build_from_nodes(doc)
click to toggle source
# File lib/graphvizml.rb, line 109 def build_from_nodes(doc) puts 'inside build_from_nodes'.info if @debug g = Graphviz::Graph.new format_summary_attributes(doc.root.attributes) # add the nodes nodes = doc.root.xpath('//node').inject({}) do |r,e| r.merge fetch_node(e) end if @debug then puts 'nodes: ' + nodes.inspect puts 'doc: ' + doc.root.xml.inspect end a = doc.root.element('style/text()').to_s.strip.split(/}/).map do |entry| puts 'entry: ' + entry.inspect if @debug raw_selector,raw_styles = entry.split(/{/,2) h = raw_styles.strip.split(/;/).inject({}) do |r, x| k, v = x.split(/:/,2).map(&:strip) r.merge(k.to_sym => v) end [raw_selector.split(/,\s*/).map(&:strip), h] end puts ' a: ' + a.inspect if @debug edge_style = a.any? ? a.find {|x| x[0].grep(/edge/).any?}.last : [] # add the edges id_1 = nodes.first[0] nodes[id_1][-1] = g.add_node(nodes[id_1][0]) doc.root.each_recursive do |node| next unless node.name == 'node' node.xpath('a/node | node').each do |child| id1, id2 = node.object_id, child.object_id label = child.attributes[:connection].to_s puts('nodes[id1]: ' + nodes[id1].inspect) if @debug puts('nodes[id1].last: ' + nodes[id1].last.inspect) if @debug nodes[id2][-1] ||= nodes[id1].last.add_node(nodes[id2][0]) attributes = child.style.merge({label: label}) conn = nodes[id1][-1].connections.last conn.attributes[:label] = label edge_style.each {|key,val| conn.attributes[key] = m(val) } end end format_attributes nodes g end
css_code()
click to toggle source
# File lib/graphvizml.rb, line 183 def css_code() <<EOF <defs> <style type='text/css'><![CDATA[ #{@css} ]]></style> </defs> EOF end
fetch_node(node)
click to toggle source
# File lib/graphvizml.rb, line 194 def fetch_node(node) puts 'inside fetch_node'.info if @debug h = node.attributes #puts 'h: ' + h.inspect puts('graphvizml/fetch_node h: ' + h.inspect) if @debug if node.parent.name == 'a' then url = node.parent.attributes[:href] h[:url] = url if url end id = h[:gid] || node.object_id label = node.text('label') # shape options: box, ellipse, record, diamond, circle, polygon, point style = {} style[:shape] = h[:shape] if h[:shape] and !h[:shape].empty? style[:URL] = h[:url] if h[:url] #puts "adding node id: %s label: %s" % [id, label] # the nil is replaced by the Graphviz node object {id => [label, node.style.merge(style), nil]} end
format_attributes(nodes)
click to toggle source
# File lib/graphvizml.rb, line 226 def format_attributes(nodes) nodes.each do |id, x| _, attributes, obj = x next unless obj attributes.each {|key, val| obj.attributes[key] = m(val) } end end
format_summary_attributes(h)
click to toggle source
# File lib/graphvizml.rb, line 238 def format_summary_attributes(h) type = (h.has_key?(:type) ? h[:type].to_sym : :digraph) h[:type] = type.to_s h[:rankdir] = h.has_key?(:direction) ? h[:direction].to_s.upcase : 'LR' %i(recordx_type format_mask schema direction).each do |x| h.delete x; h.delete x.to_s end # remove any entries with an empty value h.each {|key, value| h.delete key if value.empty?} h end
import_string(s)
click to toggle source
# File lib/graphvizml.rb, line 256 def import_string(s) s2 = s.slice!(/<\?graphvizml\b[^>]*\?>/) if s2 then attributes = %w(id fill stroke text_color).inject({}) do |r, keyword| found = s2[/(?<=#{keyword}=['"])[^'"]+/] found ? r.merge(keyword.to_sym => found) : r end fill, stroke, text_color = %i(fill stroke text_color).map do |x| attributes[x] ? attributes[x] : method(x).call end @css = " .node ellipse {stroke: #{stroke}; fill: #{fill}} .node text {fill: #{text_color}} .edge path {stroke: #{stroke}} .edge polygon {stroke: #{stroke}; fill: #{stroke}} " end xml = LineTree.new(s, root: 'nodes', debug: @debug).to_xml end
m(s)
click to toggle source
modify the value if it matches the following criteria
# File lib/graphvizml.rb, line 287 def m(s) # is it a shorthand hexcode? e.g. #fff s.gsub(/^#([\da-f]{3})$/)\ { '#' + ($1).chars.inject([]) {|r,x| r << x + x}.join} end