Class: Graphdown::Graph

Inherits:
Object
  • Object
show all
Defined in:
lib/graphdown/graph.rb

Constant Summary collapse

PADDING =
10

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeGraph

Returns a new instance of Graph.



9
10
11
12
13
# File 'lib/graphdown/graph.rb', line 9

def initialize
  @nodes = []
  @width = 0
  @height = 0
end

Instance Attribute Details

#nodesObject (readonly)

Returns the value of attribute nodes.



5
6
7
# File 'lib/graphdown/graph.rb', line 5

def nodes
  @nodes
end

Instance Method Details

#<<(node) ⇒ Object



15
16
17
18
# File 'lib/graphdown/graph.rb', line 15

def <<(node)
  labels = @nodes.map(&:label)
  @nodes << node unless labels.include?(node.label)
end

#find_node_by_label(label) ⇒ Object



20
21
22
# File 'lib/graphdown/graph.rb', line 20

def find_node_by_label(label)
  (@nodes || []).select { |node| node.label == label }.first
end

#layer_nodesObject



28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/graphdown/graph.rb', line 28

def layer_nodes
  nodes_with_level = @nodes.select { |node| node.level >= 1 }
  begin
    diff_total = 0
    nodes_with_level.each do |node|
      node.children.each do |child|
        if node.level >= child.level
          child.level += node.level + 1
          diff_total += node.level + 1
        end
      end
    end
  end while diff_total != 0
end

#layered_nodesObject



24
25
26
# File 'lib/graphdown/graph.rb', line 24

def layered_nodes
  @layered_nodes ||= @nodes.sort_by(&:level).group_by(&:level).values
end

#layout_edgesObject



60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/graphdown/graph.rb', line 60

def layout_edges
  @nodes.each do |node|
    node.child_edges.each_with_index do |edge, index|
      edge.origin.x = node.x + (node.width.to_f * (index + 1) / (node.child_edges.count + 1))
      edge.origin.y = node.y + node.height
    end

    node.parent_edges.each_with_index do |edge, index|
      edge.target.x = node.x + (node.width.to_f * (index + 1) / (node.parent_edges.count + 1))
      edge.target.y = node.y
    end
  end
end

#layout_nodesObject



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/graphdown/graph.rb', line 43

def layout_nodes
  layer_widths = []
  layer_offset = PADDING
  layered_nodes.each do |nodes|
    node_offset = PADDING
    nodes.each do |node|
      node.x = node_offset
      node.y = layer_offset
      node_offset += node.width + Node::MARGIN_RIGHT
    end
    layer_widths << node_offset + PADDING
    layer_offset += nodes.map(&:height).max + Node::MARGIN_BOTTOM
  end
  @width = layer_widths.max
  @height = layer_offset + PADDING
end

#to_svgObject



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/graphdown/graph.rb', line 74

def to_svg
  svg = SVGen::SVG.new(width: @width, height: @height) do |svg|
    # nodes
    svg.g(fill: "none", stroke: "black") do |g|
      @nodes.each do |node|
        g.rect(x: node.x, y: node.y, width: node.width, height: node.height)
      end
    end

    # texts
    svg.g("font-size" => Node::FONT_SIZE, "font-family" => Node::FONT_FAMILY, "text-anchor" => "middle") do |g|
      @nodes.each do |node|
        g.text(node.label, x: node.x + node.width / 2, y: node.y + Node::WORD_HEIGHT + Node::PADDING_TOP / 2)
      end
    end

    # edges
    svg.g(stroke: "black", "stroke-width" => 2) do |g|
      @nodes.each do |node|
        node.child_edges.each do |edge|
          g.path(d: edge.line_d, fill: "none")
          g.path(d: edge.arrow_d, fill: "black") if edge.forward?
          g.path(d: edge.reverse_arrow_d, fill: "black") if edge.backward?
        end
      end
    end
  end
  svg.generate
end