blob: 09f435c09b881be826797e7cbc0d0da495483235 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
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
103
104
105
106
107
108
109
110
111
112
113
114
115
|
dagre = require "dagre"
gdd = require "./git-deps-data.coffee"
# The list of constraints to feed into WebCola.
constraints = []
# Group nodes by row, as assigned by the y coordinates returned from
# dagre's layout(). This will map a y coordinate onto all nodes
# within that row.
row_groups = {}
# Expose a container for externally accessible objects. We can't
# directly expose the objects themselves because the references
# change each time they're constructed. However we don't need this
# trick for the constraints arrays since we can easily empty that by
# setting length to 0.
externs = {}
dagre_layout = ->
g = new dagre.graphlib.Graph()
externs.graph = g
# Set an object for the graph label
g.setGraph {}
# Default to assigning a new object as a label for each new edge.
g.setDefaultEdgeLabel -> {}
for node in gdd.nodes
g.setNode node.sha1,
label: node.name
width: node.rect_width or 70
height: node.rect_height or 30
for parent_sha1, children of gdd.deps
for child_sha1, bool of children
g.setEdge parent_sha1, child_sha1
dagre.layout g
return g
dagre_row_groups = ->
g = dagre_layout()
row_groups = {}
externs.row_groups = row_groups
for sha1 in g.nodes
x = g.node(sha1).x
y = g.node(sha1).y
row_groups[y] = [] unless y of row_groups
row_groups[y].push
sha1: sha1
x: x
return row_groups
build_constraints = ->
row_groups = dagre_row_groups()
constraints.length = 0 # FIXME: only rebuild constraints which changed
# We want alignment constraints between all nodes which dagre
# assigned the same y value.
for y of row_groups
row_nodes = row_groups[y]
# No point having an alignment group with only one node in.
if row_nodes.length > 1
constraints.push build_alignment_constraint(row_nodes)
# We also need separation constraints ensuring that the
# top-to-bottom ordering assigned by dagre is preserved. Since
# all nodes within a single row are already constrained to the
# same y coordinate from above, it should be enough to only
# have separation between a single node in adjacent rows.
row_y_coords = Object.keys(row_groups).sort()
i = 0
while i < row_y_coords.length - 1
upper_y = row_y_coords[i]
lower_y = row_y_coords[i + 1]
upper_node = row_groups[upper_y][0]
lower_node = row_groups[lower_y][0]
constraints.push
gap: 30
axis: "y"
left: gdd.node_index[upper_node.sha1]
right: gdd.node_index[lower_node.sha1]
i++
build_alignment_constraint = (row_nodes) ->
constraint =
axis: "y"
type: "alignment"
offsets: []
for i of row_nodes
node = row_nodes[i]
constraint.offsets.push
node: gdd.node_index[node.sha1]
offset: 0
return constraint
node = (sha1) ->
externs.graph.node sha1
module.exports =
# Variables
constraints: constraints
g: externs
# Functions
build_constraints: build_constraints
node: node
|