forked from skanaar/nomnoml
-
Notifications
You must be signed in to change notification settings - Fork 1
/
nomnoml.layouter.js
94 lines (87 loc) · 2.65 KB
/
nomnoml.layouter.js
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
var nomnoml = nomnoml || {}
nomnoml.Classifier = function (type, name, compartments){
return {
type: type,
name: name,
compartments: compartments
}
}
nomnoml.Compartment = function (lines, nodes, relations){
return {
lines: lines,
nodes: nodes,
relations: relations
}
}
nomnoml.layout = function (measurer, config, ast){
function runDagre(input){
return dagre.layout()
.rankSep(config.spacing)
.nodeSep(config.spacing)
.edgeSep(config.spacing)
.rankDir(config.direction)
.run(input)
}
function measureLines(lines, fontWeight){
if (!lines.length)
return { width: 0, height: config.padding }
measurer.setFont(config, fontWeight)
return {
width: Math.round(_.max(_.map(lines, measurer.textWidth)) + 2*config.padding),
height: Math.round(measurer.textHeight() * lines.length + 2*config.padding)
}
}
function layoutCompartment(c, compartmentIndex){
var textSize = measureLines(c.lines, compartmentIndex ? 'normal' : 'bold')
c.width = textSize.width
c.height = textSize.height
if (!c.nodes.length && !c.relations.length)
return
_.each(c.nodes, layoutClassifier)
var g = new dagre.Digraph()
_.each(c.nodes, function (e){
g.addNode(e.name, { width: e.width, height: e.height })
})
_.each(c.relations, function (r){
g.addEdge(r.id, r.start, r.end)
})
var dLayout = runDagre(g)
var rels = _.indexBy(c.relations, 'id')
var nodes = _.indexBy(c.nodes, 'name')
function toPoint(o){ return {x:o.x, y:o.y} }
dLayout.eachNode(function(u, value) {
nodes[u].x = value.x
nodes[u].y = value.y
})
dLayout.eachEdge(function(e, u, v, value) {
var start = nodes[u], end = nodes[v]
rels[e].path = _.map(_.flatten([start, value.points, end]), toPoint)
})
var graph = dLayout.graph()
var graphHeight = graph.height ? graph.height + 2*config.gutter : 0
var graphWidth = graph.width ? graph.width + 2*config.gutter : 0
c.width = Math.max(textSize.width, graphWidth) + 2*config.padding
c.height = textSize.height + graphHeight + config.padding
}
function layoutClassifier(clas){
var style = config.styles[clas.type] || nomnoml.styles.CLASS
if (style.hull == 'icon'){
clas.width = config.fontSize * 2.5
clas.height = config.fontSize * 2.5
return
}
if (style.hull === 'empty'){
clas.width = 0
clas.height = 0
return
}
_.each(clas.compartments, layoutCompartment)
clas.width = _.max(_.pluck(clas.compartments, 'width'))
clas.height = skanaar.sum(clas.compartments, 'height')
clas.x = clas.width/2
clas.y = clas.height/2
_.each(clas.compartments, function(co){ co.width = clas.width })
}
layoutCompartment(ast)
return ast
}