@statewalker/fsm-charts 0.2.4 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +206 -1
- package/dist/StateChart-cXyVRcs-.d.ts +94 -0
- package/dist/StateChart-cXyVRcs-.d.ts.map +1 -0
- package/dist/StateChartIndex-BK2315qj.d.ts +142 -0
- package/dist/StateChartIndex-BK2315qj.d.ts.map +1 -0
- package/dist/StateChartIndex-BOIrc_nq.js +355 -0
- package/dist/StateChartIndex-BOIrc_nq.js.map +1 -0
- package/dist/buildStatechartsPanel-CxQlIwTh.js +494 -0
- package/dist/buildStatechartsPanel-CxQlIwTh.js.map +1 -0
- package/dist/buildStatechartsPanel-hCtZbdiF.d.ts +79 -0
- package/dist/buildStatechartsPanel-hCtZbdiF.d.ts.map +1 -0
- package/dist/defineProperty-C0rC37pP.js +39 -0
- package/dist/description-panels-DI2MNlbK.js +184 -0
- package/dist/description-panels-DI2MNlbK.js.map +1 -0
- package/dist/getLabelDimensions-BY0q7j3D.d.ts +79 -0
- package/dist/getLabelDimensions-BY0q7j3D.d.ts.map +1 -0
- package/dist/getPadding-Cw0e7G2v.js +25 -0
- package/dist/getPadding-Cw0e7G2v.js.map +1 -0
- package/dist/index-config.d.ts +3 -12
- package/dist/index-config.js +2 -1
- package/dist/index-dom.d.ts +2 -49
- package/dist/index-dom.js +2 -1
- package/dist/index-html.d.ts +3 -2
- package/dist/index-html.js +2 -2
- package/dist/index-layout.d.ts +3 -77
- package/dist/index-layout.js +2 -2
- package/dist/index-runtime.d.ts +3 -141
- package/dist/index-runtime.js +2 -1
- package/dist/index.d.ts +11 -10
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -6
- package/dist/layout-Dp671N6q.js +2465 -0
- package/dist/layout-Dp671N6q.js.map +1 -0
- package/dist/newTreeBuilder-CvtLDjGj.d.ts +54 -0
- package/dist/newTreeBuilder-CvtLDjGj.d.ts.map +1 -0
- package/dist/toFsmStateConfig-DlJkyZni.js +135 -0
- package/dist/toFsmStateConfig-DlJkyZni.js.map +1 -0
- package/dist/toFsmStateConfig-DmOlTRjv.d.ts +15 -0
- package/dist/toFsmStateConfig-DmOlTRjv.d.ts.map +1 -0
- package/package.json +54 -28
- package/src/config/concatTransitionsToString.ts +4 -4
- package/src/config/index.ts +4 -4
- package/src/config/serializeProcessConfig.ts +3 -3
- package/src/config/splitTransitionString.ts +2 -4
- package/src/config/toFsmStateConfig.ts +5 -12
- package/src/dagre/acyclic.js +9 -10
- package/src/dagre/add-border-segments.js +11 -7
- package/src/dagre/coordinate-system.js +12 -12
- package/src/dagre/data/list.js +2 -2
- package/src/dagre/debug.d.ts +1 -1
- package/src/dagre/debug.js +11 -11
- package/src/dagre/greedy-fas.js +17 -21
- package/src/dagre/index.d.ts +4 -4
- package/src/dagre/index.js +4 -4
- package/src/dagre/layout.js +107 -96
- package/src/dagre/nesting-graph.js +13 -19
- package/src/dagre/normalize.js +7 -7
- package/src/dagre/order/add-subgraph-constraints.js +2 -2
- package/src/dagre/order/barycenter.d.ts +1 -1
- package/src/dagre/order/barycenter.js +4 -4
- package/src/dagre/order/build-layer-graph.d.ts +1 -1
- package/src/dagre/order/build-layer-graph.js +7 -9
- package/src/dagre/order/cross-count.js +14 -17
- package/src/dagre/order/index.js +19 -17
- package/src/dagre/order/init-order.js +5 -15
- package/src/dagre/order/resolve-conflicts.js +10 -14
- package/src/dagre/order/sort-subgraph.d.ts +1 -1
- package/src/dagre/order/sort-subgraph.js +13 -14
- package/src/dagre/order/sort.d.ts +1 -1
- package/src/dagre/order/sort.js +6 -10
- package/src/dagre/parent-dummy-chains.js +10 -4
- package/src/dagre/position/bk.d.ts +3 -3
- package/src/dagre/position/bk.js +84 -65
- package/src/dagre/position/index.js +7 -11
- package/src/dagre/rank/feasible-tree.d.ts +1 -1
- package/src/dagre/rank/feasible-tree.js +6 -6
- package/src/dagre/rank/index.js +6 -6
- package/src/dagre/rank/network-simplex.d.ts +0 -1
- package/src/dagre/rank/network-simplex.js +20 -25
- package/src/dagre/rank/util.js +2 -6
- package/src/dagre/util.d.ts +12 -6
- package/src/dagre/util.js +31 -37
- package/src/dom/buildSections.ts +15 -19
- package/src/dom/description-panels.ts +5 -7
- package/src/dom/getStatesDescriptions.ts +4 -10
- package/src/full/index.ts +1 -1
- package/src/full/toFsmStateCharts.ts +11 -11
- package/src/graphlib/alg/components.js +2 -2
- package/src/graphlib/alg/dfs.js +5 -5
- package/src/graphlib/alg/dijkstra-all.js +4 -4
- package/src/graphlib/alg/dijkstra.js +9 -12
- package/src/graphlib/alg/find-cycles.js +7 -5
- package/src/graphlib/alg/floyd-warshall.js +8 -11
- package/src/graphlib/alg/index.d.ts +11 -11
- package/src/graphlib/alg/index.js +11 -11
- package/src/graphlib/alg/is-acyclic.js +1 -1
- package/src/graphlib/alg/postorder.js +2 -2
- package/src/graphlib/alg/preorder.js +2 -2
- package/src/graphlib/alg/prim.d.ts +1 -1
- package/src/graphlib/alg/prim.js +5 -5
- package/src/graphlib/alg/tarjan.js +3 -3
- package/src/graphlib/alg/topsort.js +1 -1
- package/src/graphlib/data/priority-queue.js +8 -10
- package/src/graphlib/graph.js +53 -52
- package/src/graphlib/index.d.ts +2 -2
- package/src/graphlib/index.js +2 -2
- package/src/graphlib/json.d.ts +1 -1
- package/src/graphlib/json.js +6 -6
- package/src/html/buildStatechartCss.ts +2 -2
- package/src/html/buildStatechartStyles.ts +5 -15
- package/src/html/buildStatechartSvg.ts +8 -20
- package/src/html/buildStatechartsPanel.ts +3 -5
- package/src/html/index.ts +4 -4
- package/src/index-config.ts +2 -2
- package/src/index-dom.ts +1 -1
- package/src/index-html.ts +2 -2
- package/src/index-layout.ts +2 -2
- package/src/index-runtime.ts +2 -2
- package/src/index.ts +8 -8
- package/src/layout/buildCharts.ts +6 -7
- package/src/layout/buildFlatCharts.ts +17 -21
- package/src/layout/getGraphParamsProvider.ts +7 -19
- package/src/layout/getLabelDimensions.ts +5 -5
- package/src/layout/index.ts +5 -4
- package/src/lodash-es/index.ts +2 -2
- package/src/lodash-es/types.ts +37 -35
- package/src/runtime/RuntimeStatechartApi.ts +13 -46
- package/src/runtime/StateChartIndex.ts +7 -24
- package/src/runtime/index.ts +2 -2
- package/src/types/FsmStateConfig.ts +1 -1
- package/src/types/GraphParamsProvider.ts +3 -6
- package/src/types/Position.ts +1 -1
- package/src/types/StateChart.ts +2 -2
- package/src/types/StateGraphEdge.ts +2 -2
- package/src/types/StateGraphNode.ts +2 -2
- package/src/types/TransitionsGraph.ts +4 -4
- package/src/types/index.ts +11 -11
- package/src/utils/BasisCurve.ts +6 -15
- package/src/utils/domToText.ts +3 -7
- package/src/utils/getPadding.ts +2 -3
- package/src/utils/newId.ts +2 -1
- package/src/utils/newRegistry.ts +13 -13
- package/src/utils/serializeAttrs.ts +6 -14
- package/src/utils/serializeCss.ts +3 -7
- package/src/utils/serializeStyle.ts +2 -5
- package/src/utils/toKebabCase.ts +1 -4
- package/CHANGELOG.md +0 -1
- package/dist/StateChart-BYBjTmC2.d.ts +0 -82
- package/dist/chunk-36ZLXJVD.js +0 -606
- package/dist/chunk-AZBRQNTU.js +0 -2739
- package/dist/chunk-FIQDLBWD.js +0 -9
- package/dist/chunk-SVKVQY7B.js +0 -133
- package/dist/chunk-TZHCBZVP.js +0 -422
- package/dist/chunk-VILLJJJD.js +0 -231
- package/dist/index-html-DgSCNHkR.d.ts +0 -75
|
@@ -0,0 +1,2465 @@
|
|
|
1
|
+
import { t as getPadding } from "./getPadding-Cw0e7G2v.js";
|
|
2
|
+
//#region src/lodash-es/index.ts
|
|
3
|
+
let _ = { constant: (value) => () => value };
|
|
4
|
+
function setLodash(lib) {
|
|
5
|
+
_ = lib;
|
|
6
|
+
}
|
|
7
|
+
function getLodash() {
|
|
8
|
+
return _;
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/graphlib/graph.js
|
|
12
|
+
var DEFAULT_EDGE_NAME = "\0";
|
|
13
|
+
var GRAPH_NODE = "\0";
|
|
14
|
+
var EDGE_KEY_DELIM = "";
|
|
15
|
+
var Graph = class {
|
|
16
|
+
constructor(opts = {}) {
|
|
17
|
+
this._isDirected = _.has(opts, "directed") ? opts.directed : true;
|
|
18
|
+
this._isMultigraph = _.has(opts, "multigraph") ? opts.multigraph : false;
|
|
19
|
+
this._isCompound = _.has(opts, "compound") ? opts.compound : false;
|
|
20
|
+
this._label = void 0;
|
|
21
|
+
this._defaultNodeLabelFn = _.constant(void 0);
|
|
22
|
+
this._defaultEdgeLabelFn = _.constant(void 0);
|
|
23
|
+
this._nodes = {};
|
|
24
|
+
if (this._isCompound) {
|
|
25
|
+
this._parent = {};
|
|
26
|
+
this._children = {};
|
|
27
|
+
this._children[GRAPH_NODE] = {};
|
|
28
|
+
}
|
|
29
|
+
this._in = {};
|
|
30
|
+
this._preds = {};
|
|
31
|
+
this._out = {};
|
|
32
|
+
this._sucs = {};
|
|
33
|
+
this._edgeObjs = {};
|
|
34
|
+
this._edgeLabels = {};
|
|
35
|
+
}
|
|
36
|
+
isDirected() {
|
|
37
|
+
return this._isDirected;
|
|
38
|
+
}
|
|
39
|
+
isMultigraph() {
|
|
40
|
+
return this._isMultigraph;
|
|
41
|
+
}
|
|
42
|
+
isCompound() {
|
|
43
|
+
return this._isCompound;
|
|
44
|
+
}
|
|
45
|
+
setGraph(label) {
|
|
46
|
+
this._label = label;
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
graph() {
|
|
50
|
+
return this._label;
|
|
51
|
+
}
|
|
52
|
+
setDefaultNodeLabel(newDefault) {
|
|
53
|
+
if (!_.isFunction(newDefault)) newDefault = _.constant(newDefault);
|
|
54
|
+
this._defaultNodeLabelFn = newDefault;
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
nodeCount() {
|
|
58
|
+
return this._nodeCount;
|
|
59
|
+
}
|
|
60
|
+
nodes() {
|
|
61
|
+
return _.keys(this._nodes);
|
|
62
|
+
}
|
|
63
|
+
sources() {
|
|
64
|
+
return _.filter(this.nodes(), (v) => _.isEmpty(this._in[v]));
|
|
65
|
+
}
|
|
66
|
+
sinks() {
|
|
67
|
+
return _.filter(this.nodes(), (v) => _.isEmpty(this._out[v]));
|
|
68
|
+
}
|
|
69
|
+
setNodes(vs, value) {
|
|
70
|
+
var args = arguments;
|
|
71
|
+
_.each(vs, (v) => {
|
|
72
|
+
if (args.length > 1) this.setNode(v, value);
|
|
73
|
+
else this.setNode(v);
|
|
74
|
+
});
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
setNode(v, value) {
|
|
78
|
+
if (_.has(this._nodes, v)) {
|
|
79
|
+
if (arguments.length > 1) this._nodes[v] = value;
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
this._nodes[v] = arguments.length > 1 ? value : this._defaultNodeLabelFn(v);
|
|
83
|
+
if (this._isCompound) {
|
|
84
|
+
this._parent[v] = GRAPH_NODE;
|
|
85
|
+
this._children[v] = {};
|
|
86
|
+
this._children[GRAPH_NODE][v] = true;
|
|
87
|
+
}
|
|
88
|
+
this._in[v] = {};
|
|
89
|
+
this._preds[v] = {};
|
|
90
|
+
this._out[v] = {};
|
|
91
|
+
this._sucs[v] = {};
|
|
92
|
+
++this._nodeCount;
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
node(v) {
|
|
96
|
+
return this._nodes[v];
|
|
97
|
+
}
|
|
98
|
+
hasNode(v) {
|
|
99
|
+
return _.has(this._nodes, v);
|
|
100
|
+
}
|
|
101
|
+
removeNode(v) {
|
|
102
|
+
if (_.has(this._nodes, v)) {
|
|
103
|
+
var removeEdge = (e) => {
|
|
104
|
+
this.removeEdge(this._edgeObjs[e]);
|
|
105
|
+
};
|
|
106
|
+
delete this._nodes[v];
|
|
107
|
+
if (this._isCompound) {
|
|
108
|
+
this._removeFromParentsChildList(v);
|
|
109
|
+
delete this._parent[v];
|
|
110
|
+
_.each(this.children(v), (child) => {
|
|
111
|
+
this.setParent(child);
|
|
112
|
+
});
|
|
113
|
+
delete this._children[v];
|
|
114
|
+
}
|
|
115
|
+
_.each(_.keys(this._in[v]), removeEdge);
|
|
116
|
+
delete this._in[v];
|
|
117
|
+
delete this._preds[v];
|
|
118
|
+
_.each(_.keys(this._out[v]), removeEdge);
|
|
119
|
+
delete this._out[v];
|
|
120
|
+
delete this._sucs[v];
|
|
121
|
+
--this._nodeCount;
|
|
122
|
+
}
|
|
123
|
+
return this;
|
|
124
|
+
}
|
|
125
|
+
setParent(v, parent) {
|
|
126
|
+
if (!this._isCompound) throw new Error("Cannot set parent in a non-compound graph");
|
|
127
|
+
if (_.isUndefined(parent)) parent = GRAPH_NODE;
|
|
128
|
+
else {
|
|
129
|
+
parent += "";
|
|
130
|
+
for (var ancestor = parent; !_.isUndefined(ancestor); ancestor = this.parent(ancestor)) if (ancestor === v) throw new Error(`Setting ${parent} as parent of ${v} would create a cycle`);
|
|
131
|
+
this.setNode(parent);
|
|
132
|
+
}
|
|
133
|
+
this.setNode(v);
|
|
134
|
+
this._removeFromParentsChildList(v);
|
|
135
|
+
this._parent[v] = parent;
|
|
136
|
+
this._children[parent][v] = true;
|
|
137
|
+
return this;
|
|
138
|
+
}
|
|
139
|
+
_removeFromParentsChildList(v) {
|
|
140
|
+
delete this._children[this._parent[v]][v];
|
|
141
|
+
}
|
|
142
|
+
parent(v) {
|
|
143
|
+
if (this._isCompound) {
|
|
144
|
+
var parent = this._parent[v];
|
|
145
|
+
if (parent !== GRAPH_NODE) return parent;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
children(v) {
|
|
149
|
+
if (_.isUndefined(v)) v = GRAPH_NODE;
|
|
150
|
+
if (this._isCompound) {
|
|
151
|
+
var children = this._children[v];
|
|
152
|
+
if (children) return _.keys(children);
|
|
153
|
+
} else if (v === GRAPH_NODE) return this.nodes();
|
|
154
|
+
else if (this.hasNode(v)) return [];
|
|
155
|
+
}
|
|
156
|
+
predecessors(v) {
|
|
157
|
+
var predsV = this._preds[v];
|
|
158
|
+
if (predsV) return _.keys(predsV);
|
|
159
|
+
}
|
|
160
|
+
successors(v) {
|
|
161
|
+
var sucsV = this._sucs[v];
|
|
162
|
+
if (sucsV) return _.keys(sucsV);
|
|
163
|
+
}
|
|
164
|
+
neighbors(v) {
|
|
165
|
+
var preds = this.predecessors(v);
|
|
166
|
+
if (preds) return _.union(preds, this.successors(v));
|
|
167
|
+
}
|
|
168
|
+
isLeaf(v) {
|
|
169
|
+
var neighbors;
|
|
170
|
+
if (this.isDirected()) neighbors = this.successors(v);
|
|
171
|
+
else neighbors = this.neighbors(v);
|
|
172
|
+
return neighbors.length === 0;
|
|
173
|
+
}
|
|
174
|
+
filterNodes(filter) {
|
|
175
|
+
var copy = new this.constructor({
|
|
176
|
+
directed: this._isDirected,
|
|
177
|
+
multigraph: this._isMultigraph,
|
|
178
|
+
compound: this._isCompound
|
|
179
|
+
});
|
|
180
|
+
copy.setGraph(this.graph());
|
|
181
|
+
var self = this;
|
|
182
|
+
_.each(this._nodes, (value, v) => {
|
|
183
|
+
if (filter(v)) copy.setNode(v, value);
|
|
184
|
+
});
|
|
185
|
+
_.each(this._edgeObjs, (e) => {
|
|
186
|
+
if (copy.hasNode(e.v) && copy.hasNode(e.w)) copy.setEdge(e, self.edge(e));
|
|
187
|
+
});
|
|
188
|
+
var parents = {};
|
|
189
|
+
function findParent(v) {
|
|
190
|
+
var parent = self.parent(v);
|
|
191
|
+
if (parent === void 0 || copy.hasNode(parent)) {
|
|
192
|
+
parents[v] = parent;
|
|
193
|
+
return parent;
|
|
194
|
+
} else if (parent in parents) return parents[parent];
|
|
195
|
+
else return findParent(parent);
|
|
196
|
+
}
|
|
197
|
+
if (this._isCompound) _.each(copy.nodes(), (v) => {
|
|
198
|
+
copy.setParent(v, findParent(v));
|
|
199
|
+
});
|
|
200
|
+
return copy;
|
|
201
|
+
}
|
|
202
|
+
setDefaultEdgeLabel(newDefault) {
|
|
203
|
+
if (!_.isFunction(newDefault)) newDefault = _.constant(newDefault);
|
|
204
|
+
this._defaultEdgeLabelFn = newDefault;
|
|
205
|
+
return this;
|
|
206
|
+
}
|
|
207
|
+
edgeCount() {
|
|
208
|
+
return this._edgeCount;
|
|
209
|
+
}
|
|
210
|
+
edges() {
|
|
211
|
+
return _.values(this._edgeObjs);
|
|
212
|
+
}
|
|
213
|
+
setPath(vs, value) {
|
|
214
|
+
var args = arguments;
|
|
215
|
+
_.reduce(vs, (v, w) => {
|
|
216
|
+
if (args.length > 1) this.setEdge(v, w, value);
|
|
217
|
+
else this.setEdge(v, w);
|
|
218
|
+
return w;
|
|
219
|
+
});
|
|
220
|
+
return this;
|
|
221
|
+
}
|
|
222
|
+
setEdge() {
|
|
223
|
+
var v, w, name, value;
|
|
224
|
+
var valueSpecified = false;
|
|
225
|
+
var arg0 = arguments[0];
|
|
226
|
+
if (typeof arg0 === "object" && arg0 !== null && "v" in arg0) {
|
|
227
|
+
v = arg0.v;
|
|
228
|
+
w = arg0.w;
|
|
229
|
+
name = arg0.name;
|
|
230
|
+
if (arguments.length === 2) {
|
|
231
|
+
value = arguments[1];
|
|
232
|
+
valueSpecified = true;
|
|
233
|
+
}
|
|
234
|
+
} else {
|
|
235
|
+
v = arg0;
|
|
236
|
+
w = arguments[1];
|
|
237
|
+
name = arguments[3];
|
|
238
|
+
if (arguments.length > 2) {
|
|
239
|
+
value = arguments[2];
|
|
240
|
+
valueSpecified = true;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
v = `${v}`;
|
|
244
|
+
w = `${w}`;
|
|
245
|
+
if (!_.isUndefined(name)) name = `${name}`;
|
|
246
|
+
var e = edgeArgsToId(this._isDirected, v, w, name);
|
|
247
|
+
if (_.has(this._edgeLabels, e)) {
|
|
248
|
+
if (valueSpecified) this._edgeLabels[e] = value;
|
|
249
|
+
return this;
|
|
250
|
+
}
|
|
251
|
+
if (!_.isUndefined(name) && !this._isMultigraph) throw new Error("Cannot set a named edge when isMultigraph = false");
|
|
252
|
+
this.setNode(v);
|
|
253
|
+
this.setNode(w);
|
|
254
|
+
this._edgeLabels[e] = valueSpecified ? value : this._defaultEdgeLabelFn(v, w, name);
|
|
255
|
+
var edgeObj = edgeArgsToObj(this._isDirected, v, w, name);
|
|
256
|
+
v = edgeObj.v;
|
|
257
|
+
w = edgeObj.w;
|
|
258
|
+
Object.freeze(edgeObj);
|
|
259
|
+
this._edgeObjs[e] = edgeObj;
|
|
260
|
+
incrementOrInitEntry(this._preds[w], v);
|
|
261
|
+
incrementOrInitEntry(this._sucs[v], w);
|
|
262
|
+
this._in[w][e] = edgeObj;
|
|
263
|
+
this._out[v][e] = edgeObj;
|
|
264
|
+
this._edgeCount++;
|
|
265
|
+
return this;
|
|
266
|
+
}
|
|
267
|
+
edge(v, w, name) {
|
|
268
|
+
var e = arguments.length === 1 ? edgeObjToId(this._isDirected, arguments[0]) : edgeArgsToId(this._isDirected, v, w, name);
|
|
269
|
+
return this._edgeLabels[e];
|
|
270
|
+
}
|
|
271
|
+
hasEdge(v, w, name) {
|
|
272
|
+
var e = arguments.length === 1 ? edgeObjToId(this._isDirected, arguments[0]) : edgeArgsToId(this._isDirected, v, w, name);
|
|
273
|
+
return _.has(this._edgeLabels, e);
|
|
274
|
+
}
|
|
275
|
+
removeEdge(v, w, name) {
|
|
276
|
+
var e = arguments.length === 1 ? edgeObjToId(this._isDirected, arguments[0]) : edgeArgsToId(this._isDirected, v, w, name);
|
|
277
|
+
var edge = this._edgeObjs[e];
|
|
278
|
+
if (edge) {
|
|
279
|
+
v = edge.v;
|
|
280
|
+
w = edge.w;
|
|
281
|
+
delete this._edgeLabels[e];
|
|
282
|
+
delete this._edgeObjs[e];
|
|
283
|
+
decrementOrRemoveEntry(this._preds[w], v);
|
|
284
|
+
decrementOrRemoveEntry(this._sucs[v], w);
|
|
285
|
+
delete this._in[w][e];
|
|
286
|
+
delete this._out[v][e];
|
|
287
|
+
this._edgeCount--;
|
|
288
|
+
}
|
|
289
|
+
return this;
|
|
290
|
+
}
|
|
291
|
+
inEdges(v, u) {
|
|
292
|
+
var inV = this._in[v];
|
|
293
|
+
if (inV) {
|
|
294
|
+
var edges = _.values(inV);
|
|
295
|
+
if (!u) return edges;
|
|
296
|
+
return _.filter(edges, (edge) => edge.v === u);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
outEdges(v, w) {
|
|
300
|
+
var outV = this._out[v];
|
|
301
|
+
if (outV) {
|
|
302
|
+
var edges = _.values(outV);
|
|
303
|
+
if (!w) return edges;
|
|
304
|
+
return _.filter(edges, (edge) => edge.w === w);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
nodeEdges(v, w) {
|
|
308
|
+
var inEdges = this.inEdges(v, w);
|
|
309
|
+
if (inEdges) return inEdges.concat(this.outEdges(v, w));
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
Graph.prototype._nodeCount = 0;
|
|
313
|
+
Graph.prototype._edgeCount = 0;
|
|
314
|
+
function incrementOrInitEntry(map, k) {
|
|
315
|
+
if (map[k]) map[k]++;
|
|
316
|
+
else map[k] = 1;
|
|
317
|
+
}
|
|
318
|
+
function decrementOrRemoveEntry(map, k) {
|
|
319
|
+
if (!--map[k]) delete map[k];
|
|
320
|
+
}
|
|
321
|
+
function edgeArgsToId(isDirected, v_, w_, name) {
|
|
322
|
+
var v = `${v_}`;
|
|
323
|
+
var w = `${w_}`;
|
|
324
|
+
if (!isDirected && v > w) {
|
|
325
|
+
var tmp = v;
|
|
326
|
+
v = w;
|
|
327
|
+
w = tmp;
|
|
328
|
+
}
|
|
329
|
+
return v + EDGE_KEY_DELIM + w + EDGE_KEY_DELIM + (_.isUndefined(name) ? DEFAULT_EDGE_NAME : name);
|
|
330
|
+
}
|
|
331
|
+
function edgeArgsToObj(isDirected, v_, w_, name) {
|
|
332
|
+
var v = `${v_}`;
|
|
333
|
+
var w = `${w_}`;
|
|
334
|
+
if (!isDirected && v > w) {
|
|
335
|
+
var tmp = v;
|
|
336
|
+
v = w;
|
|
337
|
+
w = tmp;
|
|
338
|
+
}
|
|
339
|
+
var edgeObj = {
|
|
340
|
+
v,
|
|
341
|
+
w
|
|
342
|
+
};
|
|
343
|
+
if (name) edgeObj.name = name;
|
|
344
|
+
return edgeObj;
|
|
345
|
+
}
|
|
346
|
+
function edgeObjToId(isDirected, edgeObj) {
|
|
347
|
+
return edgeArgsToId(isDirected, edgeObj.v, edgeObj.w, edgeObj.name);
|
|
348
|
+
}
|
|
349
|
+
//#endregion
|
|
350
|
+
//#region src/dagre/data/list.js
|
|
351
|
+
var List = class {
|
|
352
|
+
constructor() {
|
|
353
|
+
var sentinel = {};
|
|
354
|
+
sentinel._next = sentinel._prev = sentinel;
|
|
355
|
+
this._sentinel = sentinel;
|
|
356
|
+
}
|
|
357
|
+
dequeue() {
|
|
358
|
+
var sentinel = this._sentinel;
|
|
359
|
+
var entry = sentinel._prev;
|
|
360
|
+
if (entry !== sentinel) {
|
|
361
|
+
unlink(entry);
|
|
362
|
+
return entry;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
enqueue(entry) {
|
|
366
|
+
var sentinel = this._sentinel;
|
|
367
|
+
if (entry._prev && entry._next) unlink(entry);
|
|
368
|
+
entry._next = sentinel._next;
|
|
369
|
+
sentinel._next._prev = entry;
|
|
370
|
+
sentinel._next = entry;
|
|
371
|
+
entry._prev = sentinel;
|
|
372
|
+
}
|
|
373
|
+
toString() {
|
|
374
|
+
var strs = [];
|
|
375
|
+
var sentinel = this._sentinel;
|
|
376
|
+
var curr = sentinel._prev;
|
|
377
|
+
while (curr !== sentinel) {
|
|
378
|
+
strs.push(JSON.stringify(curr, filterOutLinks));
|
|
379
|
+
curr = curr._prev;
|
|
380
|
+
}
|
|
381
|
+
return `[${strs.join(", ")}]`;
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
function unlink(entry) {
|
|
385
|
+
entry._prev._next = entry._next;
|
|
386
|
+
entry._next._prev = entry._prev;
|
|
387
|
+
delete entry._next;
|
|
388
|
+
delete entry._prev;
|
|
389
|
+
}
|
|
390
|
+
function filterOutLinks(k, v) {
|
|
391
|
+
if (k !== "_next" && k !== "_prev") return v;
|
|
392
|
+
}
|
|
393
|
+
//#endregion
|
|
394
|
+
//#region src/dagre/greedy-fas.js
|
|
395
|
+
var DEFAULT_WEIGHT_FN = _.constant(1);
|
|
396
|
+
function greedyFAS(g, weightFn) {
|
|
397
|
+
if (g.nodeCount() <= 1) return [];
|
|
398
|
+
var state = buildState(g, weightFn || DEFAULT_WEIGHT_FN);
|
|
399
|
+
var results = doGreedyFAS(state.graph, state.buckets, state.zeroIdx);
|
|
400
|
+
return _.flatten(_.map(results, (e) => g.outEdges(e.v, e.w)));
|
|
401
|
+
}
|
|
402
|
+
function doGreedyFAS(g, buckets, zeroIdx) {
|
|
403
|
+
var results = [];
|
|
404
|
+
var sources = buckets[buckets.length - 1];
|
|
405
|
+
var sinks = buckets[0];
|
|
406
|
+
var entry;
|
|
407
|
+
while (g.nodeCount()) {
|
|
408
|
+
while (entry = sinks.dequeue()) removeNode(g, buckets, zeroIdx, entry);
|
|
409
|
+
while (entry = sources.dequeue()) removeNode(g, buckets, zeroIdx, entry);
|
|
410
|
+
if (g.nodeCount()) for (var i = buckets.length - 2; i > 0; --i) {
|
|
411
|
+
entry = buckets[i].dequeue();
|
|
412
|
+
if (entry) {
|
|
413
|
+
results = results.concat(removeNode(g, buckets, zeroIdx, entry, true));
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return results;
|
|
419
|
+
}
|
|
420
|
+
function removeNode(g, buckets, zeroIdx, entry, collectPredecessors) {
|
|
421
|
+
var results = collectPredecessors ? [] : void 0;
|
|
422
|
+
_.forEach(g.inEdges(entry.v), (edge) => {
|
|
423
|
+
var weight = g.edge(edge);
|
|
424
|
+
var uEntry = g.node(edge.v);
|
|
425
|
+
if (collectPredecessors) results.push({
|
|
426
|
+
v: edge.v,
|
|
427
|
+
w: edge.w
|
|
428
|
+
});
|
|
429
|
+
uEntry.out -= weight;
|
|
430
|
+
assignBucket(buckets, zeroIdx, uEntry);
|
|
431
|
+
});
|
|
432
|
+
_.forEach(g.outEdges(entry.v), (edge) => {
|
|
433
|
+
var weight = g.edge(edge);
|
|
434
|
+
var w = edge.w;
|
|
435
|
+
var wEntry = g.node(w);
|
|
436
|
+
wEntry.in -= weight;
|
|
437
|
+
assignBucket(buckets, zeroIdx, wEntry);
|
|
438
|
+
});
|
|
439
|
+
g.removeNode(entry.v);
|
|
440
|
+
return results;
|
|
441
|
+
}
|
|
442
|
+
function buildState(g, weightFn) {
|
|
443
|
+
var fasGraph = new Graph();
|
|
444
|
+
var maxIn = 0;
|
|
445
|
+
var maxOut = 0;
|
|
446
|
+
_.forEach(g.nodes(), (v) => {
|
|
447
|
+
fasGraph.setNode(v, {
|
|
448
|
+
v,
|
|
449
|
+
in: 0,
|
|
450
|
+
out: 0
|
|
451
|
+
});
|
|
452
|
+
});
|
|
453
|
+
_.forEach(g.edges(), (e) => {
|
|
454
|
+
var prevWeight = fasGraph.edge(e.v, e.w) || 0;
|
|
455
|
+
var weight = weightFn(e);
|
|
456
|
+
var edgeWeight = prevWeight + weight;
|
|
457
|
+
fasGraph.setEdge(e.v, e.w, edgeWeight);
|
|
458
|
+
maxOut = Math.max(maxOut, fasGraph.node(e.v).out += weight);
|
|
459
|
+
maxIn = Math.max(maxIn, fasGraph.node(e.w).in += weight);
|
|
460
|
+
});
|
|
461
|
+
var buckets = _.range(maxOut + maxIn + 3).map(() => new List());
|
|
462
|
+
var zeroIdx = maxIn + 1;
|
|
463
|
+
_.forEach(fasGraph.nodes(), (v) => {
|
|
464
|
+
assignBucket(buckets, zeroIdx, fasGraph.node(v));
|
|
465
|
+
});
|
|
466
|
+
return {
|
|
467
|
+
graph: fasGraph,
|
|
468
|
+
buckets,
|
|
469
|
+
zeroIdx
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
function assignBucket(buckets, zeroIdx, entry) {
|
|
473
|
+
if (!entry.out) buckets[0].enqueue(entry);
|
|
474
|
+
else if (!entry.in) buckets[buckets.length - 1].enqueue(entry);
|
|
475
|
+
else buckets[entry.out - entry.in + zeroIdx].enqueue(entry);
|
|
476
|
+
}
|
|
477
|
+
//#endregion
|
|
478
|
+
//#region src/dagre/acyclic.js
|
|
479
|
+
function run$2(g) {
|
|
480
|
+
var fas = g.graph().acyclicer === "greedy" ? greedyFAS(g, weightFn(g)) : dfsFAS(g);
|
|
481
|
+
_.forEach(fas, (e) => {
|
|
482
|
+
var label = g.edge(e);
|
|
483
|
+
g.removeEdge(e);
|
|
484
|
+
label.forwardName = e.name;
|
|
485
|
+
label.reversed = true;
|
|
486
|
+
g.setEdge(e.w, e.v, label, _.uniqueId("rev"));
|
|
487
|
+
});
|
|
488
|
+
function weightFn(g) {
|
|
489
|
+
return (e) => g.edge(e).weight;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
function dfsFAS(g) {
|
|
493
|
+
var fas = [];
|
|
494
|
+
var stack = {};
|
|
495
|
+
var visited = {};
|
|
496
|
+
function dfs(v) {
|
|
497
|
+
if (_.has(visited, v)) return;
|
|
498
|
+
visited[v] = true;
|
|
499
|
+
stack[v] = true;
|
|
500
|
+
_.forEach(g.outEdges(v), (e) => {
|
|
501
|
+
if (_.has(stack, e.w)) fas.push(e);
|
|
502
|
+
else dfs(e.w);
|
|
503
|
+
});
|
|
504
|
+
delete stack[v];
|
|
505
|
+
}
|
|
506
|
+
_.forEach(g.nodes(), dfs);
|
|
507
|
+
return fas;
|
|
508
|
+
}
|
|
509
|
+
function undo$2(g) {
|
|
510
|
+
_.forEach(g.edges(), (e) => {
|
|
511
|
+
var label = g.edge(e);
|
|
512
|
+
if (label.reversed) {
|
|
513
|
+
g.removeEdge(e);
|
|
514
|
+
var forwardName = label.forwardName;
|
|
515
|
+
delete label.reversed;
|
|
516
|
+
delete label.forwardName;
|
|
517
|
+
g.setEdge(e.w, e.v, label, forwardName);
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
//#endregion
|
|
522
|
+
//#region src/dagre/util.js
|
|
523
|
+
function addDummyNode(g, type, attrs, name) {
|
|
524
|
+
var v;
|
|
525
|
+
do
|
|
526
|
+
v = _.uniqueId(name);
|
|
527
|
+
while (g.hasNode(v));
|
|
528
|
+
attrs.dummy = type;
|
|
529
|
+
g.setNode(v, attrs);
|
|
530
|
+
return v;
|
|
531
|
+
}
|
|
532
|
+
function simplify(g) {
|
|
533
|
+
var simplified = new Graph().setGraph(g.graph());
|
|
534
|
+
_.forEach(g.nodes(), (v) => {
|
|
535
|
+
simplified.setNode(v, g.node(v));
|
|
536
|
+
});
|
|
537
|
+
_.forEach(g.edges(), (e) => {
|
|
538
|
+
var simpleLabel = simplified.edge(e.v, e.w) || {
|
|
539
|
+
weight: 0,
|
|
540
|
+
minlen: 1
|
|
541
|
+
};
|
|
542
|
+
var label = g.edge(e);
|
|
543
|
+
simplified.setEdge(e.v, e.w, {
|
|
544
|
+
weight: simpleLabel.weight + label.weight,
|
|
545
|
+
minlen: Math.max(simpleLabel.minlen, label.minlen)
|
|
546
|
+
});
|
|
547
|
+
});
|
|
548
|
+
return simplified;
|
|
549
|
+
}
|
|
550
|
+
function asNonCompoundGraph(g) {
|
|
551
|
+
var simplified = new Graph({ multigraph: g.isMultigraph() }).setGraph(g.graph());
|
|
552
|
+
_.forEach(g.nodes(), (v) => {
|
|
553
|
+
if (!g.children(v).length) simplified.setNode(v, g.node(v));
|
|
554
|
+
});
|
|
555
|
+
_.forEach(g.edges(), (e) => {
|
|
556
|
+
simplified.setEdge(e, g.edge(e));
|
|
557
|
+
});
|
|
558
|
+
return simplified;
|
|
559
|
+
}
|
|
560
|
+
function intersectRect(rect, point) {
|
|
561
|
+
var x = rect.x;
|
|
562
|
+
var y = rect.y;
|
|
563
|
+
var dx = point.x - x;
|
|
564
|
+
var dy = point.y - y;
|
|
565
|
+
var w = rect.width / 2;
|
|
566
|
+
var h = rect.height / 2;
|
|
567
|
+
if (!dx && !dy) throw new Error("Not possible to find intersection inside of the rectangle");
|
|
568
|
+
var sx, sy;
|
|
569
|
+
if (Math.abs(dy) * w > Math.abs(dx) * h) {
|
|
570
|
+
if (dy < 0) h = -h;
|
|
571
|
+
sx = h * dx / dy;
|
|
572
|
+
sy = h;
|
|
573
|
+
} else {
|
|
574
|
+
if (dx < 0) w = -w;
|
|
575
|
+
sx = w;
|
|
576
|
+
sy = w * dy / dx;
|
|
577
|
+
}
|
|
578
|
+
return {
|
|
579
|
+
x: x + sx,
|
|
580
|
+
y: y + sy
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
function buildLayerMatrix(g) {
|
|
584
|
+
var layering = _.map(_.range(maxRank(g) + 1), () => []);
|
|
585
|
+
_.forEach(g.nodes(), (v) => {
|
|
586
|
+
var node = g.node(v);
|
|
587
|
+
var rank = node.rank;
|
|
588
|
+
if (!_.isUndefined(rank)) layering[rank][node.order] = v;
|
|
589
|
+
});
|
|
590
|
+
return layering;
|
|
591
|
+
}
|
|
592
|
+
function normalizeRanks(g) {
|
|
593
|
+
var min = _.min(_.map(g.nodes(), (v) => g.node(v).rank));
|
|
594
|
+
_.forEach(g.nodes(), (v) => {
|
|
595
|
+
var node = g.node(v);
|
|
596
|
+
if (_.has(node, "rank")) node.rank -= min;
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
function removeEmptyRanks(g) {
|
|
600
|
+
var offset = _.min(_.map(g.nodes(), (v) => g.node(v).rank));
|
|
601
|
+
var layers = [];
|
|
602
|
+
_.forEach(g.nodes(), (v) => {
|
|
603
|
+
var rank = g.node(v).rank - offset;
|
|
604
|
+
if (!layers[rank]) layers[rank] = [];
|
|
605
|
+
layers[rank].push(v);
|
|
606
|
+
});
|
|
607
|
+
var delta = 0;
|
|
608
|
+
var nodeRankFactor = g.graph().nodeRankFactor;
|
|
609
|
+
_.forEach(layers, (vs, i) => {
|
|
610
|
+
if (_.isUndefined(vs) && i % nodeRankFactor !== 0) --delta;
|
|
611
|
+
else if (delta) _.forEach(vs, (v) => {
|
|
612
|
+
g.node(v).rank += delta;
|
|
613
|
+
});
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
function addBorderNode$1(g, prefix, rank, order) {
|
|
617
|
+
var node = {
|
|
618
|
+
width: 0,
|
|
619
|
+
height: 0
|
|
620
|
+
};
|
|
621
|
+
if (arguments.length >= 4) {
|
|
622
|
+
node.rank = rank;
|
|
623
|
+
node.order = order;
|
|
624
|
+
}
|
|
625
|
+
return addDummyNode(g, "border", node, prefix);
|
|
626
|
+
}
|
|
627
|
+
function maxRank(g) {
|
|
628
|
+
return _.max(_.map(g.nodes(), (v) => {
|
|
629
|
+
var rank = g.node(v).rank;
|
|
630
|
+
if (!_.isUndefined(rank)) return rank;
|
|
631
|
+
}));
|
|
632
|
+
}
|
|
633
|
+
function partition(collection, fn) {
|
|
634
|
+
var result = {
|
|
635
|
+
lhs: [],
|
|
636
|
+
rhs: []
|
|
637
|
+
};
|
|
638
|
+
_.forEach(collection, (value) => {
|
|
639
|
+
if (fn(value)) result.lhs.push(value);
|
|
640
|
+
else result.rhs.push(value);
|
|
641
|
+
});
|
|
642
|
+
return result;
|
|
643
|
+
}
|
|
644
|
+
function time(name, fn) {
|
|
645
|
+
var start = _.now();
|
|
646
|
+
try {
|
|
647
|
+
return fn();
|
|
648
|
+
} finally {
|
|
649
|
+
console.log(`${name} time: ${_.now() - start}ms`);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
function notime(_name, fn) {
|
|
653
|
+
return fn();
|
|
654
|
+
}
|
|
655
|
+
//#endregion
|
|
656
|
+
//#region src/dagre/add-border-segments.js
|
|
657
|
+
function addBorderSegments(g) {
|
|
658
|
+
function dfs(v) {
|
|
659
|
+
var children = g.children(v);
|
|
660
|
+
var node = g.node(v);
|
|
661
|
+
if (children.length) _.forEach(children, dfs);
|
|
662
|
+
if (_.has(node, "minRank")) {
|
|
663
|
+
node.borderLeft = [];
|
|
664
|
+
node.borderRight = [];
|
|
665
|
+
for (var rank = node.minRank, maxRank = node.maxRank + 1; rank < maxRank; ++rank) {
|
|
666
|
+
addBorderNode(g, "borderLeft", "_bl", v, node, rank);
|
|
667
|
+
addBorderNode(g, "borderRight", "_br", v, node, rank);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
_.forEach(g.children(), dfs);
|
|
672
|
+
}
|
|
673
|
+
function addBorderNode(g, prop, prefix, sg, sgNode, rank) {
|
|
674
|
+
var label = {
|
|
675
|
+
width: 0,
|
|
676
|
+
height: 0,
|
|
677
|
+
rank,
|
|
678
|
+
borderType: prop
|
|
679
|
+
};
|
|
680
|
+
var prev = sgNode[prop][rank - 1];
|
|
681
|
+
var curr = addDummyNode(g, "border", label, prefix);
|
|
682
|
+
sgNode[prop][rank] = curr;
|
|
683
|
+
g.setParent(curr, sg);
|
|
684
|
+
if (prev) g.setEdge(prev, curr, { weight: 1 });
|
|
685
|
+
}
|
|
686
|
+
//#endregion
|
|
687
|
+
//#region src/dagre/coordinate-system.js
|
|
688
|
+
function adjust(g) {
|
|
689
|
+
var rankDir = g.graph().rankdir.toLowerCase();
|
|
690
|
+
if (rankDir === "lr" || rankDir === "rl") swapWidthHeight(g);
|
|
691
|
+
}
|
|
692
|
+
function undo$1(g) {
|
|
693
|
+
var rankDir = g.graph().rankdir.toLowerCase();
|
|
694
|
+
if (rankDir === "bt" || rankDir === "rl") reverseY(g);
|
|
695
|
+
if (rankDir === "lr" || rankDir === "rl") {
|
|
696
|
+
swapXY(g);
|
|
697
|
+
swapWidthHeight(g);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
function swapWidthHeight(g) {
|
|
701
|
+
_.forEach(g.nodes(), (v) => {
|
|
702
|
+
swapWidthHeightOne(g.node(v));
|
|
703
|
+
});
|
|
704
|
+
_.forEach(g.edges(), (e) => {
|
|
705
|
+
swapWidthHeightOne(g.edge(e));
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
function swapWidthHeightOne(attrs) {
|
|
709
|
+
var w = attrs.width;
|
|
710
|
+
attrs.width = attrs.height;
|
|
711
|
+
attrs.height = w;
|
|
712
|
+
}
|
|
713
|
+
function reverseY(g) {
|
|
714
|
+
_.forEach(g.nodes(), (v) => {
|
|
715
|
+
reverseYOne(g.node(v));
|
|
716
|
+
});
|
|
717
|
+
_.forEach(g.edges(), (e) => {
|
|
718
|
+
var edge = g.edge(e);
|
|
719
|
+
_.forEach(edge.points, reverseYOne);
|
|
720
|
+
if (_.has(edge, "y")) reverseYOne(edge);
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
function reverseYOne(attrs) {
|
|
724
|
+
attrs.y = -attrs.y;
|
|
725
|
+
}
|
|
726
|
+
function swapXY(g) {
|
|
727
|
+
_.forEach(g.nodes(), (v) => {
|
|
728
|
+
swapXYOne(g.node(v));
|
|
729
|
+
});
|
|
730
|
+
_.forEach(g.edges(), (e) => {
|
|
731
|
+
var edge = g.edge(e);
|
|
732
|
+
_.forEach(edge.points, swapXYOne);
|
|
733
|
+
if (_.has(edge, "x")) swapXYOne(edge);
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
function swapXYOne(attrs) {
|
|
737
|
+
var x = attrs.x;
|
|
738
|
+
attrs.x = attrs.y;
|
|
739
|
+
attrs.y = x;
|
|
740
|
+
}
|
|
741
|
+
//#endregion
|
|
742
|
+
//#region src/dagre/nesting-graph.js
|
|
743
|
+
function run$1(g) {
|
|
744
|
+
var root = addDummyNode(g, "root", {}, "_root");
|
|
745
|
+
var depths = treeDepths(g);
|
|
746
|
+
var height = _.max(_.values(depths)) - 1;
|
|
747
|
+
var nodeSep = 2 * height + 1;
|
|
748
|
+
g.graph().nestingRoot = root;
|
|
749
|
+
_.forEach(g.edges(), (e) => {
|
|
750
|
+
g.edge(e).minlen *= nodeSep;
|
|
751
|
+
});
|
|
752
|
+
var weight = sumWeights(g) + 1;
|
|
753
|
+
_.forEach(g.children(), (child) => {
|
|
754
|
+
dfs$1(g, root, nodeSep, weight, height, depths, child);
|
|
755
|
+
});
|
|
756
|
+
g.graph().nodeRankFactor = nodeSep;
|
|
757
|
+
}
|
|
758
|
+
function dfs$1(g, root, nodeSep, weight, height, depths, v) {
|
|
759
|
+
var children = g.children(v);
|
|
760
|
+
if (!children.length) {
|
|
761
|
+
if (v !== root) g.setEdge(root, v, {
|
|
762
|
+
weight: 0,
|
|
763
|
+
minlen: nodeSep
|
|
764
|
+
});
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
var top = addBorderNode$1(g, "_bt");
|
|
768
|
+
var bottom = addBorderNode$1(g, "_bb");
|
|
769
|
+
var label = g.node(v);
|
|
770
|
+
g.setParent(top, v);
|
|
771
|
+
label.borderTop = top;
|
|
772
|
+
g.setParent(bottom, v);
|
|
773
|
+
label.borderBottom = bottom;
|
|
774
|
+
_.forEach(children, (child) => {
|
|
775
|
+
dfs$1(g, root, nodeSep, weight, height, depths, child);
|
|
776
|
+
var childNode = g.node(child);
|
|
777
|
+
var childTop = childNode.borderTop ? childNode.borderTop : child;
|
|
778
|
+
var childBottom = childNode.borderBottom ? childNode.borderBottom : child;
|
|
779
|
+
var thisWeight = childNode.borderTop ? weight : 2 * weight;
|
|
780
|
+
var minlen = childTop !== childBottom ? 1 : height - depths[v] + 1;
|
|
781
|
+
g.setEdge(top, childTop, {
|
|
782
|
+
weight: thisWeight,
|
|
783
|
+
minlen,
|
|
784
|
+
nestingEdge: true
|
|
785
|
+
});
|
|
786
|
+
g.setEdge(childBottom, bottom, {
|
|
787
|
+
weight: thisWeight,
|
|
788
|
+
minlen,
|
|
789
|
+
nestingEdge: true
|
|
790
|
+
});
|
|
791
|
+
});
|
|
792
|
+
if (!g.parent(v)) g.setEdge(root, top, {
|
|
793
|
+
weight: 0,
|
|
794
|
+
minlen: height + depths[v]
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
function treeDepths(g) {
|
|
798
|
+
var depths = {};
|
|
799
|
+
function dfs(v, depth) {
|
|
800
|
+
var children = g.children(v);
|
|
801
|
+
if (children?.length) _.forEach(children, (child) => {
|
|
802
|
+
dfs(child, depth + 1);
|
|
803
|
+
});
|
|
804
|
+
depths[v] = depth;
|
|
805
|
+
}
|
|
806
|
+
_.forEach(g.children(), (v) => {
|
|
807
|
+
dfs(v, 1);
|
|
808
|
+
});
|
|
809
|
+
return depths;
|
|
810
|
+
}
|
|
811
|
+
function sumWeights(g) {
|
|
812
|
+
return _.reduce(g.edges(), (acc, e) => acc + g.edge(e).weight, 0);
|
|
813
|
+
}
|
|
814
|
+
function cleanup(g) {
|
|
815
|
+
var graphLabel = g.graph();
|
|
816
|
+
g.removeNode(graphLabel.nestingRoot);
|
|
817
|
+
delete graphLabel.nestingRoot;
|
|
818
|
+
_.forEach(g.edges(), (e) => {
|
|
819
|
+
if (g.edge(e).nestingEdge) g.removeEdge(e);
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
//#endregion
|
|
823
|
+
//#region src/dagre/normalize.js
|
|
824
|
+
function run(g) {
|
|
825
|
+
g.graph().dummyChains = [];
|
|
826
|
+
_.forEach(g.edges(), (edge) => {
|
|
827
|
+
normalizeEdge(g, edge);
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
function normalizeEdge(g, e) {
|
|
831
|
+
var v = e.v;
|
|
832
|
+
var vRank = g.node(v).rank;
|
|
833
|
+
var w = e.w;
|
|
834
|
+
var wRank = g.node(w).rank;
|
|
835
|
+
var name = e.name;
|
|
836
|
+
var edgeLabel = g.edge(e);
|
|
837
|
+
var labelRank = edgeLabel.labelRank;
|
|
838
|
+
if (wRank === vRank + 1) return;
|
|
839
|
+
g.removeEdge(e);
|
|
840
|
+
var dummy, attrs, i = 0;
|
|
841
|
+
for (++vRank; vRank < wRank; ++i, ++vRank) {
|
|
842
|
+
edgeLabel.points = [];
|
|
843
|
+
attrs = {
|
|
844
|
+
width: 0,
|
|
845
|
+
height: 0,
|
|
846
|
+
edgeLabel,
|
|
847
|
+
edgeObj: e,
|
|
848
|
+
rank: vRank
|
|
849
|
+
};
|
|
850
|
+
dummy = addDummyNode(g, "edge", attrs, "_d");
|
|
851
|
+
if (vRank === labelRank) {
|
|
852
|
+
attrs.width = edgeLabel.width;
|
|
853
|
+
attrs.height = edgeLabel.height;
|
|
854
|
+
attrs.dummy = "edge-label";
|
|
855
|
+
attrs.labelpos = edgeLabel.labelpos;
|
|
856
|
+
}
|
|
857
|
+
g.setEdge(v, dummy, { weight: edgeLabel.weight }, name);
|
|
858
|
+
if (i === 0) g.graph().dummyChains.push(dummy);
|
|
859
|
+
v = dummy;
|
|
860
|
+
}
|
|
861
|
+
g.setEdge(v, w, { weight: edgeLabel.weight }, name);
|
|
862
|
+
}
|
|
863
|
+
function undo(g) {
|
|
864
|
+
_.forEach(g.graph().dummyChains, (v) => {
|
|
865
|
+
var node = g.node(v);
|
|
866
|
+
var origLabel = node.edgeLabel;
|
|
867
|
+
var w;
|
|
868
|
+
g.setEdge(node.edgeObj, origLabel);
|
|
869
|
+
while (node.dummy) {
|
|
870
|
+
w = g.successors(v)[0];
|
|
871
|
+
g.removeNode(v);
|
|
872
|
+
origLabel.points.push({
|
|
873
|
+
x: node.x,
|
|
874
|
+
y: node.y
|
|
875
|
+
});
|
|
876
|
+
if (node.dummy === "edge-label") {
|
|
877
|
+
origLabel.x = node.x;
|
|
878
|
+
origLabel.y = node.y;
|
|
879
|
+
origLabel.width = node.width;
|
|
880
|
+
origLabel.height = node.height;
|
|
881
|
+
}
|
|
882
|
+
v = w;
|
|
883
|
+
node = g.node(v);
|
|
884
|
+
}
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
//#endregion
|
|
888
|
+
//#region src/dagre/order/add-subgraph-constraints.js
|
|
889
|
+
function addSubgraphConstraints(g, cg, vs) {
|
|
890
|
+
var prev = {}, rootPrev;
|
|
891
|
+
_.forEach(vs, (v) => {
|
|
892
|
+
var child = g.parent(v), parent, prevChild;
|
|
893
|
+
while (child) {
|
|
894
|
+
parent = g.parent(child);
|
|
895
|
+
if (parent) {
|
|
896
|
+
prevChild = prev[parent];
|
|
897
|
+
prev[parent] = child;
|
|
898
|
+
} else {
|
|
899
|
+
prevChild = rootPrev;
|
|
900
|
+
rootPrev = child;
|
|
901
|
+
}
|
|
902
|
+
if (prevChild && prevChild !== child) {
|
|
903
|
+
cg.setEdge(prevChild, child);
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
child = parent;
|
|
907
|
+
}
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
//#endregion
|
|
911
|
+
//#region src/dagre/order/build-layer-graph.js
|
|
912
|
+
function buildLayerGraph(g, rank, relationship) {
|
|
913
|
+
var root = createRootNode(g), result = new Graph({ compound: true }).setGraph({ root }).setDefaultNodeLabel((v) => g.node(v));
|
|
914
|
+
_.forEach(g.nodes(), (v) => {
|
|
915
|
+
var node = g.node(v), parent = g.parent(v);
|
|
916
|
+
if (node.rank === rank || node.minRank <= rank && rank <= node.maxRank) {
|
|
917
|
+
result.setNode(v);
|
|
918
|
+
result.setParent(v, parent || root);
|
|
919
|
+
_.forEach(g[relationship](v), (e) => {
|
|
920
|
+
var u = e.v === v ? e.w : e.v, edge = result.edge(u, v), weight = !_.isUndefined(edge) ? edge.weight : 0;
|
|
921
|
+
result.setEdge(u, v, { weight: g.edge(e).weight + weight });
|
|
922
|
+
});
|
|
923
|
+
if (_.has(node, "minRank")) result.setNode(v, {
|
|
924
|
+
borderLeft: node.borderLeft[rank],
|
|
925
|
+
borderRight: node.borderRight[rank]
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
});
|
|
929
|
+
return result;
|
|
930
|
+
}
|
|
931
|
+
function createRootNode(g) {
|
|
932
|
+
var v;
|
|
933
|
+
while (g.hasNode(v = _.uniqueId("_root")));
|
|
934
|
+
return v;
|
|
935
|
+
}
|
|
936
|
+
//#endregion
|
|
937
|
+
//#region src/dagre/order/cross-count.js
|
|
938
|
+
function crossCount(g, layering) {
|
|
939
|
+
var cc = 0;
|
|
940
|
+
for (var i = 1; i < layering.length; ++i) cc += twoLayerCrossCount(g, layering[i - 1], layering[i]);
|
|
941
|
+
return cc;
|
|
942
|
+
}
|
|
943
|
+
function twoLayerCrossCount(g, northLayer, southLayer) {
|
|
944
|
+
var southPos = _.zipObject(southLayer, _.map(southLayer, (_v, i) => i));
|
|
945
|
+
var southEntries = _.flatten(_.map(northLayer, (v) => _.sortBy(_.map(g.outEdges(v), (e) => ({
|
|
946
|
+
pos: southPos[e.w],
|
|
947
|
+
weight: g.edge(e).weight
|
|
948
|
+
})), "pos")));
|
|
949
|
+
var firstIndex = 1;
|
|
950
|
+
while (firstIndex < southLayer.length) firstIndex <<= 1;
|
|
951
|
+
var treeSize = 2 * firstIndex - 1;
|
|
952
|
+
firstIndex -= 1;
|
|
953
|
+
var tree = _.map(new Array(treeSize), () => 0);
|
|
954
|
+
var cc = 0;
|
|
955
|
+
_.forEach(southEntries.forEach((entry) => {
|
|
956
|
+
var index = entry.pos + firstIndex;
|
|
957
|
+
tree[index] += entry.weight;
|
|
958
|
+
var weightSum = 0;
|
|
959
|
+
while (index > 0) {
|
|
960
|
+
if (index % 2) weightSum += tree[index + 1];
|
|
961
|
+
index = index - 1 >> 1;
|
|
962
|
+
tree[index] += entry.weight;
|
|
963
|
+
}
|
|
964
|
+
cc += entry.weight * weightSum;
|
|
965
|
+
}));
|
|
966
|
+
return cc;
|
|
967
|
+
}
|
|
968
|
+
//#endregion
|
|
969
|
+
//#region src/dagre/order/init-order.js
|
|
970
|
+
function initOrder(g) {
|
|
971
|
+
var visited = {};
|
|
972
|
+
var simpleNodes = _.filter(g.nodes(), (v) => !g.children(v).length);
|
|
973
|
+
var maxRank = _.max(_.map(simpleNodes, (v) => g.node(v).rank));
|
|
974
|
+
var layers = _.map(_.range(maxRank + 1), () => []);
|
|
975
|
+
function dfs(v) {
|
|
976
|
+
if (_.has(visited, v)) return;
|
|
977
|
+
visited[v] = true;
|
|
978
|
+
layers[g.node(v).rank].push(v);
|
|
979
|
+
_.forEach(g.successors(v), dfs);
|
|
980
|
+
}
|
|
981
|
+
var orderedVs = _.sortBy(simpleNodes, (v) => g.node(v).rank);
|
|
982
|
+
_.forEach(orderedVs, dfs);
|
|
983
|
+
return layers;
|
|
984
|
+
}
|
|
985
|
+
//#endregion
|
|
986
|
+
//#region src/dagre/order/barycenter.js
|
|
987
|
+
function barycenter(g, movable) {
|
|
988
|
+
return _.map(movable, (v) => {
|
|
989
|
+
var inV = g.inEdges(v);
|
|
990
|
+
if (!inV.length) return { v };
|
|
991
|
+
else {
|
|
992
|
+
var result = _.reduce(inV, (acc, e) => {
|
|
993
|
+
var edge = g.edge(e), nodeU = g.node(e.v);
|
|
994
|
+
return {
|
|
995
|
+
sum: acc.sum + edge.weight * nodeU.order,
|
|
996
|
+
weight: acc.weight + edge.weight
|
|
997
|
+
};
|
|
998
|
+
}, {
|
|
999
|
+
sum: 0,
|
|
1000
|
+
weight: 0
|
|
1001
|
+
});
|
|
1002
|
+
return {
|
|
1003
|
+
v,
|
|
1004
|
+
barycenter: result.sum / result.weight,
|
|
1005
|
+
weight: result.weight
|
|
1006
|
+
};
|
|
1007
|
+
}
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
1010
|
+
//#endregion
|
|
1011
|
+
//#region src/dagre/order/resolve-conflicts.js
|
|
1012
|
+
function resolveConflicts(entries, cg) {
|
|
1013
|
+
var mappedEntries = {};
|
|
1014
|
+
_.forEach(entries, (entry, i) => {
|
|
1015
|
+
var tmp = mappedEntries[entry.v] = {
|
|
1016
|
+
indegree: 0,
|
|
1017
|
+
in: [],
|
|
1018
|
+
out: [],
|
|
1019
|
+
vs: [entry.v],
|
|
1020
|
+
i
|
|
1021
|
+
};
|
|
1022
|
+
if (!_.isUndefined(entry.barycenter)) {
|
|
1023
|
+
tmp.barycenter = entry.barycenter;
|
|
1024
|
+
tmp.weight = entry.weight;
|
|
1025
|
+
}
|
|
1026
|
+
});
|
|
1027
|
+
_.forEach(cg.edges(), (e) => {
|
|
1028
|
+
var entryV = mappedEntries[e.v];
|
|
1029
|
+
var entryW = mappedEntries[e.w];
|
|
1030
|
+
if (!_.isUndefined(entryV) && !_.isUndefined(entryW)) {
|
|
1031
|
+
entryW.indegree++;
|
|
1032
|
+
entryV.out.push(mappedEntries[e.w]);
|
|
1033
|
+
}
|
|
1034
|
+
});
|
|
1035
|
+
return doResolveConflicts(_.filter(mappedEntries, (entry) => {
|
|
1036
|
+
return !entry.indegree;
|
|
1037
|
+
}));
|
|
1038
|
+
}
|
|
1039
|
+
function doResolveConflicts(sourceSet) {
|
|
1040
|
+
var entries = [];
|
|
1041
|
+
function handleIn(vEntry) {
|
|
1042
|
+
return (uEntry) => {
|
|
1043
|
+
if (uEntry.merged) return;
|
|
1044
|
+
if (_.isUndefined(uEntry.barycenter) || _.isUndefined(vEntry.barycenter) || uEntry.barycenter >= vEntry.barycenter) mergeEntries(vEntry, uEntry);
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
function handleOut(vEntry) {
|
|
1048
|
+
return (wEntry) => {
|
|
1049
|
+
wEntry.in.push(vEntry);
|
|
1050
|
+
if (--wEntry.indegree === 0) sourceSet.push(wEntry);
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
while (sourceSet.length) {
|
|
1054
|
+
var entry = sourceSet.pop();
|
|
1055
|
+
entries.push(entry);
|
|
1056
|
+
_.forEach(entry.in.reverse(), handleIn(entry));
|
|
1057
|
+
_.forEach(entry.out, handleOut(entry));
|
|
1058
|
+
}
|
|
1059
|
+
return _.map(_.filter(entries, (entry) => !entry.merged), (entry) => _.pick(entry, [
|
|
1060
|
+
"vs",
|
|
1061
|
+
"i",
|
|
1062
|
+
"barycenter",
|
|
1063
|
+
"weight"
|
|
1064
|
+
]));
|
|
1065
|
+
}
|
|
1066
|
+
function mergeEntries(target, source) {
|
|
1067
|
+
var sum = 0;
|
|
1068
|
+
var weight = 0;
|
|
1069
|
+
if (target.weight) {
|
|
1070
|
+
sum += target.barycenter * target.weight;
|
|
1071
|
+
weight += target.weight;
|
|
1072
|
+
}
|
|
1073
|
+
if (source.weight) {
|
|
1074
|
+
sum += source.barycenter * source.weight;
|
|
1075
|
+
weight += source.weight;
|
|
1076
|
+
}
|
|
1077
|
+
target.vs = source.vs.concat(target.vs);
|
|
1078
|
+
target.barycenter = sum / weight;
|
|
1079
|
+
target.weight = weight;
|
|
1080
|
+
target.i = Math.min(source.i, target.i);
|
|
1081
|
+
source.merged = true;
|
|
1082
|
+
}
|
|
1083
|
+
//#endregion
|
|
1084
|
+
//#region src/dagre/order/sort.js
|
|
1085
|
+
function sort(entries, biasRight) {
|
|
1086
|
+
var parts = partition(entries, (entry) => _.has(entry, "barycenter"));
|
|
1087
|
+
var sortable = parts.lhs, unsortable = _.sortBy(parts.rhs, (entry) => -entry.i), vs = [], sum = 0, weight = 0, vsIndex = 0;
|
|
1088
|
+
sortable.sort(compareWithBias(!!biasRight));
|
|
1089
|
+
vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
|
|
1090
|
+
_.forEach(sortable, (entry) => {
|
|
1091
|
+
vsIndex += entry.vs.length;
|
|
1092
|
+
vs.push(entry.vs);
|
|
1093
|
+
sum += entry.barycenter * entry.weight;
|
|
1094
|
+
weight += entry.weight;
|
|
1095
|
+
vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
|
|
1096
|
+
});
|
|
1097
|
+
var result = { vs: _.flatten(vs) };
|
|
1098
|
+
if (weight) {
|
|
1099
|
+
result.barycenter = sum / weight;
|
|
1100
|
+
result.weight = weight;
|
|
1101
|
+
}
|
|
1102
|
+
return result;
|
|
1103
|
+
}
|
|
1104
|
+
function consumeUnsortable(vs, unsortable, index) {
|
|
1105
|
+
var last;
|
|
1106
|
+
while (unsortable.length && (last = _.last(unsortable)).i <= index) {
|
|
1107
|
+
unsortable.pop();
|
|
1108
|
+
vs.push(last.vs);
|
|
1109
|
+
index++;
|
|
1110
|
+
}
|
|
1111
|
+
return index;
|
|
1112
|
+
}
|
|
1113
|
+
function compareWithBias(bias) {
|
|
1114
|
+
return (entryV, entryW) => {
|
|
1115
|
+
if (entryV.barycenter < entryW.barycenter) return -1;
|
|
1116
|
+
else if (entryV.barycenter > entryW.barycenter) return 1;
|
|
1117
|
+
return !bias ? entryV.i - entryW.i : entryW.i - entryV.i;
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
//#endregion
|
|
1121
|
+
//#region src/dagre/order/sort-subgraph.js
|
|
1122
|
+
function sortSubgraph(g, v, cg, biasRight) {
|
|
1123
|
+
var movable = g.children(v);
|
|
1124
|
+
var node = g.node(v);
|
|
1125
|
+
var bl = node ? node.borderLeft : void 0;
|
|
1126
|
+
var br = node ? node.borderRight : void 0;
|
|
1127
|
+
var subgraphs = {};
|
|
1128
|
+
if (bl) movable = _.filter(movable, (w) => w !== bl && w !== br);
|
|
1129
|
+
var barycenters = barycenter(g, movable);
|
|
1130
|
+
_.forEach(barycenters, (entry) => {
|
|
1131
|
+
if (g.children(entry.v).length) {
|
|
1132
|
+
var subgraphResult = sortSubgraph(g, entry.v, cg, biasRight);
|
|
1133
|
+
subgraphs[entry.v] = subgraphResult;
|
|
1134
|
+
if (_.has(subgraphResult, "barycenter")) mergeBarycenters(entry, subgraphResult);
|
|
1135
|
+
}
|
|
1136
|
+
});
|
|
1137
|
+
var entries = resolveConflicts(barycenters, cg);
|
|
1138
|
+
expandSubgraphs(entries, subgraphs);
|
|
1139
|
+
var result = sort(entries, biasRight);
|
|
1140
|
+
if (bl) {
|
|
1141
|
+
result.vs = _.flatten([
|
|
1142
|
+
bl,
|
|
1143
|
+
result.vs,
|
|
1144
|
+
br
|
|
1145
|
+
]);
|
|
1146
|
+
if (g.predecessors(bl).length) {
|
|
1147
|
+
var blPred = g.node(g.predecessors(bl)[0]), brPred = g.node(g.predecessors(br)[0]);
|
|
1148
|
+
if (!_.has(result, "barycenter")) {
|
|
1149
|
+
result.barycenter = 0;
|
|
1150
|
+
result.weight = 0;
|
|
1151
|
+
}
|
|
1152
|
+
result.barycenter = (result.barycenter * result.weight + blPred.order + brPred.order) / (result.weight + 2);
|
|
1153
|
+
result.weight += 2;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
return result;
|
|
1157
|
+
}
|
|
1158
|
+
function expandSubgraphs(entries, subgraphs) {
|
|
1159
|
+
_.forEach(entries, (entry) => {
|
|
1160
|
+
entry.vs = _.flatten(entry.vs.map((v) => {
|
|
1161
|
+
if (subgraphs[v]) return subgraphs[v].vs;
|
|
1162
|
+
return v;
|
|
1163
|
+
}));
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
function mergeBarycenters(target, other) {
|
|
1167
|
+
if (!_.isUndefined(target.barycenter)) {
|
|
1168
|
+
target.barycenter = (target.barycenter * target.weight + other.barycenter * other.weight) / (target.weight + other.weight);
|
|
1169
|
+
target.weight += other.weight;
|
|
1170
|
+
} else {
|
|
1171
|
+
target.barycenter = other.barycenter;
|
|
1172
|
+
target.weight = other.weight;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
//#endregion
|
|
1176
|
+
//#region src/dagre/order/index.js
|
|
1177
|
+
function order(g) {
|
|
1178
|
+
var maxRank$1 = maxRank(g), downLayerGraphs = buildLayerGraphs(g, _.range(1, maxRank$1 + 1), "inEdges"), upLayerGraphs = buildLayerGraphs(g, _.range(maxRank$1 - 1, -1, -1), "outEdges");
|
|
1179
|
+
var layering = initOrder(g);
|
|
1180
|
+
assignOrder(g, layering);
|
|
1181
|
+
var bestCC = Number.POSITIVE_INFINITY, best;
|
|
1182
|
+
for (var i = 0, lastBest = 0; lastBest < 4; ++i, ++lastBest) {
|
|
1183
|
+
sweepLayerGraphs(i % 2 ? downLayerGraphs : upLayerGraphs, i % 4 >= 2);
|
|
1184
|
+
layering = buildLayerMatrix(g);
|
|
1185
|
+
var cc = crossCount(g, layering);
|
|
1186
|
+
if (cc < bestCC) {
|
|
1187
|
+
lastBest = 0;
|
|
1188
|
+
best = _.cloneDeep(layering);
|
|
1189
|
+
bestCC = cc;
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
assignOrder(g, best);
|
|
1193
|
+
}
|
|
1194
|
+
function buildLayerGraphs(g, ranks, relationship) {
|
|
1195
|
+
return _.map(ranks, (rank) => buildLayerGraph(g, rank, relationship));
|
|
1196
|
+
}
|
|
1197
|
+
function sweepLayerGraphs(layerGraphs, biasRight) {
|
|
1198
|
+
var cg = new Graph();
|
|
1199
|
+
_.forEach(layerGraphs, (lg) => {
|
|
1200
|
+
var root = lg.graph().root;
|
|
1201
|
+
var sorted = sortSubgraph(lg, root, cg, biasRight);
|
|
1202
|
+
_.forEach(sorted.vs, (v, i) => {
|
|
1203
|
+
lg.node(v).order = i;
|
|
1204
|
+
});
|
|
1205
|
+
addSubgraphConstraints(lg, cg, sorted.vs);
|
|
1206
|
+
});
|
|
1207
|
+
}
|
|
1208
|
+
function assignOrder(g, layering) {
|
|
1209
|
+
_.forEach(layering, (layer) => {
|
|
1210
|
+
_.forEach(layer, (v, i) => {
|
|
1211
|
+
g.node(v).order = i;
|
|
1212
|
+
});
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
//#endregion
|
|
1216
|
+
//#region src/dagre/parent-dummy-chains.js
|
|
1217
|
+
function parentDummyChains(g) {
|
|
1218
|
+
var postorderNums = postorder$1(g);
|
|
1219
|
+
_.forEach(g.graph().dummyChains, (v) => {
|
|
1220
|
+
var node = g.node(v);
|
|
1221
|
+
var edgeObj = node.edgeObj;
|
|
1222
|
+
var pathData = findPath(g, postorderNums, edgeObj.v, edgeObj.w);
|
|
1223
|
+
var path = pathData.path;
|
|
1224
|
+
var lca = pathData.lca;
|
|
1225
|
+
var pathIdx = 0;
|
|
1226
|
+
var pathV = path[pathIdx];
|
|
1227
|
+
var ascending = true;
|
|
1228
|
+
while (v !== edgeObj.w) {
|
|
1229
|
+
node = g.node(v);
|
|
1230
|
+
if (ascending) {
|
|
1231
|
+
while ((pathV = path[pathIdx]) !== lca && g.node(pathV).maxRank < node.rank) pathIdx++;
|
|
1232
|
+
if (pathV === lca) ascending = false;
|
|
1233
|
+
}
|
|
1234
|
+
if (!ascending) {
|
|
1235
|
+
while (pathIdx < path.length - 1 && g.node(pathV = path[pathIdx + 1]).minRank <= node.rank) pathIdx++;
|
|
1236
|
+
pathV = path[pathIdx];
|
|
1237
|
+
}
|
|
1238
|
+
g.setParent(v, pathV);
|
|
1239
|
+
v = g.successors(v)[0];
|
|
1240
|
+
}
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
function findPath(g, postorderNums, v, w) {
|
|
1244
|
+
var vPath = [];
|
|
1245
|
+
var wPath = [];
|
|
1246
|
+
var low = Math.min(postorderNums[v].low, postorderNums[w].low);
|
|
1247
|
+
var lim = Math.max(postorderNums[v].lim, postorderNums[w].lim);
|
|
1248
|
+
var parent;
|
|
1249
|
+
var lca;
|
|
1250
|
+
parent = v;
|
|
1251
|
+
do {
|
|
1252
|
+
parent = g.parent(parent);
|
|
1253
|
+
vPath.push(parent);
|
|
1254
|
+
} while (parent && (postorderNums[parent].low > low || lim > postorderNums[parent].lim));
|
|
1255
|
+
lca = parent;
|
|
1256
|
+
parent = w;
|
|
1257
|
+
while ((parent = g.parent(parent)) !== lca) wPath.push(parent);
|
|
1258
|
+
return {
|
|
1259
|
+
path: vPath.concat(wPath.reverse()),
|
|
1260
|
+
lca
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
function postorder$1(g) {
|
|
1264
|
+
var result = {};
|
|
1265
|
+
var lim = 0;
|
|
1266
|
+
function dfs(v) {
|
|
1267
|
+
var low = lim;
|
|
1268
|
+
_.forEach(g.children(v), dfs);
|
|
1269
|
+
result[v] = {
|
|
1270
|
+
low,
|
|
1271
|
+
lim: lim++
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
_.forEach(g.children(), dfs);
|
|
1275
|
+
return result;
|
|
1276
|
+
}
|
|
1277
|
+
//#endregion
|
|
1278
|
+
//#region src/dagre/position/bk.js
|
|
1279
|
+
function findType1Conflicts(g, layering) {
|
|
1280
|
+
var conflicts = {};
|
|
1281
|
+
function visitLayer(prevLayer, layer) {
|
|
1282
|
+
var k0 = 0, scanPos = 0, prevLayerLength = prevLayer.length, lastNode = _.last(layer);
|
|
1283
|
+
_.forEach(layer, (v, i) => {
|
|
1284
|
+
var w = findOtherInnerSegmentNode(g, v), k1 = w ? g.node(w).order : prevLayerLength;
|
|
1285
|
+
if (w || v === lastNode) {
|
|
1286
|
+
_.forEach(layer.slice(scanPos, i + 1), (scanNode) => {
|
|
1287
|
+
_.forEach(g.predecessors(scanNode), (u) => {
|
|
1288
|
+
var uLabel = g.node(u), uPos = uLabel.order;
|
|
1289
|
+
if ((uPos < k0 || k1 < uPos) && !(uLabel.dummy && g.node(scanNode).dummy)) addConflict(conflicts, u, scanNode);
|
|
1290
|
+
});
|
|
1291
|
+
});
|
|
1292
|
+
scanPos = i + 1;
|
|
1293
|
+
k0 = k1;
|
|
1294
|
+
}
|
|
1295
|
+
});
|
|
1296
|
+
return layer;
|
|
1297
|
+
}
|
|
1298
|
+
_.reduce(layering, visitLayer);
|
|
1299
|
+
return conflicts;
|
|
1300
|
+
}
|
|
1301
|
+
function findType2Conflicts(g, layering) {
|
|
1302
|
+
var conflicts = {};
|
|
1303
|
+
function scan(south, southPos, southEnd, prevNorthBorder, nextNorthBorder) {
|
|
1304
|
+
var v;
|
|
1305
|
+
_.forEach(_.range(southPos, southEnd), (i) => {
|
|
1306
|
+
v = south[i];
|
|
1307
|
+
if (g.node(v).dummy) _.forEach(g.predecessors(v), (u) => {
|
|
1308
|
+
var uNode = g.node(u);
|
|
1309
|
+
if (uNode.dummy && (uNode.order < prevNorthBorder || uNode.order > nextNorthBorder)) addConflict(conflicts, u, v);
|
|
1310
|
+
});
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1313
|
+
function visitLayer(north, south) {
|
|
1314
|
+
var prevNorthPos = -1, nextNorthPos, southPos = 0;
|
|
1315
|
+
_.forEach(south, (v, southLookahead) => {
|
|
1316
|
+
if (g.node(v).dummy === "border") {
|
|
1317
|
+
var predecessors = g.predecessors(v);
|
|
1318
|
+
if (predecessors.length) {
|
|
1319
|
+
nextNorthPos = g.node(predecessors[0]).order;
|
|
1320
|
+
scan(south, southPos, southLookahead, prevNorthPos, nextNorthPos);
|
|
1321
|
+
southPos = southLookahead;
|
|
1322
|
+
prevNorthPos = nextNorthPos;
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
scan(south, southPos, south.length, nextNorthPos, north.length);
|
|
1326
|
+
});
|
|
1327
|
+
return south;
|
|
1328
|
+
}
|
|
1329
|
+
_.reduce(layering, visitLayer);
|
|
1330
|
+
return conflicts;
|
|
1331
|
+
}
|
|
1332
|
+
function findOtherInnerSegmentNode(g, v) {
|
|
1333
|
+
if (g.node(v).dummy) return _.find(g.predecessors(v), (u) => g.node(u).dummy);
|
|
1334
|
+
}
|
|
1335
|
+
function addConflict(conflicts, v, w) {
|
|
1336
|
+
if (v > w) {
|
|
1337
|
+
var tmp = v;
|
|
1338
|
+
v = w;
|
|
1339
|
+
w = tmp;
|
|
1340
|
+
}
|
|
1341
|
+
var conflictsV = conflicts[v];
|
|
1342
|
+
if (!conflictsV) conflicts[v] = conflictsV = {};
|
|
1343
|
+
conflictsV[w] = true;
|
|
1344
|
+
}
|
|
1345
|
+
function hasConflict(conflicts, v, w) {
|
|
1346
|
+
if (v > w) {
|
|
1347
|
+
var tmp = v;
|
|
1348
|
+
v = w;
|
|
1349
|
+
w = tmp;
|
|
1350
|
+
}
|
|
1351
|
+
return _.has(conflicts[v], w);
|
|
1352
|
+
}
|
|
1353
|
+
function verticalAlignment(_g, layering, conflicts, neighborFn) {
|
|
1354
|
+
var root = {}, align = {}, pos = {};
|
|
1355
|
+
_.forEach(layering, (layer) => {
|
|
1356
|
+
_.forEach(layer, (v, order) => {
|
|
1357
|
+
root[v] = v;
|
|
1358
|
+
align[v] = v;
|
|
1359
|
+
pos[v] = order;
|
|
1360
|
+
});
|
|
1361
|
+
});
|
|
1362
|
+
_.forEach(layering, (layer) => {
|
|
1363
|
+
var prevIdx = -1;
|
|
1364
|
+
_.forEach(layer, (v) => {
|
|
1365
|
+
var ws = neighborFn(v);
|
|
1366
|
+
if (ws.length) {
|
|
1367
|
+
ws = _.sortBy(ws, (w) => pos[w]);
|
|
1368
|
+
var mp = (ws.length - 1) / 2;
|
|
1369
|
+
for (var i = Math.floor(mp), il = Math.ceil(mp); i <= il; ++i) {
|
|
1370
|
+
var w = ws[i];
|
|
1371
|
+
if (align[v] === v && prevIdx < pos[w] && !hasConflict(conflicts, v, w)) {
|
|
1372
|
+
align[w] = v;
|
|
1373
|
+
align[v] = root[v] = root[w];
|
|
1374
|
+
prevIdx = pos[w];
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
});
|
|
1379
|
+
});
|
|
1380
|
+
return {
|
|
1381
|
+
root,
|
|
1382
|
+
align
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
function horizontalCompaction(g, layering, root, align, reverseSep) {
|
|
1386
|
+
var xs = {}, blockG = buildBlockGraph(g, layering, root, reverseSep), borderType = reverseSep ? "borderLeft" : "borderRight";
|
|
1387
|
+
function iterate(setXsFunc, nextNodesFunc) {
|
|
1388
|
+
var stack = blockG.nodes();
|
|
1389
|
+
var elem = stack.pop();
|
|
1390
|
+
var visited = {};
|
|
1391
|
+
while (elem) {
|
|
1392
|
+
if (visited[elem]) setXsFunc(elem);
|
|
1393
|
+
else {
|
|
1394
|
+
visited[elem] = true;
|
|
1395
|
+
stack.push(elem);
|
|
1396
|
+
stack = stack.concat(nextNodesFunc(elem));
|
|
1397
|
+
}
|
|
1398
|
+
elem = stack.pop();
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
function pass1(elem) {
|
|
1402
|
+
xs[elem] = blockG.inEdges(elem).reduce((acc, e) => Math.max(acc, xs[e.v] + blockG.edge(e)), 0);
|
|
1403
|
+
}
|
|
1404
|
+
function pass2(elem) {
|
|
1405
|
+
var min = blockG.outEdges(elem).reduce((acc, e) => Math.min(acc, xs[e.w] - blockG.edge(e)), Number.POSITIVE_INFINITY);
|
|
1406
|
+
var node = g.node(elem);
|
|
1407
|
+
if (min !== Number.POSITIVE_INFINITY && node.borderType !== borderType) xs[elem] = Math.max(xs[elem], min);
|
|
1408
|
+
}
|
|
1409
|
+
iterate(pass1, blockG.predecessors.bind(blockG));
|
|
1410
|
+
iterate(pass2, blockG.successors.bind(blockG));
|
|
1411
|
+
_.forEach(align, (v) => {
|
|
1412
|
+
xs[v] = xs[root[v]];
|
|
1413
|
+
});
|
|
1414
|
+
return xs;
|
|
1415
|
+
}
|
|
1416
|
+
function buildBlockGraph(g, layering, root, reverseSep) {
|
|
1417
|
+
var blockGraph = new Graph(), graphLabel = g.graph(), sepFn = sep(graphLabel.nodesep, graphLabel.edgesep, reverseSep);
|
|
1418
|
+
_.forEach(layering, (layer) => {
|
|
1419
|
+
var u;
|
|
1420
|
+
_.forEach(layer, (v) => {
|
|
1421
|
+
var vRoot = root[v];
|
|
1422
|
+
blockGraph.setNode(vRoot);
|
|
1423
|
+
if (u) {
|
|
1424
|
+
var uRoot = root[u], prevMax = blockGraph.edge(uRoot, vRoot);
|
|
1425
|
+
blockGraph.setEdge(uRoot, vRoot, Math.max(sepFn(g, v, u), prevMax || 0));
|
|
1426
|
+
}
|
|
1427
|
+
u = v;
|
|
1428
|
+
});
|
|
1429
|
+
});
|
|
1430
|
+
return blockGraph;
|
|
1431
|
+
}
|
|
1432
|
+
function findSmallestWidthAlignment(g, xss) {
|
|
1433
|
+
return _.minBy(_.values(xss), (xs) => {
|
|
1434
|
+
var max = Number.NEGATIVE_INFINITY;
|
|
1435
|
+
var min = Number.POSITIVE_INFINITY;
|
|
1436
|
+
_.forIn(xs, (x, v) => {
|
|
1437
|
+
var halfWidth = width(g, v) / 2;
|
|
1438
|
+
max = Math.max(x + halfWidth, max);
|
|
1439
|
+
min = Math.min(x - halfWidth, min);
|
|
1440
|
+
});
|
|
1441
|
+
return max - min;
|
|
1442
|
+
});
|
|
1443
|
+
}
|
|
1444
|
+
function alignCoordinates(xss, alignTo) {
|
|
1445
|
+
var alignToVals = _.values(alignTo), alignToMin = _.min(alignToVals), alignToMax = _.max(alignToVals);
|
|
1446
|
+
_.forEach(["u", "d"], (vert) => {
|
|
1447
|
+
_.forEach(["l", "r"], (horiz) => {
|
|
1448
|
+
var alignment = vert + horiz, xs = xss[alignment], delta;
|
|
1449
|
+
if (xs === alignTo) return;
|
|
1450
|
+
var xsVals = _.values(xs);
|
|
1451
|
+
delta = horiz === "l" ? alignToMin - _.min(xsVals) : alignToMax - _.max(xsVals);
|
|
1452
|
+
if (delta) xss[alignment] = _.mapValues(xs, (x) => x + delta);
|
|
1453
|
+
});
|
|
1454
|
+
});
|
|
1455
|
+
}
|
|
1456
|
+
function balance(xss, align) {
|
|
1457
|
+
return _.mapValues(xss.ul, (_ignore, v) => {
|
|
1458
|
+
if (align) return xss[align.toLowerCase()][v];
|
|
1459
|
+
else {
|
|
1460
|
+
var xs = _.sortBy(_.map(xss, v));
|
|
1461
|
+
return (xs[1] + xs[2]) / 2;
|
|
1462
|
+
}
|
|
1463
|
+
});
|
|
1464
|
+
}
|
|
1465
|
+
function positionX(g) {
|
|
1466
|
+
var layering = buildLayerMatrix(g);
|
|
1467
|
+
var conflicts = _.merge(findType1Conflicts(g, layering), findType2Conflicts(g, layering));
|
|
1468
|
+
var xss = {};
|
|
1469
|
+
var adjustedLayering;
|
|
1470
|
+
_.forEach(["u", "d"], (vert) => {
|
|
1471
|
+
adjustedLayering = vert === "u" ? layering : _.values(layering).reverse();
|
|
1472
|
+
_.forEach(["l", "r"], (horiz) => {
|
|
1473
|
+
if (horiz === "r") adjustedLayering = _.map(adjustedLayering, (inner) => _.values(inner).reverse());
|
|
1474
|
+
var neighborFn = (vert === "u" ? g.predecessors : g.successors).bind(g);
|
|
1475
|
+
var align = verticalAlignment(g, adjustedLayering, conflicts, neighborFn);
|
|
1476
|
+
var xs = horizontalCompaction(g, adjustedLayering, align.root, align.align, horiz === "r");
|
|
1477
|
+
if (horiz === "r") xs = _.mapValues(xs, (x) => -x);
|
|
1478
|
+
xss[vert + horiz] = xs;
|
|
1479
|
+
});
|
|
1480
|
+
});
|
|
1481
|
+
alignCoordinates(xss, findSmallestWidthAlignment(g, xss));
|
|
1482
|
+
return balance(xss, g.graph().align);
|
|
1483
|
+
}
|
|
1484
|
+
function sep(nodeSep, edgeSep, reverseSep) {
|
|
1485
|
+
return (g, v, w) => {
|
|
1486
|
+
var vLabel = g.node(v);
|
|
1487
|
+
var wLabel = g.node(w);
|
|
1488
|
+
var sum = 0;
|
|
1489
|
+
var delta;
|
|
1490
|
+
sum += vLabel.width / 2;
|
|
1491
|
+
if (_.has(vLabel, "labelpos")) switch (vLabel.labelpos.toLowerCase()) {
|
|
1492
|
+
case "l":
|
|
1493
|
+
delta = -vLabel.width / 2;
|
|
1494
|
+
break;
|
|
1495
|
+
case "r": delta = vLabel.width / 2;
|
|
1496
|
+
}
|
|
1497
|
+
if (delta) sum += reverseSep ? delta : -delta;
|
|
1498
|
+
delta = 0;
|
|
1499
|
+
sum += (vLabel.dummy ? edgeSep : nodeSep) / 2;
|
|
1500
|
+
sum += (wLabel.dummy ? edgeSep : nodeSep) / 2;
|
|
1501
|
+
sum += wLabel.width / 2;
|
|
1502
|
+
if (_.has(wLabel, "labelpos")) switch (wLabel.labelpos.toLowerCase()) {
|
|
1503
|
+
case "l":
|
|
1504
|
+
delta = wLabel.width / 2;
|
|
1505
|
+
break;
|
|
1506
|
+
case "r": delta = -wLabel.width / 2;
|
|
1507
|
+
}
|
|
1508
|
+
if (delta) sum += reverseSep ? delta : -delta;
|
|
1509
|
+
delta = 0;
|
|
1510
|
+
return sum;
|
|
1511
|
+
};
|
|
1512
|
+
}
|
|
1513
|
+
function width(g, v) {
|
|
1514
|
+
return g.node(v).width;
|
|
1515
|
+
}
|
|
1516
|
+
//#endregion
|
|
1517
|
+
//#region src/dagre/position/index.js
|
|
1518
|
+
function position(g) {
|
|
1519
|
+
g = asNonCompoundGraph(g);
|
|
1520
|
+
positionY(g);
|
|
1521
|
+
_.forOwn(positionX(g), (x, v) => {
|
|
1522
|
+
g.node(v).x = x;
|
|
1523
|
+
});
|
|
1524
|
+
}
|
|
1525
|
+
function positionY(g) {
|
|
1526
|
+
var layering = buildLayerMatrix(g);
|
|
1527
|
+
var rankSep = g.graph().ranksep;
|
|
1528
|
+
var prevY = 0;
|
|
1529
|
+
_.forEach(layering, (layer) => {
|
|
1530
|
+
var maxHeight = _.max(_.map(layer, (v) => g.node(v).height));
|
|
1531
|
+
_.forEach(layer, (v) => {
|
|
1532
|
+
g.node(v).y = prevY + maxHeight / 2;
|
|
1533
|
+
});
|
|
1534
|
+
prevY += maxHeight + rankSep;
|
|
1535
|
+
});
|
|
1536
|
+
}
|
|
1537
|
+
//#endregion
|
|
1538
|
+
//#region src/dagre/rank/util.js
|
|
1539
|
+
function longestPath(g) {
|
|
1540
|
+
var visited = {};
|
|
1541
|
+
function dfs(v) {
|
|
1542
|
+
var label = g.node(v);
|
|
1543
|
+
if (_.has(visited, v)) return label.rank;
|
|
1544
|
+
visited[v] = true;
|
|
1545
|
+
var rank = _.min(_.map(g.outEdges(v), (e) => dfs(e.w) - g.edge(e).minlen));
|
|
1546
|
+
if (rank === Number.POSITIVE_INFINITY || rank === void 0 || rank === null) rank = 0;
|
|
1547
|
+
return label.rank = rank;
|
|
1548
|
+
}
|
|
1549
|
+
_.forEach(g.sources(), dfs);
|
|
1550
|
+
}
|
|
1551
|
+
function slack(g, e) {
|
|
1552
|
+
return g.node(e.w).rank - g.node(e.v).rank - g.edge(e).minlen;
|
|
1553
|
+
}
|
|
1554
|
+
//#endregion
|
|
1555
|
+
//#region src/dagre/rank/feasible-tree.js
|
|
1556
|
+
function feasibleTree(g) {
|
|
1557
|
+
var t = new Graph({ directed: false });
|
|
1558
|
+
var start = g.nodes()[0];
|
|
1559
|
+
var size = g.nodeCount();
|
|
1560
|
+
t.setNode(start, {});
|
|
1561
|
+
var edge, delta;
|
|
1562
|
+
while (tightTree(t, g) < size) {
|
|
1563
|
+
edge = findMinSlackEdge(t, g);
|
|
1564
|
+
delta = t.hasNode(edge.v) ? slack(g, edge) : -slack(g, edge);
|
|
1565
|
+
shiftRanks(t, g, delta);
|
|
1566
|
+
}
|
|
1567
|
+
return t;
|
|
1568
|
+
}
|
|
1569
|
+
function tightTree(t, g) {
|
|
1570
|
+
function dfs(v) {
|
|
1571
|
+
_.forEach(g.nodeEdges(v), (e) => {
|
|
1572
|
+
var edgeV = e.v, w = v === edgeV ? e.w : edgeV;
|
|
1573
|
+
if (!t.hasNode(w) && !slack(g, e)) {
|
|
1574
|
+
t.setNode(w, {});
|
|
1575
|
+
t.setEdge(v, w, {});
|
|
1576
|
+
dfs(w);
|
|
1577
|
+
}
|
|
1578
|
+
});
|
|
1579
|
+
}
|
|
1580
|
+
_.forEach(t.nodes(), dfs);
|
|
1581
|
+
return t.nodeCount();
|
|
1582
|
+
}
|
|
1583
|
+
function findMinSlackEdge(t, g) {
|
|
1584
|
+
return _.minBy(g.edges(), (e) => {
|
|
1585
|
+
if (t.hasNode(e.v) !== t.hasNode(e.w)) return slack(g, e);
|
|
1586
|
+
});
|
|
1587
|
+
}
|
|
1588
|
+
function shiftRanks(t, g, delta) {
|
|
1589
|
+
_.forEach(t.nodes(), (v) => {
|
|
1590
|
+
g.node(v).rank += delta;
|
|
1591
|
+
});
|
|
1592
|
+
}
|
|
1593
|
+
_.constant(1);
|
|
1594
|
+
_.constant(1);
|
|
1595
|
+
//#endregion
|
|
1596
|
+
//#region src/graphlib/alg/topsort.js
|
|
1597
|
+
topsort.CycleException = CycleException;
|
|
1598
|
+
function topsort(g) {
|
|
1599
|
+
var visited = {};
|
|
1600
|
+
var stack = {};
|
|
1601
|
+
var results = [];
|
|
1602
|
+
function visit(node) {
|
|
1603
|
+
if (_.has(stack, node)) throw new CycleException();
|
|
1604
|
+
if (!_.has(visited, node)) {
|
|
1605
|
+
stack[node] = true;
|
|
1606
|
+
visited[node] = true;
|
|
1607
|
+
_.each(g.predecessors(node), visit);
|
|
1608
|
+
delete stack[node];
|
|
1609
|
+
results.push(node);
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
_.each(g.sinks(), visit);
|
|
1613
|
+
if (_.size(visited) !== g.nodeCount()) throw new CycleException();
|
|
1614
|
+
return results;
|
|
1615
|
+
}
|
|
1616
|
+
function CycleException() {}
|
|
1617
|
+
CycleException.prototype = /* @__PURE__ */ new Error();
|
|
1618
|
+
//#endregion
|
|
1619
|
+
//#region src/graphlib/alg/dfs.js
|
|
1620
|
+
function dfs(g, vs, order) {
|
|
1621
|
+
if (!_.isArray(vs)) vs = [vs];
|
|
1622
|
+
var navigation = (g.isDirected() ? g.successors : g.neighbors).bind(g);
|
|
1623
|
+
var acc = [];
|
|
1624
|
+
var visited = {};
|
|
1625
|
+
_.each(vs, (v) => {
|
|
1626
|
+
if (!g.hasNode(v)) throw new Error(`Graph does not have node: ${v}`);
|
|
1627
|
+
doDfs(g, v, order === "post", visited, navigation, acc);
|
|
1628
|
+
});
|
|
1629
|
+
return acc;
|
|
1630
|
+
}
|
|
1631
|
+
function doDfs(g, v, postorder, visited, navigation, acc) {
|
|
1632
|
+
if (!_.has(visited, v)) {
|
|
1633
|
+
visited[v] = true;
|
|
1634
|
+
if (!postorder) acc.push(v);
|
|
1635
|
+
_.each(navigation(v), (w) => {
|
|
1636
|
+
doDfs(g, w, postorder, visited, navigation, acc);
|
|
1637
|
+
});
|
|
1638
|
+
if (postorder) acc.push(v);
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
//#endregion
|
|
1642
|
+
//#region src/graphlib/alg/postorder.js
|
|
1643
|
+
function postorder(g, vs) {
|
|
1644
|
+
return dfs(g, vs, "post");
|
|
1645
|
+
}
|
|
1646
|
+
//#endregion
|
|
1647
|
+
//#region src/graphlib/alg/preorder.js
|
|
1648
|
+
function preorder(g, vs) {
|
|
1649
|
+
return dfs(g, vs, "pre");
|
|
1650
|
+
}
|
|
1651
|
+
//#endregion
|
|
1652
|
+
//#region src/dagre/rank/network-simplex.js
|
|
1653
|
+
networkSimplex.initLowLimValues = initLowLimValues;
|
|
1654
|
+
networkSimplex.initCutValues = initCutValues;
|
|
1655
|
+
networkSimplex.calcCutValue = calcCutValue;
|
|
1656
|
+
networkSimplex.leaveEdge = leaveEdge;
|
|
1657
|
+
networkSimplex.enterEdge = enterEdge;
|
|
1658
|
+
networkSimplex.exchangeEdges = exchangeEdges;
|
|
1659
|
+
function networkSimplex(g) {
|
|
1660
|
+
g = simplify(g);
|
|
1661
|
+
longestPath(g);
|
|
1662
|
+
var t = feasibleTree(g);
|
|
1663
|
+
initLowLimValues(t);
|
|
1664
|
+
initCutValues(t, g);
|
|
1665
|
+
var e, f;
|
|
1666
|
+
while (e = leaveEdge(t)) {
|
|
1667
|
+
f = enterEdge(t, g, e);
|
|
1668
|
+
exchangeEdges(t, g, e, f);
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
function initCutValues(t, g) {
|
|
1672
|
+
var vs = postorder(t, t.nodes());
|
|
1673
|
+
vs = vs.slice(0, vs.length - 1);
|
|
1674
|
+
_.forEach(vs, (v) => {
|
|
1675
|
+
assignCutValue(t, g, v);
|
|
1676
|
+
});
|
|
1677
|
+
}
|
|
1678
|
+
function assignCutValue(t, g, child) {
|
|
1679
|
+
var parent = t.node(child).parent;
|
|
1680
|
+
t.edge(child, parent).cutvalue = calcCutValue(t, g, child);
|
|
1681
|
+
}
|
|
1682
|
+
function calcCutValue(t, g, child) {
|
|
1683
|
+
var parent = t.node(child).parent;
|
|
1684
|
+
var childIsTail = true;
|
|
1685
|
+
var graphEdge = g.edge(child, parent);
|
|
1686
|
+
var cutValue = 0;
|
|
1687
|
+
if (!graphEdge) {
|
|
1688
|
+
childIsTail = false;
|
|
1689
|
+
graphEdge = g.edge(parent, child);
|
|
1690
|
+
}
|
|
1691
|
+
cutValue = graphEdge.weight;
|
|
1692
|
+
_.forEach(g.nodeEdges(child), (e) => {
|
|
1693
|
+
var isOutEdge = e.v === child, other = isOutEdge ? e.w : e.v;
|
|
1694
|
+
if (other !== parent) {
|
|
1695
|
+
var pointsToHead = isOutEdge === childIsTail, otherWeight = g.edge(e).weight;
|
|
1696
|
+
cutValue += pointsToHead ? otherWeight : -otherWeight;
|
|
1697
|
+
if (isTreeEdge(t, child, other)) {
|
|
1698
|
+
var otherCutValue = t.edge(child, other).cutvalue;
|
|
1699
|
+
cutValue += pointsToHead ? -otherCutValue : otherCutValue;
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
});
|
|
1703
|
+
return cutValue;
|
|
1704
|
+
}
|
|
1705
|
+
function initLowLimValues(tree, root) {
|
|
1706
|
+
if (arguments.length < 2) root = tree.nodes()[0];
|
|
1707
|
+
dfsAssignLowLim(tree, {}, 1, root);
|
|
1708
|
+
}
|
|
1709
|
+
function dfsAssignLowLim(tree, visited, nextLim, v, parent) {
|
|
1710
|
+
var low = nextLim;
|
|
1711
|
+
var label = tree.node(v);
|
|
1712
|
+
visited[v] = true;
|
|
1713
|
+
_.forEach(tree.neighbors(v), (w) => {
|
|
1714
|
+
if (!_.has(visited, w)) nextLim = dfsAssignLowLim(tree, visited, nextLim, w, v);
|
|
1715
|
+
});
|
|
1716
|
+
label.low = low;
|
|
1717
|
+
label.lim = nextLim++;
|
|
1718
|
+
if (parent) label.parent = parent;
|
|
1719
|
+
else delete label.parent;
|
|
1720
|
+
return nextLim;
|
|
1721
|
+
}
|
|
1722
|
+
function leaveEdge(tree) {
|
|
1723
|
+
return _.find(tree.edges(), (e) => tree.edge(e).cutvalue < 0);
|
|
1724
|
+
}
|
|
1725
|
+
function enterEdge(t, g, edge) {
|
|
1726
|
+
var v = edge.v;
|
|
1727
|
+
var w = edge.w;
|
|
1728
|
+
if (!g.hasEdge(v, w)) {
|
|
1729
|
+
v = edge.w;
|
|
1730
|
+
w = edge.v;
|
|
1731
|
+
}
|
|
1732
|
+
var vLabel = t.node(v);
|
|
1733
|
+
var wLabel = t.node(w);
|
|
1734
|
+
var tailLabel = vLabel;
|
|
1735
|
+
var flip = false;
|
|
1736
|
+
if (vLabel.lim > wLabel.lim) {
|
|
1737
|
+
tailLabel = wLabel;
|
|
1738
|
+
flip = true;
|
|
1739
|
+
}
|
|
1740
|
+
var candidates = _.filter(g.edges(), (edge) => flip === isDescendant(t, t.node(edge.v), tailLabel) && flip !== isDescendant(t, t.node(edge.w), tailLabel));
|
|
1741
|
+
return _.minBy(candidates, (edge) => slack(g, edge));
|
|
1742
|
+
}
|
|
1743
|
+
function exchangeEdges(t, g, e, f) {
|
|
1744
|
+
var v = e.v;
|
|
1745
|
+
var w = e.w;
|
|
1746
|
+
t.removeEdge(v, w);
|
|
1747
|
+
t.setEdge(f.v, f.w, {});
|
|
1748
|
+
initLowLimValues(t);
|
|
1749
|
+
initCutValues(t, g);
|
|
1750
|
+
updateRanks(t, g);
|
|
1751
|
+
}
|
|
1752
|
+
function updateRanks(t, g) {
|
|
1753
|
+
var vs = preorder(t, _.find(t.nodes(), (v) => !g.node(v).parent));
|
|
1754
|
+
vs = vs.slice(1);
|
|
1755
|
+
_.forEach(vs, (v) => {
|
|
1756
|
+
var parent = t.node(v).parent, edge = g.edge(v, parent), flipped = false;
|
|
1757
|
+
if (!edge) {
|
|
1758
|
+
edge = g.edge(parent, v);
|
|
1759
|
+
flipped = true;
|
|
1760
|
+
}
|
|
1761
|
+
g.node(v).rank = g.node(parent).rank + (flipped ? edge.minlen : -edge.minlen);
|
|
1762
|
+
});
|
|
1763
|
+
}
|
|
1764
|
+
function isTreeEdge(tree, u, v) {
|
|
1765
|
+
return tree.hasEdge(u, v);
|
|
1766
|
+
}
|
|
1767
|
+
function isDescendant(_tree, vLabel, rootLabel) {
|
|
1768
|
+
return rootLabel.low <= vLabel.lim && vLabel.lim <= rootLabel.lim;
|
|
1769
|
+
}
|
|
1770
|
+
//#endregion
|
|
1771
|
+
//#region src/dagre/rank/index.js
|
|
1772
|
+
function rank(g) {
|
|
1773
|
+
switch (g.graph().ranker) {
|
|
1774
|
+
case "network-simplex":
|
|
1775
|
+
networkSimplexRanker(g);
|
|
1776
|
+
break;
|
|
1777
|
+
case "tight-tree":
|
|
1778
|
+
tightTreeRanker(g);
|
|
1779
|
+
break;
|
|
1780
|
+
case "longest-path":
|
|
1781
|
+
longestPathRanker(g);
|
|
1782
|
+
break;
|
|
1783
|
+
default: networkSimplexRanker(g);
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
var longestPathRanker = longestPath;
|
|
1787
|
+
function tightTreeRanker(g) {
|
|
1788
|
+
longestPath(g);
|
|
1789
|
+
feasibleTree(g);
|
|
1790
|
+
}
|
|
1791
|
+
function networkSimplexRanker(g) {
|
|
1792
|
+
networkSimplex(g);
|
|
1793
|
+
}
|
|
1794
|
+
//#endregion
|
|
1795
|
+
//#region src/dagre/layout.js
|
|
1796
|
+
function layout(g, opts) {
|
|
1797
|
+
var time$1 = opts?.debugTiming ? time : notime;
|
|
1798
|
+
time$1("layout", () => {
|
|
1799
|
+
var layoutGraph = time$1(" buildLayoutGraph", () => buildLayoutGraph(g));
|
|
1800
|
+
time$1(" runLayout", () => {
|
|
1801
|
+
runLayout(layoutGraph, time$1);
|
|
1802
|
+
});
|
|
1803
|
+
time$1(" updateInputGraph", () => {
|
|
1804
|
+
updateInputGraph(g, layoutGraph);
|
|
1805
|
+
});
|
|
1806
|
+
});
|
|
1807
|
+
}
|
|
1808
|
+
function runLayout(g, time) {
|
|
1809
|
+
time(" makeSpaceForEdgeLabels", () => {
|
|
1810
|
+
makeSpaceForEdgeLabels(g);
|
|
1811
|
+
});
|
|
1812
|
+
time(" removeSelfEdges", () => {
|
|
1813
|
+
removeSelfEdges(g);
|
|
1814
|
+
});
|
|
1815
|
+
time(" acyclic", () => {
|
|
1816
|
+
run$2(g);
|
|
1817
|
+
});
|
|
1818
|
+
time(" nestingGraph.run", () => {
|
|
1819
|
+
run$1(g);
|
|
1820
|
+
});
|
|
1821
|
+
time(" rank", () => {
|
|
1822
|
+
rank(asNonCompoundGraph(g));
|
|
1823
|
+
});
|
|
1824
|
+
time(" injectEdgeLabelProxies", () => {
|
|
1825
|
+
injectEdgeLabelProxies(g);
|
|
1826
|
+
});
|
|
1827
|
+
time(" removeEmptyRanks", () => {
|
|
1828
|
+
removeEmptyRanks(g);
|
|
1829
|
+
});
|
|
1830
|
+
time(" nestingGraph.cleanup", () => {
|
|
1831
|
+
cleanup(g);
|
|
1832
|
+
});
|
|
1833
|
+
time(" normalizeRanks", () => {
|
|
1834
|
+
normalizeRanks(g);
|
|
1835
|
+
});
|
|
1836
|
+
time(" assignRankMinMax", () => {
|
|
1837
|
+
assignRankMinMax(g);
|
|
1838
|
+
});
|
|
1839
|
+
time(" removeEdgeLabelProxies", () => {
|
|
1840
|
+
removeEdgeLabelProxies(g);
|
|
1841
|
+
});
|
|
1842
|
+
time(" normalize.run", () => {
|
|
1843
|
+
run(g);
|
|
1844
|
+
});
|
|
1845
|
+
time(" parentDummyChains", () => {
|
|
1846
|
+
parentDummyChains(g);
|
|
1847
|
+
});
|
|
1848
|
+
time(" addBorderSegments", () => {
|
|
1849
|
+
addBorderSegments(g);
|
|
1850
|
+
});
|
|
1851
|
+
time(" order", () => {
|
|
1852
|
+
order(g);
|
|
1853
|
+
});
|
|
1854
|
+
time(" insertSelfEdges", () => {
|
|
1855
|
+
insertSelfEdges(g);
|
|
1856
|
+
});
|
|
1857
|
+
time(" adjustCoordinateSystem", () => {
|
|
1858
|
+
adjust(g);
|
|
1859
|
+
});
|
|
1860
|
+
time(" position", () => {
|
|
1861
|
+
position(g);
|
|
1862
|
+
});
|
|
1863
|
+
time(" positionSelfEdges", () => {
|
|
1864
|
+
positionSelfEdges(g);
|
|
1865
|
+
});
|
|
1866
|
+
time(" removeBorderNodes", () => {
|
|
1867
|
+
removeBorderNodes(g);
|
|
1868
|
+
});
|
|
1869
|
+
time(" normalize.undo", () => {
|
|
1870
|
+
undo(g);
|
|
1871
|
+
});
|
|
1872
|
+
time(" fixupEdgeLabelCoords", () => {
|
|
1873
|
+
fixupEdgeLabelCoords(g);
|
|
1874
|
+
});
|
|
1875
|
+
time(" undoCoordinateSystem", () => {
|
|
1876
|
+
undo$1(g);
|
|
1877
|
+
});
|
|
1878
|
+
time(" translateGraph", () => {
|
|
1879
|
+
translateGraph(g);
|
|
1880
|
+
});
|
|
1881
|
+
time(" assignNodeIntersects", () => {
|
|
1882
|
+
assignNodeIntersects(g);
|
|
1883
|
+
});
|
|
1884
|
+
time(" reversePoints", () => {
|
|
1885
|
+
reversePointsForReversedEdges(g);
|
|
1886
|
+
});
|
|
1887
|
+
time(" acyclic.undo", () => {
|
|
1888
|
+
undo$2(g);
|
|
1889
|
+
});
|
|
1890
|
+
}
|
|
1891
|
+
function updateInputGraph(inputGraph, layoutGraph) {
|
|
1892
|
+
_.forEach(inputGraph.nodes(), (v) => {
|
|
1893
|
+
var inputLabel = inputGraph.node(v);
|
|
1894
|
+
var layoutLabel = layoutGraph.node(v);
|
|
1895
|
+
if (inputLabel) {
|
|
1896
|
+
inputLabel.x = layoutLabel.x;
|
|
1897
|
+
inputLabel.y = layoutLabel.y;
|
|
1898
|
+
if (layoutGraph.children(v).length) {
|
|
1899
|
+
inputLabel.width = layoutLabel.width;
|
|
1900
|
+
inputLabel.height = layoutLabel.height;
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
});
|
|
1904
|
+
_.forEach(inputGraph.edges(), (e) => {
|
|
1905
|
+
var inputLabel = inputGraph.edge(e);
|
|
1906
|
+
var layoutLabel = layoutGraph.edge(e);
|
|
1907
|
+
inputLabel.points = layoutLabel.points;
|
|
1908
|
+
if (_.has(layoutLabel, "x")) {
|
|
1909
|
+
inputLabel.x = layoutLabel.x;
|
|
1910
|
+
inputLabel.y = layoutLabel.y;
|
|
1911
|
+
}
|
|
1912
|
+
});
|
|
1913
|
+
inputGraph.graph().width = layoutGraph.graph().width;
|
|
1914
|
+
inputGraph.graph().height = layoutGraph.graph().height;
|
|
1915
|
+
}
|
|
1916
|
+
var graphNumAttrs = [
|
|
1917
|
+
"nodesep",
|
|
1918
|
+
"edgesep",
|
|
1919
|
+
"ranksep",
|
|
1920
|
+
"marginx",
|
|
1921
|
+
"marginy"
|
|
1922
|
+
];
|
|
1923
|
+
var graphDefaults = {
|
|
1924
|
+
ranksep: 50,
|
|
1925
|
+
edgesep: 20,
|
|
1926
|
+
nodesep: 50,
|
|
1927
|
+
rankdir: "tb"
|
|
1928
|
+
};
|
|
1929
|
+
var graphAttrs = [
|
|
1930
|
+
"acyclicer",
|
|
1931
|
+
"ranker",
|
|
1932
|
+
"rankdir",
|
|
1933
|
+
"align"
|
|
1934
|
+
];
|
|
1935
|
+
var nodeNumAttrs = ["width", "height"];
|
|
1936
|
+
var nodeDefaults = {
|
|
1937
|
+
width: 0,
|
|
1938
|
+
height: 0
|
|
1939
|
+
};
|
|
1940
|
+
var edgeNumAttrs = [
|
|
1941
|
+
"minlen",
|
|
1942
|
+
"weight",
|
|
1943
|
+
"width",
|
|
1944
|
+
"height",
|
|
1945
|
+
"labeloffset"
|
|
1946
|
+
];
|
|
1947
|
+
var edgeDefaults = {
|
|
1948
|
+
minlen: 1,
|
|
1949
|
+
weight: 1,
|
|
1950
|
+
width: 0,
|
|
1951
|
+
height: 0,
|
|
1952
|
+
labeloffset: 10,
|
|
1953
|
+
labelpos: "r"
|
|
1954
|
+
};
|
|
1955
|
+
var edgeAttrs = ["labelpos"];
|
|
1956
|
+
function buildLayoutGraph(inputGraph) {
|
|
1957
|
+
var g = new Graph({
|
|
1958
|
+
multigraph: true,
|
|
1959
|
+
compound: true
|
|
1960
|
+
});
|
|
1961
|
+
var graph = canonicalize(inputGraph.graph());
|
|
1962
|
+
g.setGraph(_.merge({}, graphDefaults, selectNumberAttrs(graph, graphNumAttrs), _.pick(graph, graphAttrs)));
|
|
1963
|
+
_.forEach(inputGraph.nodes(), (v) => {
|
|
1964
|
+
var node = canonicalize(inputGraph.node(v));
|
|
1965
|
+
g.setNode(v, _.defaults(selectNumberAttrs(node, nodeNumAttrs), nodeDefaults));
|
|
1966
|
+
g.setParent(v, inputGraph.parent(v));
|
|
1967
|
+
});
|
|
1968
|
+
_.forEach(inputGraph.edges(), (e) => {
|
|
1969
|
+
var edge = canonicalize(inputGraph.edge(e));
|
|
1970
|
+
g.setEdge(e, _.merge({}, edgeDefaults, selectNumberAttrs(edge, edgeNumAttrs), _.pick(edge, edgeAttrs)));
|
|
1971
|
+
});
|
|
1972
|
+
return g;
|
|
1973
|
+
}
|
|
1974
|
+
function makeSpaceForEdgeLabels(g) {
|
|
1975
|
+
var graph = g.graph();
|
|
1976
|
+
graph.ranksep /= 2;
|
|
1977
|
+
_.forEach(g.edges(), (e) => {
|
|
1978
|
+
var edge = g.edge(e);
|
|
1979
|
+
edge.minlen *= 2;
|
|
1980
|
+
if (edge.labelpos.toLowerCase() !== "c") {
|
|
1981
|
+
if (graph.rankdir === "TB" || graph.rankdir === "BT") edge.width += edge.labeloffset;
|
|
1982
|
+
else edge.height += edge.labeloffset;
|
|
1983
|
+
}
|
|
1984
|
+
});
|
|
1985
|
+
}
|
|
1986
|
+
function injectEdgeLabelProxies(g) {
|
|
1987
|
+
_.forEach(g.edges(), (e) => {
|
|
1988
|
+
var edge = g.edge(e);
|
|
1989
|
+
if (edge.width && edge.height) {
|
|
1990
|
+
var v = g.node(e.v);
|
|
1991
|
+
addDummyNode(g, "edge-proxy", {
|
|
1992
|
+
rank: (g.node(e.w).rank - v.rank) / 2 + v.rank,
|
|
1993
|
+
e
|
|
1994
|
+
}, "_ep");
|
|
1995
|
+
}
|
|
1996
|
+
});
|
|
1997
|
+
}
|
|
1998
|
+
function assignRankMinMax(g) {
|
|
1999
|
+
var maxRank = 0;
|
|
2000
|
+
_.forEach(g.nodes(), (v) => {
|
|
2001
|
+
var node = g.node(v);
|
|
2002
|
+
if (node.borderTop) {
|
|
2003
|
+
node.minRank = g.node(node.borderTop).rank;
|
|
2004
|
+
node.maxRank = g.node(node.borderBottom).rank;
|
|
2005
|
+
maxRank = _.max(maxRank, node.maxRank);
|
|
2006
|
+
}
|
|
2007
|
+
});
|
|
2008
|
+
g.graph().maxRank = maxRank;
|
|
2009
|
+
}
|
|
2010
|
+
function removeEdgeLabelProxies(g) {
|
|
2011
|
+
_.forEach(g.nodes(), (v) => {
|
|
2012
|
+
var node = g.node(v);
|
|
2013
|
+
if (node.dummy === "edge-proxy") {
|
|
2014
|
+
g.edge(node.e).labelRank = node.rank;
|
|
2015
|
+
g.removeNode(v);
|
|
2016
|
+
}
|
|
2017
|
+
});
|
|
2018
|
+
}
|
|
2019
|
+
function translateGraph(g) {
|
|
2020
|
+
var minX = Number.POSITIVE_INFINITY;
|
|
2021
|
+
var maxX = 0;
|
|
2022
|
+
var minY = Number.POSITIVE_INFINITY;
|
|
2023
|
+
var maxY = 0;
|
|
2024
|
+
var graphLabel = g.graph();
|
|
2025
|
+
var marginX = graphLabel.marginx || 0;
|
|
2026
|
+
var marginY = graphLabel.marginy || 0;
|
|
2027
|
+
function getExtremes(attrs) {
|
|
2028
|
+
var x = attrs.x;
|
|
2029
|
+
var y = attrs.y;
|
|
2030
|
+
var w = attrs.width;
|
|
2031
|
+
var h = attrs.height;
|
|
2032
|
+
minX = Math.min(minX, x - w / 2);
|
|
2033
|
+
maxX = Math.max(maxX, x + w / 2);
|
|
2034
|
+
minY = Math.min(minY, y - h / 2);
|
|
2035
|
+
maxY = Math.max(maxY, y + h / 2);
|
|
2036
|
+
}
|
|
2037
|
+
_.forEach(g.nodes(), (v) => {
|
|
2038
|
+
getExtremes(g.node(v));
|
|
2039
|
+
});
|
|
2040
|
+
_.forEach(g.edges(), (e) => {
|
|
2041
|
+
var edge = g.edge(e);
|
|
2042
|
+
if (_.has(edge, "x")) getExtremes(edge);
|
|
2043
|
+
});
|
|
2044
|
+
minX -= marginX;
|
|
2045
|
+
minY -= marginY;
|
|
2046
|
+
_.forEach(g.nodes(), (v) => {
|
|
2047
|
+
var node = g.node(v);
|
|
2048
|
+
node.x -= minX;
|
|
2049
|
+
node.y -= minY;
|
|
2050
|
+
});
|
|
2051
|
+
_.forEach(g.edges(), (e) => {
|
|
2052
|
+
var edge = g.edge(e);
|
|
2053
|
+
_.forEach(edge.points, (p) => {
|
|
2054
|
+
p.x -= minX;
|
|
2055
|
+
p.y -= minY;
|
|
2056
|
+
});
|
|
2057
|
+
if (_.has(edge, "x")) edge.x -= minX;
|
|
2058
|
+
if (_.has(edge, "y")) edge.y -= minY;
|
|
2059
|
+
});
|
|
2060
|
+
graphLabel.width = maxX - minX + marginX;
|
|
2061
|
+
graphLabel.height = maxY - minY + marginY;
|
|
2062
|
+
}
|
|
2063
|
+
function assignNodeIntersects(g) {
|
|
2064
|
+
_.forEach(g.edges(), (e) => {
|
|
2065
|
+
var edge = g.edge(e);
|
|
2066
|
+
var nodeV = g.node(e.v);
|
|
2067
|
+
var nodeW = g.node(e.w);
|
|
2068
|
+
var p1, p2;
|
|
2069
|
+
if (!edge.points) {
|
|
2070
|
+
edge.points = [];
|
|
2071
|
+
p1 = nodeW;
|
|
2072
|
+
p2 = nodeV;
|
|
2073
|
+
} else {
|
|
2074
|
+
p1 = edge.points[0];
|
|
2075
|
+
p2 = edge.points[edge.points.length - 1];
|
|
2076
|
+
}
|
|
2077
|
+
edge.points.unshift(intersectRect(nodeV, p1));
|
|
2078
|
+
edge.points.push(intersectRect(nodeW, p2));
|
|
2079
|
+
});
|
|
2080
|
+
}
|
|
2081
|
+
function fixupEdgeLabelCoords(g) {
|
|
2082
|
+
_.forEach(g.edges(), (e) => {
|
|
2083
|
+
var edge = g.edge(e);
|
|
2084
|
+
if (_.has(edge, "x")) {
|
|
2085
|
+
if (edge.labelpos === "l" || edge.labelpos === "r") edge.width -= edge.labeloffset;
|
|
2086
|
+
switch (edge.labelpos) {
|
|
2087
|
+
case "l":
|
|
2088
|
+
edge.x -= edge.width / 2 + edge.labeloffset;
|
|
2089
|
+
break;
|
|
2090
|
+
case "r": edge.x += edge.width / 2 + edge.labeloffset;
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
});
|
|
2094
|
+
}
|
|
2095
|
+
function reversePointsForReversedEdges(g) {
|
|
2096
|
+
_.forEach(g.edges(), (e) => {
|
|
2097
|
+
var edge = g.edge(e);
|
|
2098
|
+
if (edge.reversed) edge.points.reverse();
|
|
2099
|
+
});
|
|
2100
|
+
}
|
|
2101
|
+
function removeBorderNodes(g) {
|
|
2102
|
+
_.forEach(g.nodes(), (v) => {
|
|
2103
|
+
if (g.children(v).length) {
|
|
2104
|
+
var node = g.node(v);
|
|
2105
|
+
var t = g.node(node.borderTop);
|
|
2106
|
+
var b = g.node(node.borderBottom);
|
|
2107
|
+
var l = g.node(_.last(node.borderLeft));
|
|
2108
|
+
var r = g.node(_.last(node.borderRight));
|
|
2109
|
+
node.width = Math.abs(r.x - l.x);
|
|
2110
|
+
node.height = Math.abs(b.y - t.y);
|
|
2111
|
+
node.x = l.x + node.width / 2;
|
|
2112
|
+
node.y = t.y + node.height / 2;
|
|
2113
|
+
}
|
|
2114
|
+
});
|
|
2115
|
+
_.forEach(g.nodes(), (v) => {
|
|
2116
|
+
if (g.node(v).dummy === "border") g.removeNode(v);
|
|
2117
|
+
});
|
|
2118
|
+
}
|
|
2119
|
+
function removeSelfEdges(g) {
|
|
2120
|
+
_.forEach(g.edges(), (e) => {
|
|
2121
|
+
if (e.v === e.w) {
|
|
2122
|
+
var node = g.node(e.v);
|
|
2123
|
+
if (!node.selfEdges) node.selfEdges = [];
|
|
2124
|
+
node.selfEdges.push({
|
|
2125
|
+
e,
|
|
2126
|
+
label: g.edge(e)
|
|
2127
|
+
});
|
|
2128
|
+
g.removeEdge(e);
|
|
2129
|
+
}
|
|
2130
|
+
});
|
|
2131
|
+
}
|
|
2132
|
+
function insertSelfEdges(g) {
|
|
2133
|
+
var layers = buildLayerMatrix(g);
|
|
2134
|
+
_.forEach(layers, (layer) => {
|
|
2135
|
+
var orderShift = 0;
|
|
2136
|
+
_.forEach(layer, (v, i) => {
|
|
2137
|
+
var node = g.node(v);
|
|
2138
|
+
node.order = i + orderShift;
|
|
2139
|
+
_.forEach(node.selfEdges, (selfEdge) => {
|
|
2140
|
+
addDummyNode(g, "selfedge", {
|
|
2141
|
+
width: selfEdge.label.width,
|
|
2142
|
+
height: selfEdge.label.height,
|
|
2143
|
+
rank: node.rank,
|
|
2144
|
+
order: i + ++orderShift,
|
|
2145
|
+
e: selfEdge.e,
|
|
2146
|
+
label: selfEdge.label
|
|
2147
|
+
}, "_se");
|
|
2148
|
+
});
|
|
2149
|
+
delete node.selfEdges;
|
|
2150
|
+
});
|
|
2151
|
+
});
|
|
2152
|
+
}
|
|
2153
|
+
function positionSelfEdges(g) {
|
|
2154
|
+
_.forEach(g.nodes(), (v) => {
|
|
2155
|
+
var node = g.node(v);
|
|
2156
|
+
if (node.dummy === "selfedge") {
|
|
2157
|
+
var selfNode = g.node(node.e.v);
|
|
2158
|
+
var x = selfNode.x + selfNode.width / 2;
|
|
2159
|
+
var y = selfNode.y;
|
|
2160
|
+
var dx = node.x - x;
|
|
2161
|
+
var dy = selfNode.height / 2;
|
|
2162
|
+
g.setEdge(node.e, node.label);
|
|
2163
|
+
g.removeNode(v);
|
|
2164
|
+
node.label.points = [
|
|
2165
|
+
{
|
|
2166
|
+
x: x + 2 * dx / 3,
|
|
2167
|
+
y: y - dy
|
|
2168
|
+
},
|
|
2169
|
+
{
|
|
2170
|
+
x: x + 5 * dx / 6,
|
|
2171
|
+
y: y - dy
|
|
2172
|
+
},
|
|
2173
|
+
{
|
|
2174
|
+
x: x + dx,
|
|
2175
|
+
y
|
|
2176
|
+
},
|
|
2177
|
+
{
|
|
2178
|
+
x: x + 5 * dx / 6,
|
|
2179
|
+
y: y + dy
|
|
2180
|
+
},
|
|
2181
|
+
{
|
|
2182
|
+
x: x + 2 * dx / 3,
|
|
2183
|
+
y: y + dy
|
|
2184
|
+
}
|
|
2185
|
+
];
|
|
2186
|
+
node.label.x = node.x;
|
|
2187
|
+
node.label.y = node.y;
|
|
2188
|
+
}
|
|
2189
|
+
});
|
|
2190
|
+
}
|
|
2191
|
+
function selectNumberAttrs(obj, attrs) {
|
|
2192
|
+
return _.mapValues(_.pick(obj, attrs), Number);
|
|
2193
|
+
}
|
|
2194
|
+
function canonicalize(attrs) {
|
|
2195
|
+
var newAttrs = {};
|
|
2196
|
+
_.forEach(attrs, (v, k) => {
|
|
2197
|
+
newAttrs[k.toLowerCase()] = v;
|
|
2198
|
+
});
|
|
2199
|
+
return newAttrs;
|
|
2200
|
+
}
|
|
2201
|
+
//#endregion
|
|
2202
|
+
//#region src/layout/buildFlatCharts.ts
|
|
2203
|
+
/**
|
|
2204
|
+
* Build graphs corresponding to the specified transitions.
|
|
2205
|
+
* @param transitions - The transitions between states.
|
|
2206
|
+
* @param newId - A function that generates unique ids for nodes and edges.
|
|
2207
|
+
* @param getStateParams - A function that returns the dimensions of a state node.
|
|
2208
|
+
* @param getTransitionParams - A function that returns the dimensions of a transition edge.
|
|
2209
|
+
* @param initialStateKey - The key for the initial state.
|
|
2210
|
+
* @param finalStateKey - The key for the final state.
|
|
2211
|
+
* @param vertical - Whether the graph should be vertical.
|
|
2212
|
+
* @returns {TransitionsGraph} - The graph with nodes and edges.
|
|
2213
|
+
*/
|
|
2214
|
+
function buildFlatCharts({ lodash, transitions = [], newId, getStateParams, getTransitionParams, padding = [5, 5], initialStateKey = "<initial>", finalStateKey = "<final>", vertical = false, direction }) {
|
|
2215
|
+
const prevLodash = getLodash();
|
|
2216
|
+
try {
|
|
2217
|
+
setLodash(lodash);
|
|
2218
|
+
const rankdir = direction || (vertical ? "tb" : "lr");
|
|
2219
|
+
const graph = new Graph({
|
|
2220
|
+
directed: true,
|
|
2221
|
+
multigraph: true
|
|
2222
|
+
}).setGraph({
|
|
2223
|
+
rankdir,
|
|
2224
|
+
multigraph: true
|
|
2225
|
+
});
|
|
2226
|
+
const nodesIndex = {};
|
|
2227
|
+
const getStateNodeId = (key, state = key) => {
|
|
2228
|
+
let id = nodesIndex[key];
|
|
2229
|
+
if (!id) {
|
|
2230
|
+
id = nodesIndex[key] = newId("s");
|
|
2231
|
+
const params = getStateParams(key, state);
|
|
2232
|
+
graph.setNode(id, {
|
|
2233
|
+
id,
|
|
2234
|
+
...params
|
|
2235
|
+
});
|
|
2236
|
+
}
|
|
2237
|
+
return id;
|
|
2238
|
+
};
|
|
2239
|
+
for (const [fromState, event, toState] of transitions) {
|
|
2240
|
+
const fromStateKey = fromState || initialStateKey;
|
|
2241
|
+
const from = getStateNodeId(fromStateKey, fromState);
|
|
2242
|
+
const toStateKey = toState || finalStateKey;
|
|
2243
|
+
const to = getStateNodeId(toStateKey, toState);
|
|
2244
|
+
const params = getTransitionParams(fromStateKey, event, toStateKey);
|
|
2245
|
+
const edgeId = newId("t");
|
|
2246
|
+
graph.setEdge(from, to, {
|
|
2247
|
+
id: edgeId,
|
|
2248
|
+
...params
|
|
2249
|
+
}, edgeId);
|
|
2250
|
+
}
|
|
2251
|
+
layout(graph, { rankdir });
|
|
2252
|
+
const [top, right, bottom, left] = getPadding(padding);
|
|
2253
|
+
const nodes = graph.nodes().map((id) => {
|
|
2254
|
+
const n = graph.node(id);
|
|
2255
|
+
n.x += -n.width / 2;
|
|
2256
|
+
n.y += -n.height / 2;
|
|
2257
|
+
return n;
|
|
2258
|
+
});
|
|
2259
|
+
const edges = graph.edges().map(({ v, w, name }) => {
|
|
2260
|
+
const e = graph.edge(v, w, name);
|
|
2261
|
+
e.x += -e.width / 2;
|
|
2262
|
+
e.y += -e.height / 2;
|
|
2263
|
+
return e;
|
|
2264
|
+
});
|
|
2265
|
+
let x = 0;
|
|
2266
|
+
let y = 0;
|
|
2267
|
+
let width = 0;
|
|
2268
|
+
let height = 0;
|
|
2269
|
+
const addCoords = (node) => {
|
|
2270
|
+
x = Math.min(x, node.x);
|
|
2271
|
+
y = Math.min(y, node.y);
|
|
2272
|
+
width = Math.max(width, node.x + node.width);
|
|
2273
|
+
height = Math.max(height, node.y + node.height);
|
|
2274
|
+
};
|
|
2275
|
+
nodes.forEach(addCoords);
|
|
2276
|
+
edges.forEach(addCoords);
|
|
2277
|
+
edges.forEach((edge) => {
|
|
2278
|
+
for (const point of edge.points) {
|
|
2279
|
+
x = Math.min(x, edge.x);
|
|
2280
|
+
y = Math.min(y, edge.y);
|
|
2281
|
+
width = Math.max(width, point.x);
|
|
2282
|
+
height = Math.max(height, point.y);
|
|
2283
|
+
}
|
|
2284
|
+
});
|
|
2285
|
+
width += left + right;
|
|
2286
|
+
height += bottom + top;
|
|
2287
|
+
const updateCoords = (node) => {
|
|
2288
|
+
node.x = Math.round(node.x + left);
|
|
2289
|
+
node.y = Math.round(node.y + bottom);
|
|
2290
|
+
};
|
|
2291
|
+
const updateBox = (node) => {
|
|
2292
|
+
updateCoords(node);
|
|
2293
|
+
node.y = Math.round(node.y + node.height);
|
|
2294
|
+
};
|
|
2295
|
+
nodes.forEach(updateBox);
|
|
2296
|
+
edges.forEach(updateBox);
|
|
2297
|
+
edges.forEach((edge) => {
|
|
2298
|
+
edge.points.forEach(updateCoords);
|
|
2299
|
+
});
|
|
2300
|
+
return {
|
|
2301
|
+
x,
|
|
2302
|
+
y,
|
|
2303
|
+
width,
|
|
2304
|
+
height,
|
|
2305
|
+
nodes,
|
|
2306
|
+
edges
|
|
2307
|
+
};
|
|
2308
|
+
} finally {
|
|
2309
|
+
setLodash(prevLodash);
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
//#endregion
|
|
2313
|
+
//#region src/layout/buildCharts.ts
|
|
2314
|
+
/**
|
|
2315
|
+
* Build graphs corresponding to the specified transitions.
|
|
2316
|
+
* @param config - State configuration with transitions and sub-states.
|
|
2317
|
+
* @param newId - A function that generates unique ids for nodes and edges.
|
|
2318
|
+
* @param getStateParams - A function that returns the dimensions of a state node.
|
|
2319
|
+
* @param getTransitionParams - A function that returns the dimensions of a transition edge.
|
|
2320
|
+
* @param initialStateKey - The key for the initial state.
|
|
2321
|
+
* @param finalStateKey - The key for the final state.
|
|
2322
|
+
* @returns {StateChart} - The graph with nodes and edges.
|
|
2323
|
+
*/
|
|
2324
|
+
function buildCharts({ lodash, config, newId, getStateParams, getStateLabel = (stateKey) => stateKey.replace(/([a-z])([A-Z])/g, "$1 $2"), getTransitionParams, padding = [5, 5], vertical = false, initialStateKey = "<initial>", finalStateKey = "<final>", direction }) {
|
|
2325
|
+
return buildChart(config);
|
|
2326
|
+
function buildChart(config, id = newId("s"), stack = []) {
|
|
2327
|
+
stack.push(config);
|
|
2328
|
+
try {
|
|
2329
|
+
const buildStateLabel = (state, key = state) => {
|
|
2330
|
+
if (key === initialStateKey || key === finalStateKey) return "";
|
|
2331
|
+
let result;
|
|
2332
|
+
for (let i = stack.length - 1; result === void 0 && i >= 0; i--) {
|
|
2333
|
+
const conf = stack[i];
|
|
2334
|
+
if (!conf.states) continue;
|
|
2335
|
+
for (const subState of conf.states) {
|
|
2336
|
+
if (subState.key !== state) continue;
|
|
2337
|
+
result = subState.label ?? getStateLabel(state);
|
|
2338
|
+
break;
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
return result ?? getStateLabel(state) ?? state;
|
|
2342
|
+
};
|
|
2343
|
+
const graph = buildFlatCharts({
|
|
2344
|
+
lodash,
|
|
2345
|
+
transitions: config.transitions || [],
|
|
2346
|
+
newId,
|
|
2347
|
+
getStateParams: (state, key) => {
|
|
2348
|
+
const params = getStateParams(state, key);
|
|
2349
|
+
delete params.state;
|
|
2350
|
+
params.text = buildStateLabel(state, key);
|
|
2351
|
+
return params;
|
|
2352
|
+
},
|
|
2353
|
+
getTransitionParams,
|
|
2354
|
+
padding,
|
|
2355
|
+
initialStateKey,
|
|
2356
|
+
finalStateKey,
|
|
2357
|
+
vertical,
|
|
2358
|
+
direction
|
|
2359
|
+
});
|
|
2360
|
+
const index = graph.nodes.reduce((index, node) => {
|
|
2361
|
+
index[node.key] = node.id;
|
|
2362
|
+
return index;
|
|
2363
|
+
}, {});
|
|
2364
|
+
const text = config.label ?? getStateLabel(config.key) ?? config.key;
|
|
2365
|
+
const children = [];
|
|
2366
|
+
if (config.states) for (const child of config.states) {
|
|
2367
|
+
const childId = index[child.key];
|
|
2368
|
+
children.push(buildChart(child, childId, [...stack]));
|
|
2369
|
+
}
|
|
2370
|
+
return {
|
|
2371
|
+
id,
|
|
2372
|
+
key: config.key,
|
|
2373
|
+
text,
|
|
2374
|
+
...graph,
|
|
2375
|
+
children
|
|
2376
|
+
};
|
|
2377
|
+
} finally {}
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
//#endregion
|
|
2381
|
+
//#region src/layout/getLabelDimensions.ts
|
|
2382
|
+
function getLabelDimensions(label, { padding = 0, fontSize = 14, getCharWidth = () => fontSize / 1.61, lineGap = fontSize * .2 } = {}) {
|
|
2383
|
+
const lines = [label];
|
|
2384
|
+
let dimensions = {
|
|
2385
|
+
width: 0,
|
|
2386
|
+
height: 0
|
|
2387
|
+
};
|
|
2388
|
+
let lineNumber = 0;
|
|
2389
|
+
for (const line of lines) {
|
|
2390
|
+
if (lineNumber++) dimensions.height += lineGap;
|
|
2391
|
+
dimensions = expandBox(dimensions, getLineDimensions({
|
|
2392
|
+
line,
|
|
2393
|
+
fontSize,
|
|
2394
|
+
getCharWidth
|
|
2395
|
+
}));
|
|
2396
|
+
}
|
|
2397
|
+
const [top, right, bottom, left] = getPadding(padding);
|
|
2398
|
+
return {
|
|
2399
|
+
width: Math.round(dimensions.width + left + right),
|
|
2400
|
+
height: Math.round(dimensions.height + top + bottom)
|
|
2401
|
+
};
|
|
2402
|
+
function expandBox(dim1, dim2) {
|
|
2403
|
+
return {
|
|
2404
|
+
width: Math.round(Math.max(dim1.width, dim2.width)),
|
|
2405
|
+
height: Math.round(dim1.height + dim2.height)
|
|
2406
|
+
};
|
|
2407
|
+
}
|
|
2408
|
+
function getLineDimensions({ line, fontSize = 14, getCharWidth = () => fontSize }) {
|
|
2409
|
+
return {
|
|
2410
|
+
width: line.split("").reduce((w, c) => w += getCharWidth(c), 0),
|
|
2411
|
+
height: fontSize
|
|
2412
|
+
};
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2415
|
+
//#endregion
|
|
2416
|
+
//#region src/layout/getGraphParamsProvider.ts
|
|
2417
|
+
/**
|
|
2418
|
+
* Provides default functions measuring dimensions for state nodes and transition edges in the graph.
|
|
2419
|
+
* @param fontSize - The font size for the state and transition labels.
|
|
2420
|
+
* @param stateFontSize - The font size for the state labels.
|
|
2421
|
+
* @param stateTextPadding - The padding around the state labels.
|
|
2422
|
+
* @param transitionsFontSize - The font size for the transition labels.
|
|
2423
|
+
* @param transitionsTextPadding - The padding around the transition labels.
|
|
2424
|
+
*/
|
|
2425
|
+
function getGraphParamsProvider({ fontSize = 14, stateFontSize = fontSize, stateTextPadding = 0, transitionsFontSize = fontSize, transitionsTextPadding = 0, getStateLabel = (state) => state, getTransitionLabel = (_fromState, event, _toState) => event } = {}) {
|
|
2426
|
+
return {
|
|
2427
|
+
getStateParams: (stateKey, state = stateKey) => {
|
|
2428
|
+
const padding = getPadding(stateTextPadding);
|
|
2429
|
+
const fontSize = stateFontSize;
|
|
2430
|
+
const stateLabel = getStateLabel(state);
|
|
2431
|
+
return {
|
|
2432
|
+
...getLabelDimensions(stateLabel, {
|
|
2433
|
+
padding,
|
|
2434
|
+
fontSize
|
|
2435
|
+
}),
|
|
2436
|
+
state,
|
|
2437
|
+
text: stateLabel,
|
|
2438
|
+
key: stateKey,
|
|
2439
|
+
padding,
|
|
2440
|
+
fontSize
|
|
2441
|
+
};
|
|
2442
|
+
},
|
|
2443
|
+
getTransitionParams: (fromStateKey, event, toStateKey) => {
|
|
2444
|
+
const padding = getPadding(transitionsTextPadding);
|
|
2445
|
+
const fontSize = transitionsFontSize;
|
|
2446
|
+
const eventLabel = getTransitionLabel(fromStateKey, event, toStateKey);
|
|
2447
|
+
return {
|
|
2448
|
+
...getLabelDimensions(eventLabel, {
|
|
2449
|
+
padding,
|
|
2450
|
+
fontSize
|
|
2451
|
+
}),
|
|
2452
|
+
from: fromStateKey,
|
|
2453
|
+
event,
|
|
2454
|
+
to: toStateKey,
|
|
2455
|
+
text: eventLabel,
|
|
2456
|
+
padding,
|
|
2457
|
+
fontSize
|
|
2458
|
+
};
|
|
2459
|
+
}
|
|
2460
|
+
};
|
|
2461
|
+
}
|
|
2462
|
+
//#endregion
|
|
2463
|
+
export { buildFlatCharts as i, getLabelDimensions as n, buildCharts as r, getGraphParamsProvider as t };
|
|
2464
|
+
|
|
2465
|
+
//# sourceMappingURL=layout-Dp671N6q.js.map
|