forked from pattern-lab/patternlab-node
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpattern_graph_dot.js
More file actions
145 lines (123 loc) · 3.33 KB
/
pattern_graph_dot.js
File metadata and controls
145 lines (123 loc) · 3.33 KB
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
"use strict";
/**
* Overall settings
* @return {[string,string,string,string,string,string,string]}
*/
function header() {
return [
"strict digraph {",
'graph [fontname = "helvetica" size=20]',
/*compound=true;*/
"concentrate=true;",
"rankdir=LR;",
"ranksep=\"4 equally·\";",
"node [style=filled,color=white];",
"edge [style=dotted constraint=false]"
];
}
/**
* Graph nodes cannot start with numbers in GrahViz and must not contain dashes.
* @param name
* @return {string}
*/
const niceKey = function (name) {
return "O" + name.replace("-", "");
};
/**
* Adds the output for defining a node in GraphViz.
*
* @param {Pattern} pattern
* @return {string}
*/
function addNode(pattern) {
let more = "";
if (pattern.isPseudoPattern) {
more = " [fillcolor=grey]";
}
return "\"" + pattern.name + "\"" + more + ";\n";
}
/**
*
* @param {Pattern} from
* @param {Pattern} to
* @param {string} color A valid color, e.g. HTMl or a color name
* @return {string}
*/
function addEdge(from, to, color) {
return `"${from.name}" -> "${to.name}" [color=${color}];\n`;
}
/**
* Creates a sub-graph which is used to group atoms, molecules, etc.
* @param group
* @param patterns
* @return {[*,*,string,string,*,*,string]}
*/
function subGraph(group, patterns) {
const s = niceKey(group);
return [
"subgraph cluster_X" + s + " {",
"label=<<b>" + group + "</b>>;",
"style=filled;",
"color=lightgrey;",
s + " [shape=box];",
patterns.map(addNode).join(""),
//patterns.map(p => "\"" + p.name + "\"").join(" -> ") + "[style=invis]",
"}"
];
}
function footer() {
return ["}"];
}
const PatternGraphDot = {};
/**
* Create the GraphViz representation of the given graph
* @param patternGraph
* @return {string}
*/
PatternGraphDot.generate = function (patternGraph) {
const g = patternGraph.graph;
const patterns = patternGraph.patterns;
let buckets = new Map();
const colors = ["darkgreen", "firebrick", "slateblue", "darkgoldenrod", "black"];
const colorMap = new Map();
let colIdx = 0;
for (let p of patterns.partials.values()) {
if (p.isPseudoPattern || !p.patternType) {
continue;
}
let bucket = buckets.get(p.patternType);
if (bucket) {
bucket.push(p);
} else {
bucket = [p];
colorMap.set(p.patternType, colors[colIdx++]);
// Repeat if there are more categories
colIdx = colIdx % colors.length;
}
buckets.set(p.patternType, bucket);
}
let res = header();
const sortedKeys = Array.from(buckets.keys()).sort();
const niceKeys = sortedKeys.map(niceKey);
let subGraphLines = [];
for (let key of sortedKeys) {
const subPatterns = buckets.get(key);
subGraphLines = subGraphLines.concat(subGraph(key, subPatterns));
}
res = res.concat(subGraphLines);
res.push("edge[style=solid];");
foo: for (let edge of g.edges()) {
let fromTo = patternGraph.nodes2patterns([edge.v, edge.w]);
for (let pattern of fromTo) {
if (pattern.isPseudoPattern || !pattern.patternType) {
continue foo;
}
}
const thisColor = colorMap.get(fromTo[0].patternType);
res.push(addEdge(fromTo[0], fromTo[1], thisColor));
}
res.push(niceKeys.reverse().join(" -> ") + "[constraint=true];");
res = res.concat(footer());
return res.join("\n") + "\n";
};
module.exports = PatternGraphDot;