cg-code-graph 0.10.1__py3-none-any.whl

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.
Files changed (174) hide show
  1. cg_code_graph-0.10.1.dist-info/METADATA +678 -0
  2. cg_code_graph-0.10.1.dist-info/RECORD +174 -0
  3. cg_code_graph-0.10.1.dist-info/WHEEL +5 -0
  4. cg_code_graph-0.10.1.dist-info/entry_points.txt +3 -0
  5. cg_code_graph-0.10.1.dist-info/licenses/LICENSE +21 -0
  6. cg_code_graph-0.10.1.dist-info/top_level.txt +1 -0
  7. codegraph/__init__.py +2 -0
  8. codegraph/aitools.py +129 -0
  9. codegraph/apps.py +76 -0
  10. codegraph/blindspots.py +428 -0
  11. codegraph/bridges.py +1701 -0
  12. codegraph/cli.py +725 -0
  13. codegraph/concepts.py +362 -0
  14. codegraph/config.py +559 -0
  15. codegraph/core/__init__.py +0 -0
  16. codegraph/core/cache.py +375 -0
  17. codegraph/core/detect.py +80 -0
  18. codegraph/core/extractors.py +187 -0
  19. codegraph/core/fsutil.py +61 -0
  20. codegraph/core/generated.py +575 -0
  21. codegraph/core/model.py +174 -0
  22. codegraph/core/paths.py +175 -0
  23. codegraph/core/plugin.py +160 -0
  24. codegraph/core/store.py +80 -0
  25. codegraph/core/syntax_errors.py +132 -0
  26. codegraph/coverage.py +928 -0
  27. codegraph/doctor.py +453 -0
  28. codegraph/external.py +613 -0
  29. codegraph/indexer.py +336 -0
  30. codegraph/link.py +434 -0
  31. codegraph/lint_async.py +524 -0
  32. codegraph/mcp_server.py +1303 -0
  33. codegraph/parity.py +473 -0
  34. codegraph/parity_structure.py +307 -0
  35. codegraph/payload.py +321 -0
  36. codegraph/plans.py +1285 -0
  37. codegraph/platform_scan.py +643 -0
  38. codegraph/platforms.py +1369 -0
  39. codegraph/plugins/__init__.py +0 -0
  40. codegraph/plugins/cfamily/__init__.py +0 -0
  41. codegraph/plugins/cfamily/plugin.py +930 -0
  42. codegraph/plugins/cfamily/syntax.py +881 -0
  43. codegraph/plugins/dart/__init__.py +0 -0
  44. codegraph/plugins/dart/bridges.py +345 -0
  45. codegraph/plugins/dart/extractor/bin/extract.dart +717 -0
  46. codegraph/plugins/dart/extractor/pubspec.lock +149 -0
  47. codegraph/plugins/dart/extractor/pubspec.yaml +7 -0
  48. codegraph/plugins/dart/http.py +904 -0
  49. codegraph/plugins/dart/models.py +308 -0
  50. codegraph/plugins/dart/plugin.py +625 -0
  51. codegraph/plugins/dart/program.py +907 -0
  52. codegraph/plugins/django/__init__.py +0 -0
  53. codegraph/plugins/django/extras.py +378 -0
  54. codegraph/plugins/django/models.py +508 -0
  55. codegraph/plugins/django/plugin.py +728 -0
  56. codegraph/plugins/django/schemas.py +339 -0
  57. codegraph/plugins/django/shapes.py +216 -0
  58. codegraph/plugins/django/urls.py +603 -0
  59. codegraph/plugins/express/__init__.py +0 -0
  60. codegraph/plugins/express/plugin.py +428 -0
  61. codegraph/plugins/flutter/__init__.py +0 -0
  62. codegraph/plugins/flutter/plugin.py +538 -0
  63. codegraph/plugins/kotlin/__init__.py +0 -0
  64. codegraph/plugins/kotlin/exact.py +457 -0
  65. codegraph/plugins/kotlin/plugin.py +1961 -0
  66. codegraph/plugins/kotlin/reparse.py +234 -0
  67. codegraph/plugins/laravel/__init__.py +0 -0
  68. codegraph/plugins/laravel/broadcast.py +351 -0
  69. codegraph/plugins/laravel/plugin.py +863 -0
  70. codegraph/plugins/laravel/tests.py +262 -0
  71. codegraph/plugins/laravel/values.py +728 -0
  72. codegraph/plugins/native/__init__.py +0 -0
  73. codegraph/plugins/native/gates.py +286 -0
  74. codegraph/plugins/native/runner.py +183 -0
  75. codegraph/plugins/native/scipread.py +194 -0
  76. codegraph/plugins/native/ts.py +54 -0
  77. codegraph/plugins/nest/__init__.py +0 -0
  78. codegraph/plugins/nest/plugin.py +654 -0
  79. codegraph/plugins/nextjs/__init__.py +0 -0
  80. codegraph/plugins/nextjs/plugin.py +336 -0
  81. codegraph/plugins/nuxt/__init__.py +0 -0
  82. codegraph/plugins/nuxt/plugin.py +308 -0
  83. codegraph/plugins/php/__init__.py +0 -0
  84. codegraph/plugins/php/extractor/composer.json +5 -0
  85. codegraph/plugins/php/extractor/composer.lock +76 -0
  86. codegraph/plugins/php/extractor/extract.php +743 -0
  87. codegraph/plugins/php/gating.py +573 -0
  88. codegraph/plugins/php/plugin.py +668 -0
  89. codegraph/plugins/php/strings.py +197 -0
  90. codegraph/plugins/python/__init__.py +0 -0
  91. codegraph/plugins/python/aitools.py +664 -0
  92. codegraph/plugins/python/external.py +245 -0
  93. codegraph/plugins/python/fields.py +107 -0
  94. codegraph/plugins/python/plugin.py +1733 -0
  95. codegraph/plugins/python/refs.py +485 -0
  96. codegraph/plugins/python/roots.py +412 -0
  97. codegraph/plugins/python/socketio.py +210 -0
  98. codegraph/plugins/python/subproc.py +864 -0
  99. codegraph/plugins/python/tests.py +1040 -0
  100. codegraph/plugins/python/values.py +179 -0
  101. codegraph/plugins/pyweb/__init__.py +0 -0
  102. codegraph/plugins/pyweb/plugin.py +1334 -0
  103. codegraph/plugins/pyweb/values.py +68 -0
  104. codegraph/plugins/rust/__init__.py +0 -0
  105. codegraph/plugins/rust/cargo.py +226 -0
  106. codegraph/plugins/rust/plugin.py +980 -0
  107. codegraph/plugins/rust/syntax.py +678 -0
  108. codegraph/plugins/scip/__init__.py +0 -0
  109. codegraph/plugins/scip/importer.py +129 -0
  110. codegraph/plugins/scip/scip.proto +962 -0
  111. codegraph/plugins/scip/scip_pb2.py +97 -0
  112. codegraph/plugins/stubs/__init__.py +0 -0
  113. codegraph/plugins/stubs/plugins.py +38 -0
  114. codegraph/plugins/swift/__init__.py +0 -0
  115. codegraph/plugins/swift/baseurl.py +109 -0
  116. codegraph/plugins/swift/exact.py +415 -0
  117. codegraph/plugins/swift/indexstore.py +209 -0
  118. codegraph/plugins/swift/packages.py +174 -0
  119. codegraph/plugins/swift/plugin.py +2890 -0
  120. codegraph/plugins/ts/__init__.py +0 -0
  121. codegraph/plugins/ts/baseurl.py +185 -0
  122. codegraph/plugins/ts/extractor/extract.mjs +2652 -0
  123. codegraph/plugins/ts/extractor/fw.mjs +685 -0
  124. codegraph/plugins/ts/extractor/package-lock.json +205 -0
  125. codegraph/plugins/ts/extractor/package.json +9 -0
  126. codegraph/plugins/ts/plugin.py +480 -0
  127. codegraph/plugins/tsweb/__init__.py +0 -0
  128. codegraph/plugins/tsweb/common.py +290 -0
  129. codegraph/plugins/tsweb/data.py +276 -0
  130. codegraph/presets/__init__.py +146 -0
  131. codegraph/presets/c_cpp.yaml +9 -0
  132. codegraph/presets/common.yaml +66 -0
  133. codegraph/presets/dart.yaml +9 -0
  134. codegraph/presets/django-ninja.yaml +15 -0
  135. codegraph/presets/django.yaml +25 -0
  136. codegraph/presets/djangorestframework.yaml +17 -0
  137. codegraph/presets/express.yaml +17 -0
  138. codegraph/presets/kotlin.yaml +11 -0
  139. codegraph/presets/laravel.yaml +40 -0
  140. codegraph/presets/nest.yaml +11 -0
  141. codegraph/presets/nextjs.yaml +15 -0
  142. codegraph/presets/nuxt.yaml +9 -0
  143. codegraph/presets/php.yaml +5 -0
  144. codegraph/presets/python.yaml +10 -0
  145. codegraph/presets/rust.yaml +5 -0
  146. codegraph/presets/swift.yaml +10 -0
  147. codegraph/presets/typescript.yaml +13 -0
  148. codegraph/process_runs.py +328 -0
  149. codegraph/protocols/__init__.py +299 -0
  150. codegraph/protocols/builtin.py +67 -0
  151. codegraph/protocols/matchers.py +144 -0
  152. codegraph/protocols/view.py +334 -0
  153. codegraph/query.py +2089 -0
  154. codegraph/realtime.py +260 -0
  155. codegraph/roundtrip.py +346 -0
  156. codegraph/routes.py +442 -0
  157. codegraph/starters.py +218 -0
  158. codegraph/tests_index.py +117 -0
  159. codegraph/viz/__init__.py +0 -0
  160. codegraph/viz/graph.py +369 -0
  161. codegraph/viz/server.py +198 -0
  162. codegraph/viz/static/app.css +148 -0
  163. codegraph/viz/static/app.js +1082 -0
  164. codegraph/viz/static/index.html +81 -0
  165. codegraph/viz/static/layered.js +237 -0
  166. codegraph/viz/static/vendor/VERSIONS.txt +4 -0
  167. codegraph/viz/static/vendor/cose-base.js +3214 -0
  168. codegraph/viz/static/vendor/cytoscape-fcose.js +1549 -0
  169. codegraph/viz/static/vendor/cytoscape.min.js +31 -0
  170. codegraph/viz/static/vendor/layout-base.js +5230 -0
  171. codegraph/viz/tools/package-lock.json +303 -0
  172. codegraph/viz/tools/package.json +7 -0
  173. codegraph/viz/tools/shoot.mjs +165 -0
  174. codegraph/xcode.py +251 -0
@@ -0,0 +1,3214 @@
1
+ (function webpackUniversalModuleDefinition(root, factory) {
2
+ if(typeof exports === 'object' && typeof module === 'object')
3
+ module.exports = factory(require("layout-base"));
4
+ else if(typeof define === 'function' && define.amd)
5
+ define(["layout-base"], factory);
6
+ else if(typeof exports === 'object')
7
+ exports["coseBase"] = factory(require("layout-base"));
8
+ else
9
+ root["coseBase"] = factory(root["layoutBase"]);
10
+ })(this, function(__WEBPACK_EXTERNAL_MODULE__551__) {
11
+ return /******/ (() => { // webpackBootstrap
12
+ /******/ "use strict";
13
+ /******/ var __webpack_modules__ = ({
14
+
15
+ /***/ 45:
16
+ /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
17
+
18
+
19
+
20
+ var coseBase = {};
21
+
22
+ coseBase.layoutBase = __webpack_require__(551);
23
+ coseBase.CoSEConstants = __webpack_require__(806);
24
+ coseBase.CoSEEdge = __webpack_require__(767);
25
+ coseBase.CoSEGraph = __webpack_require__(880);
26
+ coseBase.CoSEGraphManager = __webpack_require__(578);
27
+ coseBase.CoSELayout = __webpack_require__(765);
28
+ coseBase.CoSENode = __webpack_require__(991);
29
+ coseBase.ConstraintHandler = __webpack_require__(902);
30
+
31
+ module.exports = coseBase;
32
+
33
+ /***/ }),
34
+
35
+ /***/ 806:
36
+ /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
37
+
38
+
39
+
40
+ var FDLayoutConstants = __webpack_require__(551).FDLayoutConstants;
41
+
42
+ function CoSEConstants() {}
43
+
44
+ //CoSEConstants inherits static props in FDLayoutConstants
45
+ for (var prop in FDLayoutConstants) {
46
+ CoSEConstants[prop] = FDLayoutConstants[prop];
47
+ }
48
+
49
+ CoSEConstants.DEFAULT_USE_MULTI_LEVEL_SCALING = false;
50
+ CoSEConstants.DEFAULT_RADIAL_SEPARATION = FDLayoutConstants.DEFAULT_EDGE_LENGTH;
51
+ CoSEConstants.DEFAULT_COMPONENT_SEPERATION = 60;
52
+ CoSEConstants.TILE = true;
53
+ CoSEConstants.TILING_PADDING_VERTICAL = 10;
54
+ CoSEConstants.TILING_PADDING_HORIZONTAL = 10;
55
+ CoSEConstants.TRANSFORM_ON_CONSTRAINT_HANDLING = true;
56
+ CoSEConstants.ENFORCE_CONSTRAINTS = true;
57
+ CoSEConstants.APPLY_LAYOUT = true;
58
+ CoSEConstants.RELAX_MOVEMENT_ON_CONSTRAINTS = true;
59
+ CoSEConstants.TREE_REDUCTION_ON_INCREMENTAL = true; // this should be set to false if there will be a constraint
60
+ // This constant is for differentiating whether actual layout algorithm that uses cose-base wants to apply only incremental layout or
61
+ // an incremental layout on top of a randomized layout. If it is only incremental layout, then this constant should be true.
62
+ CoSEConstants.PURE_INCREMENTAL = CoSEConstants.DEFAULT_INCREMENTAL;
63
+
64
+ module.exports = CoSEConstants;
65
+
66
+ /***/ }),
67
+
68
+ /***/ 767:
69
+ /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
70
+
71
+
72
+
73
+ var FDLayoutEdge = __webpack_require__(551).FDLayoutEdge;
74
+
75
+ function CoSEEdge(source, target, vEdge) {
76
+ FDLayoutEdge.call(this, source, target, vEdge);
77
+ }
78
+
79
+ CoSEEdge.prototype = Object.create(FDLayoutEdge.prototype);
80
+ for (var prop in FDLayoutEdge) {
81
+ CoSEEdge[prop] = FDLayoutEdge[prop];
82
+ }
83
+
84
+ module.exports = CoSEEdge;
85
+
86
+ /***/ }),
87
+
88
+ /***/ 880:
89
+ /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
90
+
91
+
92
+
93
+ var LGraph = __webpack_require__(551).LGraph;
94
+
95
+ function CoSEGraph(parent, graphMgr, vGraph) {
96
+ LGraph.call(this, parent, graphMgr, vGraph);
97
+ }
98
+
99
+ CoSEGraph.prototype = Object.create(LGraph.prototype);
100
+ for (var prop in LGraph) {
101
+ CoSEGraph[prop] = LGraph[prop];
102
+ }
103
+
104
+ module.exports = CoSEGraph;
105
+
106
+ /***/ }),
107
+
108
+ /***/ 578:
109
+ /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
110
+
111
+
112
+
113
+ var LGraphManager = __webpack_require__(551).LGraphManager;
114
+
115
+ function CoSEGraphManager(layout) {
116
+ LGraphManager.call(this, layout);
117
+ }
118
+
119
+ CoSEGraphManager.prototype = Object.create(LGraphManager.prototype);
120
+ for (var prop in LGraphManager) {
121
+ CoSEGraphManager[prop] = LGraphManager[prop];
122
+ }
123
+
124
+ module.exports = CoSEGraphManager;
125
+
126
+ /***/ }),
127
+
128
+ /***/ 765:
129
+ /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
130
+
131
+
132
+
133
+ var FDLayout = __webpack_require__(551).FDLayout;
134
+ var CoSEGraphManager = __webpack_require__(578);
135
+ var CoSEGraph = __webpack_require__(880);
136
+ var CoSENode = __webpack_require__(991);
137
+ var CoSEEdge = __webpack_require__(767);
138
+ var CoSEConstants = __webpack_require__(806);
139
+ var ConstraintHandler = __webpack_require__(902);
140
+ var FDLayoutConstants = __webpack_require__(551).FDLayoutConstants;
141
+ var LayoutConstants = __webpack_require__(551).LayoutConstants;
142
+ var Point = __webpack_require__(551).Point;
143
+ var PointD = __webpack_require__(551).PointD;
144
+ var DimensionD = __webpack_require__(551).DimensionD;
145
+ var Layout = __webpack_require__(551).Layout;
146
+ var Integer = __webpack_require__(551).Integer;
147
+ var IGeometry = __webpack_require__(551).IGeometry;
148
+ var LGraph = __webpack_require__(551).LGraph;
149
+ var Transform = __webpack_require__(551).Transform;
150
+ var LinkedList = __webpack_require__(551).LinkedList;
151
+
152
+ function CoSELayout() {
153
+ FDLayout.call(this);
154
+
155
+ this.toBeTiled = {}; // Memorize if a node is to be tiled or is tiled
156
+ this.constraints = {}; // keep layout constraints
157
+ }
158
+
159
+ CoSELayout.prototype = Object.create(FDLayout.prototype);
160
+
161
+ for (var prop in FDLayout) {
162
+ CoSELayout[prop] = FDLayout[prop];
163
+ }
164
+
165
+ CoSELayout.prototype.newGraphManager = function () {
166
+ var gm = new CoSEGraphManager(this);
167
+ this.graphManager = gm;
168
+ return gm;
169
+ };
170
+
171
+ CoSELayout.prototype.newGraph = function (vGraph) {
172
+ return new CoSEGraph(null, this.graphManager, vGraph);
173
+ };
174
+
175
+ CoSELayout.prototype.newNode = function (vNode) {
176
+ return new CoSENode(this.graphManager, vNode);
177
+ };
178
+
179
+ CoSELayout.prototype.newEdge = function (vEdge) {
180
+ return new CoSEEdge(null, null, vEdge);
181
+ };
182
+
183
+ CoSELayout.prototype.initParameters = function () {
184
+ FDLayout.prototype.initParameters.call(this, arguments);
185
+ if (!this.isSubLayout) {
186
+ if (CoSEConstants.DEFAULT_EDGE_LENGTH < 10) {
187
+ this.idealEdgeLength = 10;
188
+ } else {
189
+ this.idealEdgeLength = CoSEConstants.DEFAULT_EDGE_LENGTH;
190
+ }
191
+
192
+ this.useSmartIdealEdgeLengthCalculation = CoSEConstants.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION;
193
+ this.gravityConstant = FDLayoutConstants.DEFAULT_GRAVITY_STRENGTH;
194
+ this.compoundGravityConstant = FDLayoutConstants.DEFAULT_COMPOUND_GRAVITY_STRENGTH;
195
+ this.gravityRangeFactor = FDLayoutConstants.DEFAULT_GRAVITY_RANGE_FACTOR;
196
+ this.compoundGravityRangeFactor = FDLayoutConstants.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR;
197
+
198
+ // variables for tree reduction support
199
+ this.prunedNodesAll = [];
200
+ this.growTreeIterations = 0;
201
+ this.afterGrowthIterations = 0;
202
+ this.isTreeGrowing = false;
203
+ this.isGrowthFinished = false;
204
+ }
205
+ };
206
+
207
+ // This method is used to set CoSE related parameters used by spring embedder.
208
+ CoSELayout.prototype.initSpringEmbedder = function () {
209
+ FDLayout.prototype.initSpringEmbedder.call(this);
210
+
211
+ // variables for cooling
212
+ this.coolingCycle = 0;
213
+ this.maxCoolingCycle = this.maxIterations / FDLayoutConstants.CONVERGENCE_CHECK_PERIOD;
214
+ this.finalTemperature = 0.04;
215
+ this.coolingAdjuster = 1;
216
+ };
217
+
218
+ CoSELayout.prototype.layout = function () {
219
+ var createBendsAsNeeded = LayoutConstants.DEFAULT_CREATE_BENDS_AS_NEEDED;
220
+ if (createBendsAsNeeded) {
221
+ this.createBendpoints();
222
+ this.graphManager.resetAllEdges();
223
+ }
224
+
225
+ this.level = 0;
226
+ return this.classicLayout();
227
+ };
228
+
229
+ CoSELayout.prototype.classicLayout = function () {
230
+ this.nodesWithGravity = this.calculateNodesToApplyGravitationTo();
231
+ this.graphManager.setAllNodesToApplyGravitation(this.nodesWithGravity);
232
+ this.calcNoOfChildrenForAllNodes();
233
+ this.graphManager.calcLowestCommonAncestors();
234
+ this.graphManager.calcInclusionTreeDepths();
235
+ this.graphManager.getRoot().calcEstimatedSize();
236
+ this.calcIdealEdgeLengths();
237
+
238
+ if (!this.incremental) {
239
+ var forest = this.getFlatForest();
240
+
241
+ // The graph associated with this layout is flat and a forest
242
+ if (forest.length > 0) {
243
+ this.positionNodesRadially(forest);
244
+ }
245
+ // The graph associated with this layout is not flat or a forest
246
+ else {
247
+ // Reduce the trees when incremental mode is not enabled and graph is not a forest
248
+ this.reduceTrees();
249
+ // Update nodes that gravity will be applied
250
+ this.graphManager.resetAllNodesToApplyGravitation();
251
+ var allNodes = new Set(this.getAllNodes());
252
+ var intersection = this.nodesWithGravity.filter(function (x) {
253
+ return allNodes.has(x);
254
+ });
255
+ this.graphManager.setAllNodesToApplyGravitation(intersection);
256
+
257
+ this.positionNodesRandomly();
258
+ }
259
+ } else {
260
+ if (CoSEConstants.TREE_REDUCTION_ON_INCREMENTAL) {
261
+ // Reduce the trees in incremental mode if only this constant is set to true
262
+ this.reduceTrees();
263
+ // Update nodes that gravity will be applied
264
+ this.graphManager.resetAllNodesToApplyGravitation();
265
+ var allNodes = new Set(this.getAllNodes());
266
+ var intersection = this.nodesWithGravity.filter(function (x) {
267
+ return allNodes.has(x);
268
+ });
269
+ this.graphManager.setAllNodesToApplyGravitation(intersection);
270
+ }
271
+ }
272
+
273
+ if (Object.keys(this.constraints).length > 0) {
274
+ ConstraintHandler.handleConstraints(this);
275
+ this.initConstraintVariables();
276
+ }
277
+
278
+ this.initSpringEmbedder();
279
+ if (CoSEConstants.APPLY_LAYOUT) {
280
+ this.runSpringEmbedder();
281
+ }
282
+
283
+ return true;
284
+ };
285
+
286
+ CoSELayout.prototype.tick = function () {
287
+ this.totalIterations++;
288
+
289
+ if (this.totalIterations === this.maxIterations && !this.isTreeGrowing && !this.isGrowthFinished) {
290
+ if (this.prunedNodesAll.length > 0) {
291
+ this.isTreeGrowing = true;
292
+ } else {
293
+ return true;
294
+ }
295
+ }
296
+
297
+ if (this.totalIterations % FDLayoutConstants.CONVERGENCE_CHECK_PERIOD == 0 && !this.isTreeGrowing && !this.isGrowthFinished) {
298
+ if (this.isConverged()) {
299
+ if (this.prunedNodesAll.length > 0) {
300
+ this.isTreeGrowing = true;
301
+ } else {
302
+ return true;
303
+ }
304
+ }
305
+
306
+ this.coolingCycle++;
307
+
308
+ if (this.layoutQuality == 0) {
309
+ // quality - "draft"
310
+ this.coolingAdjuster = this.coolingCycle;
311
+ } else if (this.layoutQuality == 1) {
312
+ // quality - "default"
313
+ this.coolingAdjuster = this.coolingCycle / 3;
314
+ }
315
+
316
+ // cooling schedule is based on http://www.btluke.com/simanf1.html -> cooling schedule 3
317
+ this.coolingFactor = Math.max(this.initialCoolingFactor - Math.pow(this.coolingCycle, Math.log(100 * (this.initialCoolingFactor - this.finalTemperature)) / Math.log(this.maxCoolingCycle)) / 100 * this.coolingAdjuster, this.finalTemperature);
318
+ this.animationPeriod = Math.ceil(this.initialAnimationPeriod * Math.sqrt(this.coolingFactor));
319
+ }
320
+ // Operations while tree is growing again
321
+ if (this.isTreeGrowing) {
322
+ if (this.growTreeIterations % 10 == 0) {
323
+ if (this.prunedNodesAll.length > 0) {
324
+ this.graphManager.updateBounds();
325
+ this.updateGrid();
326
+ this.growTree(this.prunedNodesAll);
327
+ // Update nodes that gravity will be applied
328
+ this.graphManager.resetAllNodesToApplyGravitation();
329
+ var allNodes = new Set(this.getAllNodes());
330
+ var intersection = this.nodesWithGravity.filter(function (x) {
331
+ return allNodes.has(x);
332
+ });
333
+ this.graphManager.setAllNodesToApplyGravitation(intersection);
334
+
335
+ this.graphManager.updateBounds();
336
+ this.updateGrid();
337
+ if (CoSEConstants.PURE_INCREMENTAL) this.coolingFactor = FDLayoutConstants.DEFAULT_COOLING_FACTOR_INCREMENTAL / 2;else this.coolingFactor = FDLayoutConstants.DEFAULT_COOLING_FACTOR_INCREMENTAL;
338
+ } else {
339
+ this.isTreeGrowing = false;
340
+ this.isGrowthFinished = true;
341
+ }
342
+ }
343
+ this.growTreeIterations++;
344
+ }
345
+ // Operations after growth is finished
346
+ if (this.isGrowthFinished) {
347
+ if (this.isConverged()) {
348
+ return true;
349
+ }
350
+ if (this.afterGrowthIterations % 10 == 0) {
351
+ this.graphManager.updateBounds();
352
+ this.updateGrid();
353
+ }
354
+ if (CoSEConstants.PURE_INCREMENTAL) this.coolingFactor = FDLayoutConstants.DEFAULT_COOLING_FACTOR_INCREMENTAL / 2 * ((100 - this.afterGrowthIterations) / 100);else this.coolingFactor = FDLayoutConstants.DEFAULT_COOLING_FACTOR_INCREMENTAL * ((100 - this.afterGrowthIterations) / 100);
355
+ this.afterGrowthIterations++;
356
+ }
357
+
358
+ var gridUpdateAllowed = !this.isTreeGrowing && !this.isGrowthFinished;
359
+ var forceToNodeSurroundingUpdate = this.growTreeIterations % 10 == 1 && this.isTreeGrowing || this.afterGrowthIterations % 10 == 1 && this.isGrowthFinished;
360
+
361
+ this.totalDisplacement = 0;
362
+ this.graphManager.updateBounds();
363
+ this.calcSpringForces();
364
+ this.calcRepulsionForces(gridUpdateAllowed, forceToNodeSurroundingUpdate);
365
+ this.calcGravitationalForces();
366
+ this.moveNodes();
367
+ this.animate();
368
+
369
+ return false; // Layout is not ended yet return false
370
+ };
371
+
372
+ CoSELayout.prototype.getPositionsData = function () {
373
+ var allNodes = this.graphManager.getAllNodes();
374
+ var pData = {};
375
+ for (var i = 0; i < allNodes.length; i++) {
376
+ var rect = allNodes[i].rect;
377
+ var id = allNodes[i].id;
378
+ pData[id] = {
379
+ id: id,
380
+ x: rect.getCenterX(),
381
+ y: rect.getCenterY(),
382
+ w: rect.width,
383
+ h: rect.height
384
+ };
385
+ }
386
+
387
+ return pData;
388
+ };
389
+
390
+ CoSELayout.prototype.runSpringEmbedder = function () {
391
+ this.initialAnimationPeriod = 25;
392
+ this.animationPeriod = this.initialAnimationPeriod;
393
+ var layoutEnded = false;
394
+
395
+ // If aminate option is 'during' signal that layout is supposed to start iterating
396
+ if (FDLayoutConstants.ANIMATE === 'during') {
397
+ this.emit('layoutstarted');
398
+ } else {
399
+ // If aminate option is 'during' tick() function will be called on index.js
400
+ while (!layoutEnded) {
401
+ layoutEnded = this.tick();
402
+ }
403
+
404
+ this.graphManager.updateBounds();
405
+ }
406
+ };
407
+
408
+ // overrides moveNodes method in FDLayout
409
+ CoSELayout.prototype.moveNodes = function () {
410
+ var lNodes = this.getAllNodes();
411
+ var node;
412
+
413
+ // calculate displacement for each node
414
+ for (var i = 0; i < lNodes.length; i++) {
415
+ node = lNodes[i];
416
+ node.calculateDisplacement();
417
+ }
418
+
419
+ if (Object.keys(this.constraints).length > 0) {
420
+ this.updateDisplacements();
421
+ }
422
+
423
+ // move each node
424
+ for (var i = 0; i < lNodes.length; i++) {
425
+ node = lNodes[i];
426
+ node.move();
427
+ }
428
+ };
429
+
430
+ // constraint related methods: initConstraintVariables and updateDisplacements
431
+
432
+ // initialize constraint related variables
433
+ CoSELayout.prototype.initConstraintVariables = function () {
434
+ var self = this;
435
+ this.idToNodeMap = new Map();
436
+ this.fixedNodeSet = new Set();
437
+
438
+ var allNodes = this.graphManager.getAllNodes();
439
+
440
+ // fill idToNodeMap
441
+ for (var i = 0; i < allNodes.length; i++) {
442
+ var node = allNodes[i];
443
+ this.idToNodeMap.set(node.id, node);
444
+ }
445
+
446
+ // calculate fixed node weight for given compound node
447
+ var calculateCompoundWeight = function calculateCompoundWeight(compoundNode) {
448
+ var nodes = compoundNode.getChild().getNodes();
449
+ var node;
450
+ var fixedNodeWeight = 0;
451
+ for (var i = 0; i < nodes.length; i++) {
452
+ node = nodes[i];
453
+ if (node.getChild() == null) {
454
+ if (self.fixedNodeSet.has(node.id)) {
455
+ fixedNodeWeight += 100;
456
+ }
457
+ } else {
458
+ fixedNodeWeight += calculateCompoundWeight(node);
459
+ }
460
+ }
461
+ return fixedNodeWeight;
462
+ };
463
+
464
+ if (this.constraints.fixedNodeConstraint) {
465
+ // fill fixedNodeSet
466
+ this.constraints.fixedNodeConstraint.forEach(function (nodeData) {
467
+ self.fixedNodeSet.add(nodeData.nodeId);
468
+ });
469
+
470
+ // assign fixed node weights to compounds if they contain fixed nodes
471
+ var allNodes = this.graphManager.getAllNodes();
472
+ var node;
473
+
474
+ for (var i = 0; i < allNodes.length; i++) {
475
+ node = allNodes[i];
476
+ if (node.getChild() != null) {
477
+ var fixedNodeWeight = calculateCompoundWeight(node);
478
+ if (fixedNodeWeight > 0) {
479
+ node.fixedNodeWeight = fixedNodeWeight;
480
+ }
481
+ }
482
+ }
483
+ }
484
+
485
+ if (this.constraints.relativePlacementConstraint) {
486
+ var nodeToDummyForVerticalAlignment = new Map();
487
+ var nodeToDummyForHorizontalAlignment = new Map();
488
+ this.dummyToNodeForVerticalAlignment = new Map();
489
+ this.dummyToNodeForHorizontalAlignment = new Map();
490
+ this.fixedNodesOnHorizontal = new Set();
491
+ this.fixedNodesOnVertical = new Set();
492
+
493
+ // fill maps and sets
494
+ this.fixedNodeSet.forEach(function (nodeId) {
495
+ self.fixedNodesOnHorizontal.add(nodeId);
496
+ self.fixedNodesOnVertical.add(nodeId);
497
+ });
498
+
499
+ if (this.constraints.alignmentConstraint) {
500
+ if (this.constraints.alignmentConstraint.vertical) {
501
+ var verticalAlignment = this.constraints.alignmentConstraint.vertical;
502
+ for (var i = 0; i < verticalAlignment.length; i++) {
503
+ this.dummyToNodeForVerticalAlignment.set("dummy" + i, []);
504
+ verticalAlignment[i].forEach(function (nodeId) {
505
+ nodeToDummyForVerticalAlignment.set(nodeId, "dummy" + i);
506
+ self.dummyToNodeForVerticalAlignment.get("dummy" + i).push(nodeId);
507
+ if (self.fixedNodeSet.has(nodeId)) {
508
+ self.fixedNodesOnHorizontal.add("dummy" + i);
509
+ }
510
+ });
511
+ }
512
+ }
513
+ if (this.constraints.alignmentConstraint.horizontal) {
514
+ var horizontalAlignment = this.constraints.alignmentConstraint.horizontal;
515
+ for (var i = 0; i < horizontalAlignment.length; i++) {
516
+ this.dummyToNodeForHorizontalAlignment.set("dummy" + i, []);
517
+ horizontalAlignment[i].forEach(function (nodeId) {
518
+ nodeToDummyForHorizontalAlignment.set(nodeId, "dummy" + i);
519
+ self.dummyToNodeForHorizontalAlignment.get("dummy" + i).push(nodeId);
520
+ if (self.fixedNodeSet.has(nodeId)) {
521
+ self.fixedNodesOnVertical.add("dummy" + i);
522
+ }
523
+ });
524
+ }
525
+ }
526
+ }
527
+
528
+ if (CoSEConstants.RELAX_MOVEMENT_ON_CONSTRAINTS) {
529
+
530
+ this.shuffle = function (array) {
531
+ var j, x, i;
532
+ for (i = array.length - 1; i >= 2 * array.length / 3; i--) {
533
+ j = Math.floor(Math.random() * (i + 1));
534
+ x = array[i];
535
+ array[i] = array[j];
536
+ array[j] = x;
537
+ }
538
+ return array;
539
+ };
540
+
541
+ this.nodesInRelativeHorizontal = [];
542
+ this.nodesInRelativeVertical = [];
543
+ this.nodeToRelativeConstraintMapHorizontal = new Map();
544
+ this.nodeToRelativeConstraintMapVertical = new Map();
545
+ this.nodeToTempPositionMapHorizontal = new Map();
546
+ this.nodeToTempPositionMapVertical = new Map();
547
+
548
+ // fill arrays and maps
549
+ this.constraints.relativePlacementConstraint.forEach(function (constraint) {
550
+ if (constraint.left) {
551
+ var nodeIdLeft = nodeToDummyForVerticalAlignment.has(constraint.left) ? nodeToDummyForVerticalAlignment.get(constraint.left) : constraint.left;
552
+ var nodeIdRight = nodeToDummyForVerticalAlignment.has(constraint.right) ? nodeToDummyForVerticalAlignment.get(constraint.right) : constraint.right;
553
+
554
+ if (!self.nodesInRelativeHorizontal.includes(nodeIdLeft)) {
555
+ self.nodesInRelativeHorizontal.push(nodeIdLeft);
556
+ self.nodeToRelativeConstraintMapHorizontal.set(nodeIdLeft, []);
557
+ if (self.dummyToNodeForVerticalAlignment.has(nodeIdLeft)) {
558
+ self.nodeToTempPositionMapHorizontal.set(nodeIdLeft, self.idToNodeMap.get(self.dummyToNodeForVerticalAlignment.get(nodeIdLeft)[0]).getCenterX());
559
+ } else {
560
+ self.nodeToTempPositionMapHorizontal.set(nodeIdLeft, self.idToNodeMap.get(nodeIdLeft).getCenterX());
561
+ }
562
+ }
563
+ if (!self.nodesInRelativeHorizontal.includes(nodeIdRight)) {
564
+ self.nodesInRelativeHorizontal.push(nodeIdRight);
565
+ self.nodeToRelativeConstraintMapHorizontal.set(nodeIdRight, []);
566
+ if (self.dummyToNodeForVerticalAlignment.has(nodeIdRight)) {
567
+ self.nodeToTempPositionMapHorizontal.set(nodeIdRight, self.idToNodeMap.get(self.dummyToNodeForVerticalAlignment.get(nodeIdRight)[0]).getCenterX());
568
+ } else {
569
+ self.nodeToTempPositionMapHorizontal.set(nodeIdRight, self.idToNodeMap.get(nodeIdRight).getCenterX());
570
+ }
571
+ }
572
+
573
+ self.nodeToRelativeConstraintMapHorizontal.get(nodeIdLeft).push({ right: nodeIdRight, gap: constraint.gap });
574
+ self.nodeToRelativeConstraintMapHorizontal.get(nodeIdRight).push({ left: nodeIdLeft, gap: constraint.gap });
575
+ } else {
576
+ var nodeIdTop = nodeToDummyForHorizontalAlignment.has(constraint.top) ? nodeToDummyForHorizontalAlignment.get(constraint.top) : constraint.top;
577
+ var nodeIdBottom = nodeToDummyForHorizontalAlignment.has(constraint.bottom) ? nodeToDummyForHorizontalAlignment.get(constraint.bottom) : constraint.bottom;
578
+
579
+ if (!self.nodesInRelativeVertical.includes(nodeIdTop)) {
580
+ self.nodesInRelativeVertical.push(nodeIdTop);
581
+ self.nodeToRelativeConstraintMapVertical.set(nodeIdTop, []);
582
+ if (self.dummyToNodeForHorizontalAlignment.has(nodeIdTop)) {
583
+ self.nodeToTempPositionMapVertical.set(nodeIdTop, self.idToNodeMap.get(self.dummyToNodeForHorizontalAlignment.get(nodeIdTop)[0]).getCenterY());
584
+ } else {
585
+ self.nodeToTempPositionMapVertical.set(nodeIdTop, self.idToNodeMap.get(nodeIdTop).getCenterY());
586
+ }
587
+ }
588
+ if (!self.nodesInRelativeVertical.includes(nodeIdBottom)) {
589
+ self.nodesInRelativeVertical.push(nodeIdBottom);
590
+ self.nodeToRelativeConstraintMapVertical.set(nodeIdBottom, []);
591
+ if (self.dummyToNodeForHorizontalAlignment.has(nodeIdBottom)) {
592
+ self.nodeToTempPositionMapVertical.set(nodeIdBottom, self.idToNodeMap.get(self.dummyToNodeForHorizontalAlignment.get(nodeIdBottom)[0]).getCenterY());
593
+ } else {
594
+ self.nodeToTempPositionMapVertical.set(nodeIdBottom, self.idToNodeMap.get(nodeIdBottom).getCenterY());
595
+ }
596
+ }
597
+ self.nodeToRelativeConstraintMapVertical.get(nodeIdTop).push({ bottom: nodeIdBottom, gap: constraint.gap });
598
+ self.nodeToRelativeConstraintMapVertical.get(nodeIdBottom).push({ top: nodeIdTop, gap: constraint.gap });
599
+ }
600
+ });
601
+ } else {
602
+ var subGraphOnHorizontal = new Map(); // subgraph from vertical RP constraints
603
+ var subGraphOnVertical = new Map(); // subgraph from vertical RP constraints
604
+
605
+ // construct subgraphs from relative placement constraints
606
+ this.constraints.relativePlacementConstraint.forEach(function (constraint) {
607
+ if (constraint.left) {
608
+ var left = nodeToDummyForVerticalAlignment.has(constraint.left) ? nodeToDummyForVerticalAlignment.get(constraint.left) : constraint.left;
609
+ var right = nodeToDummyForVerticalAlignment.has(constraint.right) ? nodeToDummyForVerticalAlignment.get(constraint.right) : constraint.right;
610
+ if (subGraphOnHorizontal.has(left)) {
611
+ subGraphOnHorizontal.get(left).push(right);
612
+ } else {
613
+ subGraphOnHorizontal.set(left, [right]);
614
+ }
615
+ if (subGraphOnHorizontal.has(right)) {
616
+ subGraphOnHorizontal.get(right).push(left);
617
+ } else {
618
+ subGraphOnHorizontal.set(right, [left]);
619
+ }
620
+ } else {
621
+ var top = nodeToDummyForHorizontalAlignment.has(constraint.top) ? nodeToDummyForHorizontalAlignment.get(constraint.top) : constraint.top;
622
+ var bottom = nodeToDummyForHorizontalAlignment.has(constraint.bottom) ? nodeToDummyForHorizontalAlignment.get(constraint.bottom) : constraint.bottom;
623
+ if (subGraphOnVertical.has(top)) {
624
+ subGraphOnVertical.get(top).push(bottom);
625
+ } else {
626
+ subGraphOnVertical.set(top, [bottom]);
627
+ }
628
+ if (subGraphOnVertical.has(bottom)) {
629
+ subGraphOnVertical.get(bottom).push(top);
630
+ } else {
631
+ subGraphOnVertical.set(bottom, [top]);
632
+ }
633
+ }
634
+ });
635
+
636
+ // function to construct components from a given graph
637
+ // also returns an array that keeps whether each component contains fixed node
638
+ var constructComponents = function constructComponents(graph, fixedNodes) {
639
+ var components = [];
640
+ var isFixed = [];
641
+ var queue = new LinkedList();
642
+ var visited = new Set();
643
+ var count = 0;
644
+
645
+ graph.forEach(function (value, key) {
646
+ if (!visited.has(key)) {
647
+ components[count] = [];
648
+ isFixed[count] = false;
649
+ var currentNode = key;
650
+ queue.push(currentNode);
651
+ visited.add(currentNode);
652
+ components[count].push(currentNode);
653
+
654
+ while (queue.length != 0) {
655
+ currentNode = queue.shift();
656
+ if (fixedNodes.has(currentNode)) {
657
+ isFixed[count] = true;
658
+ }
659
+ var neighbors = graph.get(currentNode);
660
+ neighbors.forEach(function (neighbor) {
661
+ if (!visited.has(neighbor)) {
662
+ queue.push(neighbor);
663
+ visited.add(neighbor);
664
+ components[count].push(neighbor);
665
+ }
666
+ });
667
+ }
668
+ count++;
669
+ }
670
+ });
671
+
672
+ return { components: components, isFixed: isFixed };
673
+ };
674
+
675
+ var resultOnHorizontal = constructComponents(subGraphOnHorizontal, self.fixedNodesOnHorizontal);
676
+ this.componentsOnHorizontal = resultOnHorizontal.components;
677
+ this.fixedComponentsOnHorizontal = resultOnHorizontal.isFixed;
678
+ var resultOnVertical = constructComponents(subGraphOnVertical, self.fixedNodesOnVertical);
679
+ this.componentsOnVertical = resultOnVertical.components;
680
+ this.fixedComponentsOnVertical = resultOnVertical.isFixed;
681
+ }
682
+ }
683
+ };
684
+
685
+ // updates node displacements based on constraints
686
+ CoSELayout.prototype.updateDisplacements = function () {
687
+ var self = this;
688
+ if (this.constraints.fixedNodeConstraint) {
689
+ this.constraints.fixedNodeConstraint.forEach(function (nodeData) {
690
+ var fixedNode = self.idToNodeMap.get(nodeData.nodeId);
691
+ fixedNode.displacementX = 0;
692
+ fixedNode.displacementY = 0;
693
+ });
694
+ }
695
+
696
+ if (this.constraints.alignmentConstraint) {
697
+ if (this.constraints.alignmentConstraint.vertical) {
698
+ var allVerticalAlignments = this.constraints.alignmentConstraint.vertical;
699
+ for (var i = 0; i < allVerticalAlignments.length; i++) {
700
+ var totalDisplacementX = 0;
701
+ for (var j = 0; j < allVerticalAlignments[i].length; j++) {
702
+ if (this.fixedNodeSet.has(allVerticalAlignments[i][j])) {
703
+ totalDisplacementX = 0;
704
+ break;
705
+ }
706
+ totalDisplacementX += this.idToNodeMap.get(allVerticalAlignments[i][j]).displacementX;
707
+ }
708
+ var averageDisplacementX = totalDisplacementX / allVerticalAlignments[i].length;
709
+ for (var j = 0; j < allVerticalAlignments[i].length; j++) {
710
+ this.idToNodeMap.get(allVerticalAlignments[i][j]).displacementX = averageDisplacementX;
711
+ }
712
+ }
713
+ }
714
+ if (this.constraints.alignmentConstraint.horizontal) {
715
+ var allHorizontalAlignments = this.constraints.alignmentConstraint.horizontal;
716
+ for (var i = 0; i < allHorizontalAlignments.length; i++) {
717
+ var totalDisplacementY = 0;
718
+ for (var j = 0; j < allHorizontalAlignments[i].length; j++) {
719
+ if (this.fixedNodeSet.has(allHorizontalAlignments[i][j])) {
720
+ totalDisplacementY = 0;
721
+ break;
722
+ }
723
+ totalDisplacementY += this.idToNodeMap.get(allHorizontalAlignments[i][j]).displacementY;
724
+ }
725
+ var averageDisplacementY = totalDisplacementY / allHorizontalAlignments[i].length;
726
+ for (var j = 0; j < allHorizontalAlignments[i].length; j++) {
727
+ this.idToNodeMap.get(allHorizontalAlignments[i][j]).displacementY = averageDisplacementY;
728
+ }
729
+ }
730
+ }
731
+ }
732
+
733
+ if (this.constraints.relativePlacementConstraint) {
734
+
735
+ if (CoSEConstants.RELAX_MOVEMENT_ON_CONSTRAINTS) {
736
+ // shuffle array to randomize node processing order
737
+ if (this.totalIterations % 10 == 0) {
738
+ this.shuffle(this.nodesInRelativeHorizontal);
739
+ this.shuffle(this.nodesInRelativeVertical);
740
+ }
741
+
742
+ this.nodesInRelativeHorizontal.forEach(function (nodeId) {
743
+ if (!self.fixedNodesOnHorizontal.has(nodeId)) {
744
+ var displacement = 0;
745
+ if (self.dummyToNodeForVerticalAlignment.has(nodeId)) {
746
+ displacement = self.idToNodeMap.get(self.dummyToNodeForVerticalAlignment.get(nodeId)[0]).displacementX;
747
+ } else {
748
+ displacement = self.idToNodeMap.get(nodeId).displacementX;
749
+ }
750
+ self.nodeToRelativeConstraintMapHorizontal.get(nodeId).forEach(function (constraint) {
751
+ if (constraint.right) {
752
+ var diff = self.nodeToTempPositionMapHorizontal.get(constraint.right) - self.nodeToTempPositionMapHorizontal.get(nodeId) - displacement;
753
+ if (diff < constraint.gap) {
754
+ displacement -= constraint.gap - diff;
755
+ }
756
+ } else {
757
+ var diff = self.nodeToTempPositionMapHorizontal.get(nodeId) - self.nodeToTempPositionMapHorizontal.get(constraint.left) + displacement;
758
+ if (diff < constraint.gap) {
759
+ displacement += constraint.gap - diff;
760
+ }
761
+ }
762
+ });
763
+ self.nodeToTempPositionMapHorizontal.set(nodeId, self.nodeToTempPositionMapHorizontal.get(nodeId) + displacement);
764
+ if (self.dummyToNodeForVerticalAlignment.has(nodeId)) {
765
+ self.dummyToNodeForVerticalAlignment.get(nodeId).forEach(function (nodeId) {
766
+ self.idToNodeMap.get(nodeId).displacementX = displacement;
767
+ });
768
+ } else {
769
+ self.idToNodeMap.get(nodeId).displacementX = displacement;
770
+ }
771
+ }
772
+ });
773
+
774
+ this.nodesInRelativeVertical.forEach(function (nodeId) {
775
+ if (!self.fixedNodesOnHorizontal.has(nodeId)) {
776
+ var displacement = 0;
777
+ if (self.dummyToNodeForHorizontalAlignment.has(nodeId)) {
778
+ displacement = self.idToNodeMap.get(self.dummyToNodeForHorizontalAlignment.get(nodeId)[0]).displacementY;
779
+ } else {
780
+ displacement = self.idToNodeMap.get(nodeId).displacementY;
781
+ }
782
+ self.nodeToRelativeConstraintMapVertical.get(nodeId).forEach(function (constraint) {
783
+ if (constraint.bottom) {
784
+ var diff = self.nodeToTempPositionMapVertical.get(constraint.bottom) - self.nodeToTempPositionMapVertical.get(nodeId) - displacement;
785
+ if (diff < constraint.gap) {
786
+ displacement -= constraint.gap - diff;
787
+ }
788
+ } else {
789
+ var diff = self.nodeToTempPositionMapVertical.get(nodeId) - self.nodeToTempPositionMapVertical.get(constraint.top) + displacement;
790
+ if (diff < constraint.gap) {
791
+ displacement += constraint.gap - diff;
792
+ }
793
+ }
794
+ });
795
+ self.nodeToTempPositionMapVertical.set(nodeId, self.nodeToTempPositionMapVertical.get(nodeId) + displacement);
796
+ if (self.dummyToNodeForHorizontalAlignment.has(nodeId)) {
797
+ self.dummyToNodeForHorizontalAlignment.get(nodeId).forEach(function (nodeId) {
798
+ self.idToNodeMap.get(nodeId).displacementY = displacement;
799
+ });
800
+ } else {
801
+ self.idToNodeMap.get(nodeId).displacementY = displacement;
802
+ }
803
+ }
804
+ });
805
+ } else {
806
+ for (var i = 0; i < this.componentsOnHorizontal.length; i++) {
807
+ var component = this.componentsOnHorizontal[i];
808
+ if (this.fixedComponentsOnHorizontal[i]) {
809
+ for (var j = 0; j < component.length; j++) {
810
+ if (this.dummyToNodeForVerticalAlignment.has(component[j])) {
811
+ this.dummyToNodeForVerticalAlignment.get(component[j]).forEach(function (nodeId) {
812
+ self.idToNodeMap.get(nodeId).displacementX = 0;
813
+ });
814
+ } else {
815
+ this.idToNodeMap.get(component[j]).displacementX = 0;
816
+ }
817
+ }
818
+ } else {
819
+ var sum = 0;
820
+ var count = 0;
821
+ for (var j = 0; j < component.length; j++) {
822
+ if (this.dummyToNodeForVerticalAlignment.has(component[j])) {
823
+ var actualNodes = this.dummyToNodeForVerticalAlignment.get(component[j]);
824
+ sum += actualNodes.length * this.idToNodeMap.get(actualNodes[0]).displacementX;
825
+ count += actualNodes.length;
826
+ } else {
827
+ sum += this.idToNodeMap.get(component[j]).displacementX;
828
+ count++;
829
+ }
830
+ }
831
+ var averageDisplacement = sum / count;
832
+ for (var j = 0; j < component.length; j++) {
833
+ if (this.dummyToNodeForVerticalAlignment.has(component[j])) {
834
+ this.dummyToNodeForVerticalAlignment.get(component[j]).forEach(function (nodeId) {
835
+ self.idToNodeMap.get(nodeId).displacementX = averageDisplacement;
836
+ });
837
+ } else {
838
+ this.idToNodeMap.get(component[j]).displacementX = averageDisplacement;
839
+ }
840
+ }
841
+ }
842
+ }
843
+
844
+ for (var i = 0; i < this.componentsOnVertical.length; i++) {
845
+ var component = this.componentsOnVertical[i];
846
+ if (this.fixedComponentsOnVertical[i]) {
847
+ for (var j = 0; j < component.length; j++) {
848
+ if (this.dummyToNodeForHorizontalAlignment.has(component[j])) {
849
+ this.dummyToNodeForHorizontalAlignment.get(component[j]).forEach(function (nodeId) {
850
+ self.idToNodeMap.get(nodeId).displacementY = 0;
851
+ });
852
+ } else {
853
+ this.idToNodeMap.get(component[j]).displacementY = 0;
854
+ }
855
+ }
856
+ } else {
857
+ var sum = 0;
858
+ var count = 0;
859
+ for (var j = 0; j < component.length; j++) {
860
+ if (this.dummyToNodeForHorizontalAlignment.has(component[j])) {
861
+ var actualNodes = this.dummyToNodeForHorizontalAlignment.get(component[j]);
862
+ sum += actualNodes.length * this.idToNodeMap.get(actualNodes[0]).displacementY;
863
+ count += actualNodes.length;
864
+ } else {
865
+ sum += this.idToNodeMap.get(component[j]).displacementY;
866
+ count++;
867
+ }
868
+ }
869
+ var averageDisplacement = sum / count;
870
+ for (var j = 0; j < component.length; j++) {
871
+ if (this.dummyToNodeForHorizontalAlignment.has(component[j])) {
872
+ this.dummyToNodeForHorizontalAlignment.get(component[j]).forEach(function (nodeId) {
873
+ self.idToNodeMap.get(nodeId).displacementY = averageDisplacement;
874
+ });
875
+ } else {
876
+ this.idToNodeMap.get(component[j]).displacementY = averageDisplacement;
877
+ }
878
+ }
879
+ }
880
+ }
881
+ }
882
+ }
883
+ };
884
+
885
+ CoSELayout.prototype.calculateNodesToApplyGravitationTo = function () {
886
+ var nodeList = [];
887
+ var graph;
888
+
889
+ var graphs = this.graphManager.getGraphs();
890
+ var size = graphs.length;
891
+ var i;
892
+ for (i = 0; i < size; i++) {
893
+ graph = graphs[i];
894
+
895
+ graph.updateConnected();
896
+
897
+ if (!graph.isConnected) {
898
+ nodeList = nodeList.concat(graph.getNodes());
899
+ }
900
+ }
901
+
902
+ return nodeList;
903
+ };
904
+
905
+ CoSELayout.prototype.createBendpoints = function () {
906
+ var edges = [];
907
+ edges = edges.concat(this.graphManager.getAllEdges());
908
+ var visited = new Set();
909
+ var i;
910
+ for (i = 0; i < edges.length; i++) {
911
+ var edge = edges[i];
912
+
913
+ if (!visited.has(edge)) {
914
+ var source = edge.getSource();
915
+ var target = edge.getTarget();
916
+
917
+ if (source == target) {
918
+ edge.getBendpoints().push(new PointD());
919
+ edge.getBendpoints().push(new PointD());
920
+ this.createDummyNodesForBendpoints(edge);
921
+ visited.add(edge);
922
+ } else {
923
+ var edgeList = [];
924
+
925
+ edgeList = edgeList.concat(source.getEdgeListToNode(target));
926
+ edgeList = edgeList.concat(target.getEdgeListToNode(source));
927
+
928
+ if (!visited.has(edgeList[0])) {
929
+ if (edgeList.length > 1) {
930
+ var k;
931
+ for (k = 0; k < edgeList.length; k++) {
932
+ var multiEdge = edgeList[k];
933
+ multiEdge.getBendpoints().push(new PointD());
934
+ this.createDummyNodesForBendpoints(multiEdge);
935
+ }
936
+ }
937
+ edgeList.forEach(function (edge) {
938
+ visited.add(edge);
939
+ });
940
+ }
941
+ }
942
+ }
943
+
944
+ if (visited.size == edges.length) {
945
+ break;
946
+ }
947
+ }
948
+ };
949
+
950
+ CoSELayout.prototype.positionNodesRadially = function (forest) {
951
+ // We tile the trees to a grid row by row; first tree starts at (0,0)
952
+ var currentStartingPoint = new Point(0, 0);
953
+ var numberOfColumns = Math.ceil(Math.sqrt(forest.length));
954
+ var height = 0;
955
+ var currentY = 0;
956
+ var currentX = 0;
957
+ var point = new PointD(0, 0);
958
+
959
+ for (var i = 0; i < forest.length; i++) {
960
+ if (i % numberOfColumns == 0) {
961
+ // Start of a new row, make the x coordinate 0, increment the
962
+ // y coordinate with the max height of the previous row
963
+ currentX = 0;
964
+ currentY = height;
965
+
966
+ if (i != 0) {
967
+ currentY += CoSEConstants.DEFAULT_COMPONENT_SEPERATION;
968
+ }
969
+
970
+ height = 0;
971
+ }
972
+
973
+ var tree = forest[i];
974
+
975
+ // Find the center of the tree
976
+ var centerNode = Layout.findCenterOfTree(tree);
977
+
978
+ // Set the staring point of the next tree
979
+ currentStartingPoint.x = currentX;
980
+ currentStartingPoint.y = currentY;
981
+
982
+ // Do a radial layout starting with the center
983
+ point = CoSELayout.radialLayout(tree, centerNode, currentStartingPoint);
984
+
985
+ if (point.y > height) {
986
+ height = Math.floor(point.y);
987
+ }
988
+
989
+ currentX = Math.floor(point.x + CoSEConstants.DEFAULT_COMPONENT_SEPERATION);
990
+ }
991
+
992
+ this.transform(new PointD(LayoutConstants.WORLD_CENTER_X - point.x / 2, LayoutConstants.WORLD_CENTER_Y - point.y / 2));
993
+ };
994
+
995
+ CoSELayout.radialLayout = function (tree, centerNode, startingPoint) {
996
+ var radialSep = Math.max(this.maxDiagonalInTree(tree), CoSEConstants.DEFAULT_RADIAL_SEPARATION);
997
+ CoSELayout.branchRadialLayout(centerNode, null, 0, 359, 0, radialSep);
998
+ var bounds = LGraph.calculateBounds(tree);
999
+
1000
+ var transform = new Transform();
1001
+ transform.setDeviceOrgX(bounds.getMinX());
1002
+ transform.setDeviceOrgY(bounds.getMinY());
1003
+ transform.setWorldOrgX(startingPoint.x);
1004
+ transform.setWorldOrgY(startingPoint.y);
1005
+
1006
+ for (var i = 0; i < tree.length; i++) {
1007
+ var node = tree[i];
1008
+ node.transform(transform);
1009
+ }
1010
+
1011
+ var bottomRight = new PointD(bounds.getMaxX(), bounds.getMaxY());
1012
+
1013
+ return transform.inverseTransformPoint(bottomRight);
1014
+ };
1015
+
1016
+ CoSELayout.branchRadialLayout = function (node, parentOfNode, startAngle, endAngle, distance, radialSeparation) {
1017
+ // First, position this node by finding its angle.
1018
+ var halfInterval = (endAngle - startAngle + 1) / 2;
1019
+
1020
+ if (halfInterval < 0) {
1021
+ halfInterval += 180;
1022
+ }
1023
+
1024
+ var nodeAngle = (halfInterval + startAngle) % 360;
1025
+ var teta = nodeAngle * IGeometry.TWO_PI / 360;
1026
+
1027
+ // Make polar to java cordinate conversion.
1028
+ var cos_teta = Math.cos(teta);
1029
+ var x_ = distance * Math.cos(teta);
1030
+ var y_ = distance * Math.sin(teta);
1031
+
1032
+ node.setCenter(x_, y_);
1033
+
1034
+ // Traverse all neighbors of this node and recursively call this
1035
+ // function.
1036
+ var neighborEdges = [];
1037
+ neighborEdges = neighborEdges.concat(node.getEdges());
1038
+ var childCount = neighborEdges.length;
1039
+
1040
+ if (parentOfNode != null) {
1041
+ childCount--;
1042
+ }
1043
+
1044
+ var branchCount = 0;
1045
+
1046
+ var incEdgesCount = neighborEdges.length;
1047
+ var startIndex;
1048
+
1049
+ var edges = node.getEdgesBetween(parentOfNode);
1050
+
1051
+ // If there are multiple edges, prune them until there remains only one
1052
+ // edge.
1053
+ while (edges.length > 1) {
1054
+ //neighborEdges.remove(edges.remove(0));
1055
+ var temp = edges[0];
1056
+ edges.splice(0, 1);
1057
+ var index = neighborEdges.indexOf(temp);
1058
+ if (index >= 0) {
1059
+ neighborEdges.splice(index, 1);
1060
+ }
1061
+ incEdgesCount--;
1062
+ childCount--;
1063
+ }
1064
+
1065
+ if (parentOfNode != null) {
1066
+ //assert edges.length == 1;
1067
+ startIndex = (neighborEdges.indexOf(edges[0]) + 1) % incEdgesCount;
1068
+ } else {
1069
+ startIndex = 0;
1070
+ }
1071
+
1072
+ var stepAngle = Math.abs(endAngle - startAngle) / childCount;
1073
+
1074
+ for (var i = startIndex; branchCount != childCount; i = ++i % incEdgesCount) {
1075
+ var currentNeighbor = neighborEdges[i].getOtherEnd(node);
1076
+
1077
+ // Don't back traverse to root node in current tree.
1078
+ if (currentNeighbor == parentOfNode) {
1079
+ continue;
1080
+ }
1081
+
1082
+ var childStartAngle = (startAngle + branchCount * stepAngle) % 360;
1083
+ var childEndAngle = (childStartAngle + stepAngle) % 360;
1084
+
1085
+ CoSELayout.branchRadialLayout(currentNeighbor, node, childStartAngle, childEndAngle, distance + radialSeparation, radialSeparation);
1086
+
1087
+ branchCount++;
1088
+ }
1089
+ };
1090
+
1091
+ CoSELayout.maxDiagonalInTree = function (tree) {
1092
+ var maxDiagonal = Integer.MIN_VALUE;
1093
+
1094
+ for (var i = 0; i < tree.length; i++) {
1095
+ var node = tree[i];
1096
+ var diagonal = node.getDiagonal();
1097
+
1098
+ if (diagonal > maxDiagonal) {
1099
+ maxDiagonal = diagonal;
1100
+ }
1101
+ }
1102
+
1103
+ return maxDiagonal;
1104
+ };
1105
+
1106
+ CoSELayout.prototype.calcRepulsionRange = function () {
1107
+ // formula is 2 x (level + 1) x idealEdgeLength
1108
+ return 2 * (this.level + 1) * this.idealEdgeLength;
1109
+ };
1110
+
1111
+ // Tiling methods
1112
+
1113
+ // Group zero degree members whose parents are not to be tiled, create dummy parents where needed and fill memberGroups by their dummp parent id's
1114
+ CoSELayout.prototype.groupZeroDegreeMembers = function () {
1115
+ var self = this;
1116
+ // array of [parent_id x oneDegreeNode_id]
1117
+ var tempMemberGroups = {}; // A temporary map of parent node and its zero degree members
1118
+ this.memberGroups = {}; // A map of dummy parent node and its zero degree members whose parents are not to be tiled
1119
+ this.idToDummyNode = {}; // A map of id to dummy node
1120
+
1121
+ var zeroDegree = []; // List of zero degree nodes whose parents are not to be tiled
1122
+ var allNodes = this.graphManager.getAllNodes();
1123
+
1124
+ // Fill zero degree list
1125
+ for (var i = 0; i < allNodes.length; i++) {
1126
+ var node = allNodes[i];
1127
+ var parent = node.getParent();
1128
+ // If a node has zero degree and its parent is not to be tiled if exists add that node to zeroDegres list
1129
+ if (this.getNodeDegreeWithChildren(node) === 0 && (parent.id == undefined || !this.getToBeTiled(parent))) {
1130
+ zeroDegree.push(node);
1131
+ }
1132
+ }
1133
+
1134
+ // Create a map of parent node and its zero degree members
1135
+ for (var i = 0; i < zeroDegree.length; i++) {
1136
+ var node = zeroDegree[i]; // Zero degree node itself
1137
+ var p_id = node.getParent().id; // Parent id
1138
+
1139
+ if (typeof tempMemberGroups[p_id] === "undefined") tempMemberGroups[p_id] = [];
1140
+
1141
+ tempMemberGroups[p_id] = tempMemberGroups[p_id].concat(node); // Push node to the list belongs to its parent in tempMemberGroups
1142
+ }
1143
+
1144
+ // If there are at least two nodes at a level, create a dummy compound for them
1145
+ Object.keys(tempMemberGroups).forEach(function (p_id) {
1146
+ if (tempMemberGroups[p_id].length > 1) {
1147
+ var dummyCompoundId = "DummyCompound_" + p_id; // The id of dummy compound which will be created soon
1148
+ self.memberGroups[dummyCompoundId] = tempMemberGroups[p_id]; // Add dummy compound to memberGroups
1149
+
1150
+ var parent = tempMemberGroups[p_id][0].getParent(); // The parent of zero degree nodes will be the parent of new dummy compound
1151
+
1152
+ // Create a dummy compound with calculated id
1153
+ var dummyCompound = new CoSENode(self.graphManager);
1154
+ dummyCompound.id = dummyCompoundId;
1155
+ dummyCompound.paddingLeft = parent.paddingLeft || 0;
1156
+ dummyCompound.paddingRight = parent.paddingRight || 0;
1157
+ dummyCompound.paddingBottom = parent.paddingBottom || 0;
1158
+ dummyCompound.paddingTop = parent.paddingTop || 0;
1159
+
1160
+ self.idToDummyNode[dummyCompoundId] = dummyCompound;
1161
+
1162
+ var dummyParentGraph = self.getGraphManager().add(self.newGraph(), dummyCompound);
1163
+ var parentGraph = parent.getChild();
1164
+
1165
+ // Add dummy compound to parent the graph
1166
+ parentGraph.add(dummyCompound);
1167
+
1168
+ // For each zero degree node in this level remove it from its parent graph and add it to the graph of dummy parent
1169
+ for (var i = 0; i < tempMemberGroups[p_id].length; i++) {
1170
+ var node = tempMemberGroups[p_id][i];
1171
+
1172
+ parentGraph.remove(node);
1173
+ dummyParentGraph.add(node);
1174
+ }
1175
+ }
1176
+ });
1177
+ };
1178
+
1179
+ CoSELayout.prototype.clearCompounds = function () {
1180
+ var childGraphMap = {};
1181
+ var idToNode = {};
1182
+
1183
+ // Get compound ordering by finding the inner one first
1184
+ this.performDFSOnCompounds();
1185
+
1186
+ for (var i = 0; i < this.compoundOrder.length; i++) {
1187
+
1188
+ idToNode[this.compoundOrder[i].id] = this.compoundOrder[i];
1189
+ childGraphMap[this.compoundOrder[i].id] = [].concat(this.compoundOrder[i].getChild().getNodes());
1190
+
1191
+ // Remove children of compounds
1192
+ this.graphManager.remove(this.compoundOrder[i].getChild());
1193
+ this.compoundOrder[i].child = null;
1194
+ }
1195
+
1196
+ this.graphManager.resetAllNodes();
1197
+
1198
+ // Tile the removed children
1199
+ this.tileCompoundMembers(childGraphMap, idToNode);
1200
+ };
1201
+
1202
+ CoSELayout.prototype.clearZeroDegreeMembers = function () {
1203
+ var self = this;
1204
+ var tiledZeroDegreePack = this.tiledZeroDegreePack = [];
1205
+
1206
+ Object.keys(this.memberGroups).forEach(function (id) {
1207
+ var compoundNode = self.idToDummyNode[id]; // Get the dummy compound
1208
+
1209
+ tiledZeroDegreePack[id] = self.tileNodes(self.memberGroups[id], compoundNode.paddingLeft + compoundNode.paddingRight);
1210
+
1211
+ // Set the width and height of the dummy compound as calculated
1212
+ compoundNode.rect.width = tiledZeroDegreePack[id].width;
1213
+ compoundNode.rect.height = tiledZeroDegreePack[id].height;
1214
+ compoundNode.setCenter(tiledZeroDegreePack[id].centerX, tiledZeroDegreePack[id].centerY);
1215
+
1216
+ // compound left and top margings for labels
1217
+ // when node labels are included, these values may be set to different values below and are used in tilingPostLayout,
1218
+ // otherwise they stay as zero
1219
+ compoundNode.labelMarginLeft = 0;
1220
+ compoundNode.labelMarginTop = 0;
1221
+
1222
+ // Update compound bounds considering its label properties and set label margins for left and top
1223
+ if (CoSEConstants.NODE_DIMENSIONS_INCLUDE_LABELS) {
1224
+
1225
+ var width = compoundNode.rect.width;
1226
+ var height = compoundNode.rect.height;
1227
+
1228
+ if (compoundNode.labelWidth) {
1229
+ if (compoundNode.labelPosHorizontal == "left") {
1230
+ compoundNode.rect.x -= compoundNode.labelWidth;
1231
+ compoundNode.setWidth(width + compoundNode.labelWidth);
1232
+ compoundNode.labelMarginLeft = compoundNode.labelWidth;
1233
+ } else if (compoundNode.labelPosHorizontal == "center" && compoundNode.labelWidth > width) {
1234
+ compoundNode.rect.x -= (compoundNode.labelWidth - width) / 2;
1235
+ compoundNode.setWidth(compoundNode.labelWidth);
1236
+ compoundNode.labelMarginLeft = (compoundNode.labelWidth - width) / 2;
1237
+ } else if (compoundNode.labelPosHorizontal == "right") {
1238
+ compoundNode.setWidth(width + compoundNode.labelWidth);
1239
+ }
1240
+ }
1241
+
1242
+ if (compoundNode.labelHeight) {
1243
+ if (compoundNode.labelPosVertical == "top") {
1244
+ compoundNode.rect.y -= compoundNode.labelHeight;
1245
+ compoundNode.setHeight(height + compoundNode.labelHeight);
1246
+ compoundNode.labelMarginTop = compoundNode.labelHeight;
1247
+ } else if (compoundNode.labelPosVertical == "center" && compoundNode.labelHeight > height) {
1248
+ compoundNode.rect.y -= (compoundNode.labelHeight - height) / 2;
1249
+ compoundNode.setHeight(compoundNode.labelHeight);
1250
+ compoundNode.labelMarginTop = (compoundNode.labelHeight - height) / 2;
1251
+ } else if (compoundNode.labelPosVertical == "bottom") {
1252
+ compoundNode.setHeight(height + compoundNode.labelHeight);
1253
+ }
1254
+ }
1255
+ }
1256
+ });
1257
+ };
1258
+
1259
+ CoSELayout.prototype.repopulateCompounds = function () {
1260
+ for (var i = this.compoundOrder.length - 1; i >= 0; i--) {
1261
+ var lCompoundNode = this.compoundOrder[i];
1262
+ var id = lCompoundNode.id;
1263
+ var horizontalMargin = lCompoundNode.paddingLeft;
1264
+ var verticalMargin = lCompoundNode.paddingTop;
1265
+ var labelMarginLeft = lCompoundNode.labelMarginLeft;
1266
+ var labelMarginTop = lCompoundNode.labelMarginTop;
1267
+
1268
+ this.adjustLocations(this.tiledMemberPack[id], lCompoundNode.rect.x, lCompoundNode.rect.y, horizontalMargin, verticalMargin, labelMarginLeft, labelMarginTop);
1269
+ }
1270
+ };
1271
+
1272
+ CoSELayout.prototype.repopulateZeroDegreeMembers = function () {
1273
+ var self = this;
1274
+ var tiledPack = this.tiledZeroDegreePack;
1275
+
1276
+ Object.keys(tiledPack).forEach(function (id) {
1277
+ var compoundNode = self.idToDummyNode[id]; // Get the dummy compound by its id
1278
+ var horizontalMargin = compoundNode.paddingLeft;
1279
+ var verticalMargin = compoundNode.paddingTop;
1280
+ var labelMarginLeft = compoundNode.labelMarginLeft;
1281
+ var labelMarginTop = compoundNode.labelMarginTop;
1282
+
1283
+ // Adjust the positions of nodes wrt its compound
1284
+ self.adjustLocations(tiledPack[id], compoundNode.rect.x, compoundNode.rect.y, horizontalMargin, verticalMargin, labelMarginLeft, labelMarginTop);
1285
+ });
1286
+ };
1287
+
1288
+ CoSELayout.prototype.getToBeTiled = function (node) {
1289
+ var id = node.id;
1290
+ //firstly check the previous results
1291
+ if (this.toBeTiled[id] != null) {
1292
+ return this.toBeTiled[id];
1293
+ }
1294
+
1295
+ //only compound nodes are to be tiled
1296
+ var childGraph = node.getChild();
1297
+ if (childGraph == null) {
1298
+ this.toBeTiled[id] = false;
1299
+ return false;
1300
+ }
1301
+
1302
+ var children = childGraph.getNodes(); // Get the children nodes
1303
+
1304
+ //a compound node is not to be tiled if all of its compound children are not to be tiled
1305
+ for (var i = 0; i < children.length; i++) {
1306
+ var theChild = children[i];
1307
+
1308
+ if (this.getNodeDegree(theChild) > 0) {
1309
+ this.toBeTiled[id] = false;
1310
+ return false;
1311
+ }
1312
+
1313
+ //pass the children not having the compound structure
1314
+ if (theChild.getChild() == null) {
1315
+ this.toBeTiled[theChild.id] = false;
1316
+ continue;
1317
+ }
1318
+
1319
+ if (!this.getToBeTiled(theChild)) {
1320
+ this.toBeTiled[id] = false;
1321
+ return false;
1322
+ }
1323
+ }
1324
+ this.toBeTiled[id] = true;
1325
+ return true;
1326
+ };
1327
+
1328
+ // Get degree of a node depending of its edges and independent of its children
1329
+ CoSELayout.prototype.getNodeDegree = function (node) {
1330
+ var id = node.id;
1331
+ var edges = node.getEdges();
1332
+ var degree = 0;
1333
+
1334
+ // For the edges connected
1335
+ for (var i = 0; i < edges.length; i++) {
1336
+ var edge = edges[i];
1337
+ if (edge.getSource().id !== edge.getTarget().id) {
1338
+ degree = degree + 1;
1339
+ }
1340
+ }
1341
+ return degree;
1342
+ };
1343
+
1344
+ // Get degree of a node with its children
1345
+ CoSELayout.prototype.getNodeDegreeWithChildren = function (node) {
1346
+ var degree = this.getNodeDegree(node);
1347
+ if (node.getChild() == null) {
1348
+ return degree;
1349
+ }
1350
+ var children = node.getChild().getNodes();
1351
+ for (var i = 0; i < children.length; i++) {
1352
+ var child = children[i];
1353
+ degree += this.getNodeDegreeWithChildren(child);
1354
+ }
1355
+ return degree;
1356
+ };
1357
+
1358
+ CoSELayout.prototype.performDFSOnCompounds = function () {
1359
+ this.compoundOrder = [];
1360
+ this.fillCompexOrderByDFS(this.graphManager.getRoot().getNodes());
1361
+ };
1362
+
1363
+ CoSELayout.prototype.fillCompexOrderByDFS = function (children) {
1364
+ for (var i = 0; i < children.length; i++) {
1365
+ var child = children[i];
1366
+ if (child.getChild() != null) {
1367
+ this.fillCompexOrderByDFS(child.getChild().getNodes());
1368
+ }
1369
+ if (this.getToBeTiled(child)) {
1370
+ this.compoundOrder.push(child);
1371
+ }
1372
+ }
1373
+ };
1374
+
1375
+ /**
1376
+ * This method places each zero degree member wrt given (x,y) coordinates (top left).
1377
+ */
1378
+ CoSELayout.prototype.adjustLocations = function (organization, x, y, compoundHorizontalMargin, compoundVerticalMargin, compoundLabelMarginLeft, compoundLabelMarginTop) {
1379
+ x += compoundHorizontalMargin + compoundLabelMarginLeft;
1380
+ y += compoundVerticalMargin + compoundLabelMarginTop;
1381
+
1382
+ var left = x;
1383
+
1384
+ for (var i = 0; i < organization.rows.length; i++) {
1385
+ var row = organization.rows[i];
1386
+ x = left;
1387
+ var maxHeight = 0;
1388
+
1389
+ for (var j = 0; j < row.length; j++) {
1390
+ var lnode = row[j];
1391
+
1392
+ lnode.rect.x = x; // + lnode.rect.width / 2;
1393
+ lnode.rect.y = y; // + lnode.rect.height / 2;
1394
+
1395
+ x += lnode.rect.width + organization.horizontalPadding;
1396
+
1397
+ if (lnode.rect.height > maxHeight) maxHeight = lnode.rect.height;
1398
+ }
1399
+
1400
+ y += maxHeight + organization.verticalPadding;
1401
+ }
1402
+ };
1403
+
1404
+ CoSELayout.prototype.tileCompoundMembers = function (childGraphMap, idToNode) {
1405
+ var self = this;
1406
+ this.tiledMemberPack = [];
1407
+
1408
+ Object.keys(childGraphMap).forEach(function (id) {
1409
+ // Get the compound node
1410
+ var compoundNode = idToNode[id];
1411
+
1412
+ self.tiledMemberPack[id] = self.tileNodes(childGraphMap[id], compoundNode.paddingLeft + compoundNode.paddingRight);
1413
+
1414
+ compoundNode.rect.width = self.tiledMemberPack[id].width;
1415
+ compoundNode.rect.height = self.tiledMemberPack[id].height;
1416
+ compoundNode.setCenter(self.tiledMemberPack[id].centerX, self.tiledMemberPack[id].centerY);
1417
+
1418
+ // compound left and top margings for labels
1419
+ // when node labels are included, these values may be set to different values below and are used in tilingPostLayout,
1420
+ // otherwise they stay as zero
1421
+ compoundNode.labelMarginLeft = 0;
1422
+ compoundNode.labelMarginTop = 0;
1423
+
1424
+ // Update compound bounds considering its label properties and set label margins for left and top
1425
+ if (CoSEConstants.NODE_DIMENSIONS_INCLUDE_LABELS) {
1426
+
1427
+ var width = compoundNode.rect.width;
1428
+ var height = compoundNode.rect.height;
1429
+
1430
+ if (compoundNode.labelWidth) {
1431
+ if (compoundNode.labelPosHorizontal == "left") {
1432
+ compoundNode.rect.x -= compoundNode.labelWidth;
1433
+ compoundNode.setWidth(width + compoundNode.labelWidth);
1434
+ compoundNode.labelMarginLeft = compoundNode.labelWidth;
1435
+ } else if (compoundNode.labelPosHorizontal == "center" && compoundNode.labelWidth > width) {
1436
+ compoundNode.rect.x -= (compoundNode.labelWidth - width) / 2;
1437
+ compoundNode.setWidth(compoundNode.labelWidth);
1438
+ compoundNode.labelMarginLeft = (compoundNode.labelWidth - width) / 2;
1439
+ } else if (compoundNode.labelPosHorizontal == "right") {
1440
+ compoundNode.setWidth(width + compoundNode.labelWidth);
1441
+ }
1442
+ }
1443
+
1444
+ if (compoundNode.labelHeight) {
1445
+ if (compoundNode.labelPosVertical == "top") {
1446
+ compoundNode.rect.y -= compoundNode.labelHeight;
1447
+ compoundNode.setHeight(height + compoundNode.labelHeight);
1448
+ compoundNode.labelMarginTop = compoundNode.labelHeight;
1449
+ } else if (compoundNode.labelPosVertical == "center" && compoundNode.labelHeight > height) {
1450
+ compoundNode.rect.y -= (compoundNode.labelHeight - height) / 2;
1451
+ compoundNode.setHeight(compoundNode.labelHeight);
1452
+ compoundNode.labelMarginTop = (compoundNode.labelHeight - height) / 2;
1453
+ } else if (compoundNode.labelPosVertical == "bottom") {
1454
+ compoundNode.setHeight(height + compoundNode.labelHeight);
1455
+ }
1456
+ }
1457
+ }
1458
+ });
1459
+ };
1460
+
1461
+ CoSELayout.prototype.tileNodes = function (nodes, minWidth) {
1462
+ var horizontalOrg = this.tileNodesByFavoringDim(nodes, minWidth, true);
1463
+ var verticalOrg = this.tileNodesByFavoringDim(nodes, minWidth, false);
1464
+
1465
+ var horizontalRatio = this.getOrgRatio(horizontalOrg);
1466
+ var verticalRatio = this.getOrgRatio(verticalOrg);
1467
+ var bestOrg;
1468
+
1469
+ // the best ratio is the one that is closer to 1 since the ratios are already normalized
1470
+ // and the best organization is the one that has the best ratio
1471
+ if (verticalRatio < horizontalRatio) {
1472
+ bestOrg = verticalOrg;
1473
+ } else {
1474
+ bestOrg = horizontalOrg;
1475
+ }
1476
+
1477
+ return bestOrg;
1478
+ };
1479
+
1480
+ // get the width/height ratio of the organization that is normalized so that it will not be less than 1
1481
+ CoSELayout.prototype.getOrgRatio = function (organization) {
1482
+ // get dimensions and calculate the initial ratio
1483
+ var width = organization.width;
1484
+ var height = organization.height;
1485
+ var ratio = width / height;
1486
+
1487
+ // if the initial ratio is less then 1 then inverse it
1488
+ if (ratio < 1) {
1489
+ ratio = 1 / ratio;
1490
+ }
1491
+
1492
+ // return the normalized ratio
1493
+ return ratio;
1494
+ };
1495
+
1496
+ /*
1497
+ * Calculates the ideal width for the rows. This method assumes that
1498
+ * each node has the same sizes and calculates the ideal row width that
1499
+ * approximates a square shaped complex accordingly. However, since nodes would
1500
+ * have different sizes some rows would have different sizes and the resulting
1501
+ * shape would not be an exact square.
1502
+ */
1503
+ CoSELayout.prototype.calcIdealRowWidth = function (members, favorHorizontalDim) {
1504
+ // To approximate a square shaped complex we need to make complex width equal to complex height.
1505
+ // To achieve this we need to solve the following equation system for hc:
1506
+ // (x + bx) * hc - bx = (y + by) * vc - by, hc * vc = n
1507
+ // where x is the avarage width of the nodes, y is the avarage height of nodes
1508
+ // bx and by are the buffer sizes in horizontal and vertical dimensions accordingly,
1509
+ // hc and vc are the number of rows in horizontal and vertical dimensions
1510
+ // n is number of members.
1511
+
1512
+ var verticalPadding = CoSEConstants.TILING_PADDING_VERTICAL;
1513
+ var horizontalPadding = CoSEConstants.TILING_PADDING_HORIZONTAL;
1514
+
1515
+ // number of members
1516
+ var membersSize = members.length;
1517
+
1518
+ // sum of the width of all members
1519
+ var totalWidth = 0;
1520
+
1521
+ // sum of the height of all members
1522
+ var totalHeight = 0;
1523
+
1524
+ var maxWidth = 0;
1525
+
1526
+ // traverse all members to calculate total width and total height and get the maximum members width
1527
+ members.forEach(function (node) {
1528
+ totalWidth += node.getWidth();
1529
+ totalHeight += node.getHeight();
1530
+
1531
+ if (node.getWidth() > maxWidth) {
1532
+ maxWidth = node.getWidth();
1533
+ }
1534
+ });
1535
+
1536
+ // average width of the members
1537
+ var averageWidth = totalWidth / membersSize;
1538
+
1539
+ // average height of the members
1540
+ var averageHeight = totalHeight / membersSize;
1541
+
1542
+ // solving the initial equation system for the hc yields the following second degree equation:
1543
+ // hc^2 * (x+bx) + hc * (by - bx) - n * (y + by) = 0
1544
+
1545
+ // the delta value to solve the equation above for hc
1546
+ var delta = Math.pow(verticalPadding - horizontalPadding, 2) + 4 * (averageWidth + horizontalPadding) * (averageHeight + verticalPadding) * membersSize;
1547
+
1548
+ // solve the equation using delta value to calculate the horizontal count
1549
+ // that represents the number of nodes in an ideal row
1550
+ var horizontalCountDouble = (horizontalPadding - verticalPadding + Math.sqrt(delta)) / (2 * (averageWidth + horizontalPadding));
1551
+ // round the calculated horizontal count up or down according to the favored dimension
1552
+ var horizontalCount;
1553
+
1554
+ if (favorHorizontalDim) {
1555
+ horizontalCount = Math.ceil(horizontalCountDouble);
1556
+ // if horizontalCount count is not a float value then both of rounding to floor and ceil
1557
+ // will yield the same values. Instead of repeating the same calculation try going up
1558
+ // while favoring horizontal dimension in such cases
1559
+ if (horizontalCount == horizontalCountDouble) {
1560
+ horizontalCount++;
1561
+ }
1562
+ } else {
1563
+ horizontalCount = Math.floor(horizontalCountDouble);
1564
+ }
1565
+
1566
+ // ideal width to be calculated
1567
+ var idealWidth = horizontalCount * (averageWidth + horizontalPadding) - horizontalPadding;
1568
+
1569
+ // if max width is bigger than calculated ideal width reset ideal width to it
1570
+ if (maxWidth > idealWidth) {
1571
+ idealWidth = maxWidth;
1572
+ }
1573
+
1574
+ // add the left-right margins to the ideal row width
1575
+ idealWidth += horizontalPadding * 2;
1576
+
1577
+ // return the ideal row width1
1578
+ return idealWidth;
1579
+ };
1580
+
1581
+ CoSELayout.prototype.tileNodesByFavoringDim = function (nodes, minWidth, favorHorizontalDim) {
1582
+ var verticalPadding = CoSEConstants.TILING_PADDING_VERTICAL;
1583
+ var horizontalPadding = CoSEConstants.TILING_PADDING_HORIZONTAL;
1584
+ var tilingCompareBy = CoSEConstants.TILING_COMPARE_BY;
1585
+ var organization = {
1586
+ rows: [],
1587
+ rowWidth: [],
1588
+ rowHeight: [],
1589
+ width: 0,
1590
+ height: minWidth, // assume minHeight equals to minWidth
1591
+ verticalPadding: verticalPadding,
1592
+ horizontalPadding: horizontalPadding,
1593
+ centerX: 0,
1594
+ centerY: 0
1595
+ };
1596
+
1597
+ if (tilingCompareBy) {
1598
+ organization.idealRowWidth = this.calcIdealRowWidth(nodes, favorHorizontalDim);
1599
+ }
1600
+
1601
+ var getNodeArea = function getNodeArea(n) {
1602
+ return n.rect.width * n.rect.height;
1603
+ };
1604
+
1605
+ var areaCompareFcn = function areaCompareFcn(n1, n2) {
1606
+ return getNodeArea(n2) - getNodeArea(n1);
1607
+ };
1608
+
1609
+ // Sort the nodes in descending order of their areas
1610
+ nodes.sort(function (n1, n2) {
1611
+ var cmpBy = areaCompareFcn;
1612
+ if (organization.idealRowWidth) {
1613
+ cmpBy = tilingCompareBy;
1614
+ return cmpBy(n1.id, n2.id);
1615
+ }
1616
+ return cmpBy(n1, n2);
1617
+ });
1618
+
1619
+ // Create the organization -> calculate compound center
1620
+ var sumCenterX = 0;
1621
+ var sumCenterY = 0;
1622
+ for (var i = 0; i < nodes.length; i++) {
1623
+ var lNode = nodes[i];
1624
+
1625
+ sumCenterX += lNode.getCenterX();
1626
+ sumCenterY += lNode.getCenterY();
1627
+ }
1628
+
1629
+ organization.centerX = sumCenterX / nodes.length;
1630
+ organization.centerY = sumCenterY / nodes.length;
1631
+
1632
+ // Create the organization -> tile members
1633
+ for (var i = 0; i < nodes.length; i++) {
1634
+ var lNode = nodes[i];
1635
+
1636
+ if (organization.rows.length == 0) {
1637
+ this.insertNodeToRow(organization, lNode, 0, minWidth);
1638
+ } else if (this.canAddHorizontal(organization, lNode.rect.width, lNode.rect.height)) {
1639
+ var rowIndex = organization.rows.length - 1;
1640
+ if (!organization.idealRowWidth) {
1641
+ rowIndex = this.getShortestRowIndex(organization);
1642
+ }
1643
+ this.insertNodeToRow(organization, lNode, rowIndex, minWidth);
1644
+ } else {
1645
+ this.insertNodeToRow(organization, lNode, organization.rows.length, minWidth);
1646
+ }
1647
+
1648
+ this.shiftToLastRow(organization);
1649
+ }
1650
+
1651
+ return organization;
1652
+ };
1653
+
1654
+ CoSELayout.prototype.insertNodeToRow = function (organization, node, rowIndex, minWidth) {
1655
+ var minCompoundSize = minWidth;
1656
+
1657
+ // Add new row if needed
1658
+ if (rowIndex == organization.rows.length) {
1659
+ var secondDimension = [];
1660
+
1661
+ organization.rows.push(secondDimension);
1662
+ organization.rowWidth.push(minCompoundSize);
1663
+ organization.rowHeight.push(0);
1664
+ }
1665
+
1666
+ // Update row width
1667
+ var w = organization.rowWidth[rowIndex] + node.rect.width;
1668
+
1669
+ if (organization.rows[rowIndex].length > 0) {
1670
+ w += organization.horizontalPadding;
1671
+ }
1672
+
1673
+ organization.rowWidth[rowIndex] = w;
1674
+ // Update compound width
1675
+ if (organization.width < w) {
1676
+ organization.width = w;
1677
+ }
1678
+
1679
+ // Update height
1680
+ var h = node.rect.height;
1681
+ if (rowIndex > 0) h += organization.verticalPadding;
1682
+
1683
+ var extraHeight = 0;
1684
+ if (h > organization.rowHeight[rowIndex]) {
1685
+ extraHeight = organization.rowHeight[rowIndex];
1686
+ organization.rowHeight[rowIndex] = h;
1687
+ extraHeight = organization.rowHeight[rowIndex] - extraHeight;
1688
+ }
1689
+
1690
+ organization.height += extraHeight;
1691
+
1692
+ // Insert node
1693
+ organization.rows[rowIndex].push(node);
1694
+ };
1695
+
1696
+ //Scans the rows of an organization and returns the one with the min width
1697
+ CoSELayout.prototype.getShortestRowIndex = function (organization) {
1698
+ var r = -1;
1699
+ var min = Number.MAX_VALUE;
1700
+
1701
+ for (var i = 0; i < organization.rows.length; i++) {
1702
+ if (organization.rowWidth[i] < min) {
1703
+ r = i;
1704
+ min = organization.rowWidth[i];
1705
+ }
1706
+ }
1707
+ return r;
1708
+ };
1709
+
1710
+ //Scans the rows of an organization and returns the one with the max width
1711
+ CoSELayout.prototype.getLongestRowIndex = function (organization) {
1712
+ var r = -1;
1713
+ var max = Number.MIN_VALUE;
1714
+
1715
+ for (var i = 0; i < organization.rows.length; i++) {
1716
+
1717
+ if (organization.rowWidth[i] > max) {
1718
+ r = i;
1719
+ max = organization.rowWidth[i];
1720
+ }
1721
+ }
1722
+
1723
+ return r;
1724
+ };
1725
+
1726
+ /**
1727
+ * This method checks whether adding extra width to the organization violates
1728
+ * the aspect ratio(1) or not.
1729
+ */
1730
+ CoSELayout.prototype.canAddHorizontal = function (organization, extraWidth, extraHeight) {
1731
+
1732
+ // if there is an ideal row width specified use it instead of checking the aspect ratio
1733
+ if (organization.idealRowWidth) {
1734
+ var lastRowIndex = organization.rows.length - 1;
1735
+ var lastRowWidth = organization.rowWidth[lastRowIndex];
1736
+
1737
+ // check and return if ideal row width will be exceed if the node is added to the row
1738
+ return lastRowWidth + extraWidth + organization.horizontalPadding <= organization.idealRowWidth;
1739
+ }
1740
+
1741
+ var sri = this.getShortestRowIndex(organization);
1742
+
1743
+ if (sri < 0) {
1744
+ return true;
1745
+ }
1746
+
1747
+ var min = organization.rowWidth[sri];
1748
+
1749
+ if (min + organization.horizontalPadding + extraWidth <= organization.width) return true;
1750
+
1751
+ var hDiff = 0;
1752
+
1753
+ // Adding to an existing row
1754
+ if (organization.rowHeight[sri] < extraHeight) {
1755
+ if (sri > 0) hDiff = extraHeight + organization.verticalPadding - organization.rowHeight[sri];
1756
+ }
1757
+
1758
+ var add_to_row_ratio;
1759
+ if (organization.width - min >= extraWidth + organization.horizontalPadding) {
1760
+ add_to_row_ratio = (organization.height + hDiff) / (min + extraWidth + organization.horizontalPadding);
1761
+ } else {
1762
+ add_to_row_ratio = (organization.height + hDiff) / organization.width;
1763
+ }
1764
+
1765
+ // Adding a new row for this node
1766
+ hDiff = extraHeight + organization.verticalPadding;
1767
+ var add_new_row_ratio;
1768
+ if (organization.width < extraWidth) {
1769
+ add_new_row_ratio = (organization.height + hDiff) / extraWidth;
1770
+ } else {
1771
+ add_new_row_ratio = (organization.height + hDiff) / organization.width;
1772
+ }
1773
+
1774
+ if (add_new_row_ratio < 1) add_new_row_ratio = 1 / add_new_row_ratio;
1775
+
1776
+ if (add_to_row_ratio < 1) add_to_row_ratio = 1 / add_to_row_ratio;
1777
+
1778
+ return add_to_row_ratio < add_new_row_ratio;
1779
+ };
1780
+
1781
+ //If moving the last node from the longest row and adding it to the last
1782
+ //row makes the bounding box smaller, do it.
1783
+ CoSELayout.prototype.shiftToLastRow = function (organization) {
1784
+ var longest = this.getLongestRowIndex(organization);
1785
+ var last = organization.rowWidth.length - 1;
1786
+ var row = organization.rows[longest];
1787
+ var node = row[row.length - 1];
1788
+
1789
+ var diff = node.width + organization.horizontalPadding;
1790
+
1791
+ // Check if there is enough space on the last row
1792
+ if (organization.width - organization.rowWidth[last] > diff && longest != last) {
1793
+ // Remove the last element of the longest row
1794
+ row.splice(-1, 1);
1795
+
1796
+ // Push it to the last row
1797
+ organization.rows[last].push(node);
1798
+
1799
+ organization.rowWidth[longest] = organization.rowWidth[longest] - diff;
1800
+ organization.rowWidth[last] = organization.rowWidth[last] + diff;
1801
+ organization.width = organization.rowWidth[instance.getLongestRowIndex(organization)];
1802
+
1803
+ // Update heights of the organization
1804
+ var maxHeight = Number.MIN_VALUE;
1805
+ for (var i = 0; i < row.length; i++) {
1806
+ if (row[i].height > maxHeight) maxHeight = row[i].height;
1807
+ }
1808
+ if (longest > 0) maxHeight += organization.verticalPadding;
1809
+
1810
+ var prevTotal = organization.rowHeight[longest] + organization.rowHeight[last];
1811
+
1812
+ organization.rowHeight[longest] = maxHeight;
1813
+ if (organization.rowHeight[last] < node.height + organization.verticalPadding) organization.rowHeight[last] = node.height + organization.verticalPadding;
1814
+
1815
+ var finalTotal = organization.rowHeight[longest] + organization.rowHeight[last];
1816
+ organization.height += finalTotal - prevTotal;
1817
+
1818
+ this.shiftToLastRow(organization);
1819
+ }
1820
+ };
1821
+
1822
+ CoSELayout.prototype.tilingPreLayout = function () {
1823
+ if (CoSEConstants.TILE) {
1824
+ // Find zero degree nodes and create a compound for each level
1825
+ this.groupZeroDegreeMembers();
1826
+ // Tile and clear children of each compound
1827
+ this.clearCompounds();
1828
+ // Separately tile and clear zero degree nodes for each level
1829
+ this.clearZeroDegreeMembers();
1830
+ }
1831
+ };
1832
+
1833
+ CoSELayout.prototype.tilingPostLayout = function () {
1834
+ if (CoSEConstants.TILE) {
1835
+ this.repopulateZeroDegreeMembers();
1836
+ this.repopulateCompounds();
1837
+ }
1838
+ };
1839
+
1840
+ // -----------------------------------------------------------------------------
1841
+ // Section: Tree Reduction methods
1842
+ // -----------------------------------------------------------------------------
1843
+ // Reduce trees
1844
+ CoSELayout.prototype.reduceTrees = function () {
1845
+ var prunedNodesAll = [];
1846
+ var containsLeaf = true;
1847
+ var node;
1848
+
1849
+ while (containsLeaf) {
1850
+ var allNodes = this.graphManager.getAllNodes();
1851
+ var prunedNodesInStepTemp = [];
1852
+ containsLeaf = false;
1853
+
1854
+ for (var i = 0; i < allNodes.length; i++) {
1855
+ node = allNodes[i];
1856
+ if (node.getEdges().length == 1 && !node.getEdges()[0].isInterGraph && node.getChild() == null) {
1857
+ if (CoSEConstants.PURE_INCREMENTAL) {
1858
+ var otherEnd = node.getEdges()[0].getOtherEnd(node);
1859
+ var relativePosition = new DimensionD(node.getCenterX() - otherEnd.getCenterX(), node.getCenterY() - otherEnd.getCenterY());
1860
+ prunedNodesInStepTemp.push([node, node.getEdges()[0], node.getOwner(), relativePosition]);
1861
+ } else {
1862
+ prunedNodesInStepTemp.push([node, node.getEdges()[0], node.getOwner()]);
1863
+ }
1864
+ containsLeaf = true;
1865
+ }
1866
+ }
1867
+ if (containsLeaf == true) {
1868
+ var prunedNodesInStep = [];
1869
+ for (var j = 0; j < prunedNodesInStepTemp.length; j++) {
1870
+ if (prunedNodesInStepTemp[j][0].getEdges().length == 1) {
1871
+ prunedNodesInStep.push(prunedNodesInStepTemp[j]);
1872
+ prunedNodesInStepTemp[j][0].getOwner().remove(prunedNodesInStepTemp[j][0]);
1873
+ }
1874
+ }
1875
+ prunedNodesAll.push(prunedNodesInStep);
1876
+ this.graphManager.resetAllNodes();
1877
+ this.graphManager.resetAllEdges();
1878
+ }
1879
+ }
1880
+ this.prunedNodesAll = prunedNodesAll;
1881
+ };
1882
+
1883
+ // Grow tree one step
1884
+ CoSELayout.prototype.growTree = function (prunedNodesAll) {
1885
+ var lengthOfPrunedNodesInStep = prunedNodesAll.length;
1886
+ var prunedNodesInStep = prunedNodesAll[lengthOfPrunedNodesInStep - 1];
1887
+
1888
+ var nodeData;
1889
+ for (var i = 0; i < prunedNodesInStep.length; i++) {
1890
+ nodeData = prunedNodesInStep[i];
1891
+
1892
+ this.findPlaceforPrunedNode(nodeData);
1893
+
1894
+ nodeData[2].add(nodeData[0]);
1895
+ nodeData[2].add(nodeData[1], nodeData[1].source, nodeData[1].target);
1896
+ }
1897
+
1898
+ prunedNodesAll.splice(prunedNodesAll.length - 1, 1);
1899
+ this.graphManager.resetAllNodes();
1900
+ this.graphManager.resetAllEdges();
1901
+ };
1902
+
1903
+ // Find an appropriate position to replace pruned node, this method can be improved
1904
+ CoSELayout.prototype.findPlaceforPrunedNode = function (nodeData) {
1905
+
1906
+ var gridForPrunedNode;
1907
+ var nodeToConnect;
1908
+ var prunedNode = nodeData[0];
1909
+ if (prunedNode == nodeData[1].source) {
1910
+ nodeToConnect = nodeData[1].target;
1911
+ } else {
1912
+ nodeToConnect = nodeData[1].source;
1913
+ }
1914
+
1915
+ if (CoSEConstants.PURE_INCREMENTAL) {
1916
+ prunedNode.setCenter(nodeToConnect.getCenterX() + nodeData[3].getWidth(), nodeToConnect.getCenterY() + nodeData[3].getHeight());
1917
+ } else {
1918
+ var startGridX = nodeToConnect.startX;
1919
+ var finishGridX = nodeToConnect.finishX;
1920
+ var startGridY = nodeToConnect.startY;
1921
+ var finishGridY = nodeToConnect.finishY;
1922
+
1923
+ var upNodeCount = 0;
1924
+ var downNodeCount = 0;
1925
+ var rightNodeCount = 0;
1926
+ var leftNodeCount = 0;
1927
+ var controlRegions = [upNodeCount, rightNodeCount, downNodeCount, leftNodeCount];
1928
+
1929
+ if (startGridY > 0) {
1930
+ for (var i = startGridX; i <= finishGridX; i++) {
1931
+ controlRegions[0] += this.grid[i][startGridY - 1].length + this.grid[i][startGridY].length - 1;
1932
+ }
1933
+ }
1934
+ if (finishGridX < this.grid.length - 1) {
1935
+ for (var i = startGridY; i <= finishGridY; i++) {
1936
+ controlRegions[1] += this.grid[finishGridX + 1][i].length + this.grid[finishGridX][i].length - 1;
1937
+ }
1938
+ }
1939
+ if (finishGridY < this.grid[0].length - 1) {
1940
+ for (var i = startGridX; i <= finishGridX; i++) {
1941
+ controlRegions[2] += this.grid[i][finishGridY + 1].length + this.grid[i][finishGridY].length - 1;
1942
+ }
1943
+ }
1944
+ if (startGridX > 0) {
1945
+ for (var i = startGridY; i <= finishGridY; i++) {
1946
+ controlRegions[3] += this.grid[startGridX - 1][i].length + this.grid[startGridX][i].length - 1;
1947
+ }
1948
+ }
1949
+ var min = Integer.MAX_VALUE;
1950
+ var minCount;
1951
+ var minIndex;
1952
+ for (var j = 0; j < controlRegions.length; j++) {
1953
+ if (controlRegions[j] < min) {
1954
+ min = controlRegions[j];
1955
+ minCount = 1;
1956
+ minIndex = j;
1957
+ } else if (controlRegions[j] == min) {
1958
+ minCount++;
1959
+ }
1960
+ }
1961
+
1962
+ if (minCount == 3 && min == 0) {
1963
+ if (controlRegions[0] == 0 && controlRegions[1] == 0 && controlRegions[2] == 0) {
1964
+ gridForPrunedNode = 1;
1965
+ } else if (controlRegions[0] == 0 && controlRegions[1] == 0 && controlRegions[3] == 0) {
1966
+ gridForPrunedNode = 0;
1967
+ } else if (controlRegions[0] == 0 && controlRegions[2] == 0 && controlRegions[3] == 0) {
1968
+ gridForPrunedNode = 3;
1969
+ } else if (controlRegions[1] == 0 && controlRegions[2] == 0 && controlRegions[3] == 0) {
1970
+ gridForPrunedNode = 2;
1971
+ }
1972
+ } else if (minCount == 2 && min == 0) {
1973
+ var random = Math.floor(Math.random() * 2);
1974
+ if (controlRegions[0] == 0 && controlRegions[1] == 0) {
1975
+ ;
1976
+ if (random == 0) {
1977
+ gridForPrunedNode = 0;
1978
+ } else {
1979
+ gridForPrunedNode = 1;
1980
+ }
1981
+ } else if (controlRegions[0] == 0 && controlRegions[2] == 0) {
1982
+ if (random == 0) {
1983
+ gridForPrunedNode = 0;
1984
+ } else {
1985
+ gridForPrunedNode = 2;
1986
+ }
1987
+ } else if (controlRegions[0] == 0 && controlRegions[3] == 0) {
1988
+ if (random == 0) {
1989
+ gridForPrunedNode = 0;
1990
+ } else {
1991
+ gridForPrunedNode = 3;
1992
+ }
1993
+ } else if (controlRegions[1] == 0 && controlRegions[2] == 0) {
1994
+ if (random == 0) {
1995
+ gridForPrunedNode = 1;
1996
+ } else {
1997
+ gridForPrunedNode = 2;
1998
+ }
1999
+ } else if (controlRegions[1] == 0 && controlRegions[3] == 0) {
2000
+ if (random == 0) {
2001
+ gridForPrunedNode = 1;
2002
+ } else {
2003
+ gridForPrunedNode = 3;
2004
+ }
2005
+ } else {
2006
+ if (random == 0) {
2007
+ gridForPrunedNode = 2;
2008
+ } else {
2009
+ gridForPrunedNode = 3;
2010
+ }
2011
+ }
2012
+ } else if (minCount == 4 && min == 0) {
2013
+ var random = Math.floor(Math.random() * 4);
2014
+ gridForPrunedNode = random;
2015
+ } else {
2016
+ gridForPrunedNode = minIndex;
2017
+ }
2018
+
2019
+ if (gridForPrunedNode == 0) {
2020
+ prunedNode.setCenter(nodeToConnect.getCenterX(), nodeToConnect.getCenterY() - nodeToConnect.getHeight() / 2 - FDLayoutConstants.DEFAULT_EDGE_LENGTH - prunedNode.getHeight() / 2);
2021
+ } else if (gridForPrunedNode == 1) {
2022
+ prunedNode.setCenter(nodeToConnect.getCenterX() + nodeToConnect.getWidth() / 2 + FDLayoutConstants.DEFAULT_EDGE_LENGTH + prunedNode.getWidth() / 2, nodeToConnect.getCenterY());
2023
+ } else if (gridForPrunedNode == 2) {
2024
+ prunedNode.setCenter(nodeToConnect.getCenterX(), nodeToConnect.getCenterY() + nodeToConnect.getHeight() / 2 + FDLayoutConstants.DEFAULT_EDGE_LENGTH + prunedNode.getHeight() / 2);
2025
+ } else {
2026
+ prunedNode.setCenter(nodeToConnect.getCenterX() - nodeToConnect.getWidth() / 2 - FDLayoutConstants.DEFAULT_EDGE_LENGTH - prunedNode.getWidth() / 2, nodeToConnect.getCenterY());
2027
+ }
2028
+ }
2029
+ };
2030
+
2031
+ module.exports = CoSELayout;
2032
+
2033
+ /***/ }),
2034
+
2035
+ /***/ 991:
2036
+ /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2037
+
2038
+
2039
+
2040
+ var FDLayoutNode = __webpack_require__(551).FDLayoutNode;
2041
+ var IMath = __webpack_require__(551).IMath;
2042
+
2043
+ function CoSENode(gm, loc, size, vNode) {
2044
+ FDLayoutNode.call(this, gm, loc, size, vNode);
2045
+ }
2046
+
2047
+ CoSENode.prototype = Object.create(FDLayoutNode.prototype);
2048
+ for (var prop in FDLayoutNode) {
2049
+ CoSENode[prop] = FDLayoutNode[prop];
2050
+ }
2051
+
2052
+ CoSENode.prototype.calculateDisplacement = function () {
2053
+ var layout = this.graphManager.getLayout();
2054
+ // this check is for compound nodes that contain fixed nodes
2055
+ if (this.getChild() != null && this.fixedNodeWeight) {
2056
+ this.displacementX += layout.coolingFactor * (this.springForceX + this.repulsionForceX + this.gravitationForceX) / this.fixedNodeWeight;
2057
+ this.displacementY += layout.coolingFactor * (this.springForceY + this.repulsionForceY + this.gravitationForceY) / this.fixedNodeWeight;
2058
+ } else {
2059
+ this.displacementX += layout.coolingFactor * (this.springForceX + this.repulsionForceX + this.gravitationForceX) / this.noOfChildren;
2060
+ this.displacementY += layout.coolingFactor * (this.springForceY + this.repulsionForceY + this.gravitationForceY) / this.noOfChildren;
2061
+ }
2062
+
2063
+ if (Math.abs(this.displacementX) > layout.coolingFactor * layout.maxNodeDisplacement) {
2064
+ this.displacementX = layout.coolingFactor * layout.maxNodeDisplacement * IMath.sign(this.displacementX);
2065
+ }
2066
+
2067
+ if (Math.abs(this.displacementY) > layout.coolingFactor * layout.maxNodeDisplacement) {
2068
+ this.displacementY = layout.coolingFactor * layout.maxNodeDisplacement * IMath.sign(this.displacementY);
2069
+ }
2070
+
2071
+ // non-empty compound node, propogate movement to children as well
2072
+ if (this.child && this.child.getNodes().length > 0) {
2073
+ this.propogateDisplacementToChildren(this.displacementX, this.displacementY);
2074
+ }
2075
+ };
2076
+
2077
+ CoSENode.prototype.propogateDisplacementToChildren = function (dX, dY) {
2078
+ var nodes = this.getChild().getNodes();
2079
+ var node;
2080
+ for (var i = 0; i < nodes.length; i++) {
2081
+ node = nodes[i];
2082
+ if (node.getChild() == null) {
2083
+ node.displacementX += dX;
2084
+ node.displacementY += dY;
2085
+ } else {
2086
+ node.propogateDisplacementToChildren(dX, dY);
2087
+ }
2088
+ }
2089
+ };
2090
+
2091
+ CoSENode.prototype.move = function () {
2092
+ var layout = this.graphManager.getLayout();
2093
+
2094
+ // a simple node or an empty compound node, move it
2095
+ if (this.child == null || this.child.getNodes().length == 0) {
2096
+ this.moveBy(this.displacementX, this.displacementY);
2097
+
2098
+ layout.totalDisplacement += Math.abs(this.displacementX) + Math.abs(this.displacementY);
2099
+ }
2100
+
2101
+ this.springForceX = 0;
2102
+ this.springForceY = 0;
2103
+ this.repulsionForceX = 0;
2104
+ this.repulsionForceY = 0;
2105
+ this.gravitationForceX = 0;
2106
+ this.gravitationForceY = 0;
2107
+ this.displacementX = 0;
2108
+ this.displacementY = 0;
2109
+ };
2110
+
2111
+ CoSENode.prototype.setPred1 = function (pred1) {
2112
+ this.pred1 = pred1;
2113
+ };
2114
+
2115
+ CoSENode.prototype.getPred1 = function () {
2116
+ return pred1;
2117
+ };
2118
+
2119
+ CoSENode.prototype.getPred2 = function () {
2120
+ return pred2;
2121
+ };
2122
+
2123
+ CoSENode.prototype.setNext = function (next) {
2124
+ this.next = next;
2125
+ };
2126
+
2127
+ CoSENode.prototype.getNext = function () {
2128
+ return next;
2129
+ };
2130
+
2131
+ CoSENode.prototype.setProcessed = function (processed) {
2132
+ this.processed = processed;
2133
+ };
2134
+
2135
+ CoSENode.prototype.isProcessed = function () {
2136
+ return processed;
2137
+ };
2138
+
2139
+ module.exports = CoSENode;
2140
+
2141
+ /***/ }),
2142
+
2143
+ /***/ 902:
2144
+ /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2145
+
2146
+
2147
+
2148
+ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
2149
+
2150
+ var CoSEConstants = __webpack_require__(806);
2151
+ var LinkedList = __webpack_require__(551).LinkedList;
2152
+ var Matrix = __webpack_require__(551).Matrix;
2153
+ var SVD = __webpack_require__(551).SVD;
2154
+
2155
+ function ConstraintHandler() {}
2156
+
2157
+ ConstraintHandler.handleConstraints = function (layout) {
2158
+ // let layout = this.graphManager.getLayout();
2159
+
2160
+ // get constraints from layout
2161
+ var constraints = {};
2162
+ constraints.fixedNodeConstraint = layout.constraints.fixedNodeConstraint;
2163
+ constraints.alignmentConstraint = layout.constraints.alignmentConstraint;
2164
+ constraints.relativePlacementConstraint = layout.constraints.relativePlacementConstraint;
2165
+
2166
+ var idToNodeMap = new Map();
2167
+ var nodeIndexes = new Map();
2168
+ var xCoords = [];
2169
+ var yCoords = [];
2170
+
2171
+ var allNodes = layout.getAllNodes();
2172
+ var index = 0;
2173
+ // fill index map and coordinates
2174
+ for (var i = 0; i < allNodes.length; i++) {
2175
+ var node = allNodes[i];
2176
+ if (node.getChild() == null) {
2177
+ nodeIndexes.set(node.id, index++);
2178
+ xCoords.push(node.getCenterX());
2179
+ yCoords.push(node.getCenterY());
2180
+ idToNodeMap.set(node.id, node);
2181
+ }
2182
+ }
2183
+
2184
+ // if there exists relative placement constraint without gap value, set it to default
2185
+ if (constraints.relativePlacementConstraint) {
2186
+ constraints.relativePlacementConstraint.forEach(function (constraint) {
2187
+ if (!constraint.gap && constraint.gap != 0) {
2188
+ if (constraint.left) {
2189
+ constraint.gap = CoSEConstants.DEFAULT_EDGE_LENGTH + idToNodeMap.get(constraint.left).getWidth() / 2 + idToNodeMap.get(constraint.right).getWidth() / 2;
2190
+ } else {
2191
+ constraint.gap = CoSEConstants.DEFAULT_EDGE_LENGTH + idToNodeMap.get(constraint.top).getHeight() / 2 + idToNodeMap.get(constraint.bottom).getHeight() / 2;
2192
+ }
2193
+ }
2194
+ });
2195
+ }
2196
+
2197
+ /* auxiliary functions */
2198
+
2199
+ // calculate difference between two position objects
2200
+ var calculatePositionDiff = function calculatePositionDiff(pos1, pos2) {
2201
+ return { x: pos1.x - pos2.x, y: pos1.y - pos2.y };
2202
+ };
2203
+
2204
+ // calculate average position of the nodes
2205
+ var calculateAvgPosition = function calculateAvgPosition(nodeIdSet) {
2206
+ var xPosSum = 0;
2207
+ var yPosSum = 0;
2208
+ nodeIdSet.forEach(function (nodeId) {
2209
+ xPosSum += xCoords[nodeIndexes.get(nodeId)];
2210
+ yPosSum += yCoords[nodeIndexes.get(nodeId)];
2211
+ });
2212
+
2213
+ return { x: xPosSum / nodeIdSet.size, y: yPosSum / nodeIdSet.size };
2214
+ };
2215
+
2216
+ // find an appropriate positioning for the nodes in a given graph according to relative placement constraints
2217
+ // this function also takes the fixed nodes and alignment constraints into account
2218
+ // graph: dag to be evaluated, direction: "horizontal" or "vertical",
2219
+ // fixedNodes: set of fixed nodes to consider during evaluation, dummyPositions: appropriate coordinates of the dummy nodes
2220
+ var findAppropriatePositionForRelativePlacement = function findAppropriatePositionForRelativePlacement(graph, direction, fixedNodes, dummyPositions, componentSources) {
2221
+
2222
+ // find union of two sets
2223
+ function setUnion(setA, setB) {
2224
+ var union = new Set(setA);
2225
+ var _iteratorNormalCompletion = true;
2226
+ var _didIteratorError = false;
2227
+ var _iteratorError = undefined;
2228
+
2229
+ try {
2230
+ for (var _iterator = setB[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
2231
+ var elem = _step.value;
2232
+
2233
+ union.add(elem);
2234
+ }
2235
+ } catch (err) {
2236
+ _didIteratorError = true;
2237
+ _iteratorError = err;
2238
+ } finally {
2239
+ try {
2240
+ if (!_iteratorNormalCompletion && _iterator.return) {
2241
+ _iterator.return();
2242
+ }
2243
+ } finally {
2244
+ if (_didIteratorError) {
2245
+ throw _iteratorError;
2246
+ }
2247
+ }
2248
+ }
2249
+
2250
+ return union;
2251
+ }
2252
+
2253
+ // find indegree count for each node
2254
+ var inDegrees = new Map();
2255
+
2256
+ graph.forEach(function (value, key) {
2257
+ inDegrees.set(key, 0);
2258
+ });
2259
+ graph.forEach(function (value, key) {
2260
+ value.forEach(function (adjacent) {
2261
+ inDegrees.set(adjacent.id, inDegrees.get(adjacent.id) + 1);
2262
+ });
2263
+ });
2264
+
2265
+ var positionMap = new Map(); // keeps the position for each node
2266
+ var pastMap = new Map(); // keeps the predecessors(past) of a node
2267
+ var queue = new LinkedList();
2268
+ inDegrees.forEach(function (value, key) {
2269
+ if (value == 0) {
2270
+ queue.push(key);
2271
+ if (!fixedNodes) {
2272
+ if (direction == "horizontal") {
2273
+ positionMap.set(key, nodeIndexes.has(key) ? xCoords[nodeIndexes.get(key)] : dummyPositions.get(key));
2274
+ } else {
2275
+ positionMap.set(key, nodeIndexes.has(key) ? yCoords[nodeIndexes.get(key)] : dummyPositions.get(key));
2276
+ }
2277
+ }
2278
+ } else {
2279
+ positionMap.set(key, Number.NEGATIVE_INFINITY);
2280
+ }
2281
+ if (fixedNodes) {
2282
+ pastMap.set(key, new Set([key]));
2283
+ }
2284
+ });
2285
+
2286
+ // align sources of each component in enforcement phase
2287
+ if (fixedNodes) {
2288
+ componentSources.forEach(function (component) {
2289
+ var fixedIds = [];
2290
+ component.forEach(function (nodeId) {
2291
+ if (fixedNodes.has(nodeId)) {
2292
+ fixedIds.push(nodeId);
2293
+ }
2294
+ });
2295
+ if (fixedIds.length > 0) {
2296
+ var position = 0;
2297
+ fixedIds.forEach(function (fixedId) {
2298
+ if (direction == "horizontal") {
2299
+ positionMap.set(fixedId, nodeIndexes.has(fixedId) ? xCoords[nodeIndexes.get(fixedId)] : dummyPositions.get(fixedId));
2300
+ position += positionMap.get(fixedId);
2301
+ } else {
2302
+ positionMap.set(fixedId, nodeIndexes.has(fixedId) ? yCoords[nodeIndexes.get(fixedId)] : dummyPositions.get(fixedId));
2303
+ position += positionMap.get(fixedId);
2304
+ }
2305
+ });
2306
+ position = position / fixedIds.length;
2307
+ component.forEach(function (nodeId) {
2308
+ if (!fixedNodes.has(nodeId)) {
2309
+ positionMap.set(nodeId, position);
2310
+ }
2311
+ });
2312
+ } else {
2313
+ var _position = 0;
2314
+ component.forEach(function (nodeId) {
2315
+ if (direction == "horizontal") {
2316
+ _position += nodeIndexes.has(nodeId) ? xCoords[nodeIndexes.get(nodeId)] : dummyPositions.get(nodeId);
2317
+ } else {
2318
+ _position += nodeIndexes.has(nodeId) ? yCoords[nodeIndexes.get(nodeId)] : dummyPositions.get(nodeId);
2319
+ }
2320
+ });
2321
+ _position = _position / component.length;
2322
+ component.forEach(function (nodeId) {
2323
+ positionMap.set(nodeId, _position);
2324
+ });
2325
+ }
2326
+ });
2327
+ }
2328
+
2329
+ // calculate positions of the nodes
2330
+
2331
+ var _loop = function _loop() {
2332
+ var currentNode = queue.shift();
2333
+ var neighbors = graph.get(currentNode);
2334
+ neighbors.forEach(function (neighbor) {
2335
+ if (positionMap.get(neighbor.id) < positionMap.get(currentNode) + neighbor.gap) {
2336
+ if (fixedNodes && fixedNodes.has(neighbor.id)) {
2337
+ var fixedPosition = void 0;
2338
+ if (direction == "horizontal") {
2339
+ fixedPosition = nodeIndexes.has(neighbor.id) ? xCoords[nodeIndexes.get(neighbor.id)] : dummyPositions.get(neighbor.id);
2340
+ } else {
2341
+ fixedPosition = nodeIndexes.has(neighbor.id) ? yCoords[nodeIndexes.get(neighbor.id)] : dummyPositions.get(neighbor.id);
2342
+ }
2343
+ positionMap.set(neighbor.id, fixedPosition); // TODO: may do unnecessary work
2344
+ if (fixedPosition < positionMap.get(currentNode) + neighbor.gap) {
2345
+ var diff = positionMap.get(currentNode) + neighbor.gap - fixedPosition;
2346
+ pastMap.get(currentNode).forEach(function (nodeId) {
2347
+ positionMap.set(nodeId, positionMap.get(nodeId) - diff);
2348
+ });
2349
+ }
2350
+ } else {
2351
+ positionMap.set(neighbor.id, positionMap.get(currentNode) + neighbor.gap);
2352
+ }
2353
+ }
2354
+ inDegrees.set(neighbor.id, inDegrees.get(neighbor.id) - 1);
2355
+ if (inDegrees.get(neighbor.id) == 0) {
2356
+ queue.push(neighbor.id);
2357
+ }
2358
+ if (fixedNodes) {
2359
+ pastMap.set(neighbor.id, setUnion(pastMap.get(currentNode), pastMap.get(neighbor.id)));
2360
+ }
2361
+ });
2362
+ };
2363
+
2364
+ while (queue.length != 0) {
2365
+ _loop();
2366
+ }
2367
+
2368
+ // readjust position of the nodes after enforcement
2369
+ if (fixedNodes) {
2370
+ // find indegree count for each node
2371
+ var sinkNodes = new Set();
2372
+
2373
+ graph.forEach(function (value, key) {
2374
+ if (value.length == 0) {
2375
+ sinkNodes.add(key);
2376
+ }
2377
+ });
2378
+
2379
+ var _components = [];
2380
+ pastMap.forEach(function (value, key) {
2381
+ if (sinkNodes.has(key)) {
2382
+ var isFixedComponent = false;
2383
+ var _iteratorNormalCompletion2 = true;
2384
+ var _didIteratorError2 = false;
2385
+ var _iteratorError2 = undefined;
2386
+
2387
+ try {
2388
+ for (var _iterator2 = value[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
2389
+ var nodeId = _step2.value;
2390
+
2391
+ if (fixedNodes.has(nodeId)) {
2392
+ isFixedComponent = true;
2393
+ }
2394
+ }
2395
+ } catch (err) {
2396
+ _didIteratorError2 = true;
2397
+ _iteratorError2 = err;
2398
+ } finally {
2399
+ try {
2400
+ if (!_iteratorNormalCompletion2 && _iterator2.return) {
2401
+ _iterator2.return();
2402
+ }
2403
+ } finally {
2404
+ if (_didIteratorError2) {
2405
+ throw _iteratorError2;
2406
+ }
2407
+ }
2408
+ }
2409
+
2410
+ if (!isFixedComponent) {
2411
+ var isExist = false;
2412
+ var existAt = void 0;
2413
+ _components.forEach(function (component, index) {
2414
+ if (component.has([].concat(_toConsumableArray(value))[0])) {
2415
+ isExist = true;
2416
+ existAt = index;
2417
+ }
2418
+ });
2419
+ if (!isExist) {
2420
+ _components.push(new Set(value));
2421
+ } else {
2422
+ value.forEach(function (ele) {
2423
+ _components[existAt].add(ele);
2424
+ });
2425
+ }
2426
+ }
2427
+ }
2428
+ });
2429
+
2430
+ _components.forEach(function (component, index) {
2431
+ var minBefore = Number.POSITIVE_INFINITY;
2432
+ var minAfter = Number.POSITIVE_INFINITY;
2433
+ var maxBefore = Number.NEGATIVE_INFINITY;
2434
+ var maxAfter = Number.NEGATIVE_INFINITY;
2435
+
2436
+ var _iteratorNormalCompletion3 = true;
2437
+ var _didIteratorError3 = false;
2438
+ var _iteratorError3 = undefined;
2439
+
2440
+ try {
2441
+ for (var _iterator3 = component[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
2442
+ var nodeId = _step3.value;
2443
+
2444
+ var posBefore = void 0;
2445
+ if (direction == "horizontal") {
2446
+ posBefore = nodeIndexes.has(nodeId) ? xCoords[nodeIndexes.get(nodeId)] : dummyPositions.get(nodeId);
2447
+ } else {
2448
+ posBefore = nodeIndexes.has(nodeId) ? yCoords[nodeIndexes.get(nodeId)] : dummyPositions.get(nodeId);
2449
+ }
2450
+ var posAfter = positionMap.get(nodeId);
2451
+ if (posBefore < minBefore) {
2452
+ minBefore = posBefore;
2453
+ }
2454
+ if (posBefore > maxBefore) {
2455
+ maxBefore = posBefore;
2456
+ }
2457
+ if (posAfter < minAfter) {
2458
+ minAfter = posAfter;
2459
+ }
2460
+ if (posAfter > maxAfter) {
2461
+ maxAfter = posAfter;
2462
+ }
2463
+ }
2464
+ } catch (err) {
2465
+ _didIteratorError3 = true;
2466
+ _iteratorError3 = err;
2467
+ } finally {
2468
+ try {
2469
+ if (!_iteratorNormalCompletion3 && _iterator3.return) {
2470
+ _iterator3.return();
2471
+ }
2472
+ } finally {
2473
+ if (_didIteratorError3) {
2474
+ throw _iteratorError3;
2475
+ }
2476
+ }
2477
+ }
2478
+
2479
+ var diff = (minBefore + maxBefore) / 2 - (minAfter + maxAfter) / 2;
2480
+
2481
+ var _iteratorNormalCompletion4 = true;
2482
+ var _didIteratorError4 = false;
2483
+ var _iteratorError4 = undefined;
2484
+
2485
+ try {
2486
+ for (var _iterator4 = component[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
2487
+ var _nodeId = _step4.value;
2488
+
2489
+ positionMap.set(_nodeId, positionMap.get(_nodeId) + diff);
2490
+ }
2491
+ } catch (err) {
2492
+ _didIteratorError4 = true;
2493
+ _iteratorError4 = err;
2494
+ } finally {
2495
+ try {
2496
+ if (!_iteratorNormalCompletion4 && _iterator4.return) {
2497
+ _iterator4.return();
2498
+ }
2499
+ } finally {
2500
+ if (_didIteratorError4) {
2501
+ throw _iteratorError4;
2502
+ }
2503
+ }
2504
+ }
2505
+ });
2506
+ }
2507
+
2508
+ return positionMap;
2509
+ };
2510
+
2511
+ // find transformation based on rel. placement constraints if there are both alignment and rel. placement constraints
2512
+ // or if there are only rel. placement contraints where the largest component isn't sufficiently large
2513
+ var applyReflectionForRelativePlacement = function applyReflectionForRelativePlacement(relativePlacementConstraints) {
2514
+ // variables to count votes
2515
+ var reflectOnY = 0,
2516
+ notReflectOnY = 0;
2517
+ var reflectOnX = 0,
2518
+ notReflectOnX = 0;
2519
+
2520
+ relativePlacementConstraints.forEach(function (constraint) {
2521
+ if (constraint.left) {
2522
+ xCoords[nodeIndexes.get(constraint.left)] - xCoords[nodeIndexes.get(constraint.right)] >= 0 ? reflectOnY++ : notReflectOnY++;
2523
+ } else {
2524
+ yCoords[nodeIndexes.get(constraint.top)] - yCoords[nodeIndexes.get(constraint.bottom)] >= 0 ? reflectOnX++ : notReflectOnX++;
2525
+ }
2526
+ });
2527
+
2528
+ if (reflectOnY > notReflectOnY && reflectOnX > notReflectOnX) {
2529
+ for (var _i = 0; _i < nodeIndexes.size; _i++) {
2530
+ xCoords[_i] = -1 * xCoords[_i];
2531
+ yCoords[_i] = -1 * yCoords[_i];
2532
+ }
2533
+ } else if (reflectOnY > notReflectOnY) {
2534
+ for (var _i2 = 0; _i2 < nodeIndexes.size; _i2++) {
2535
+ xCoords[_i2] = -1 * xCoords[_i2];
2536
+ }
2537
+ } else if (reflectOnX > notReflectOnX) {
2538
+ for (var _i3 = 0; _i3 < nodeIndexes.size; _i3++) {
2539
+ yCoords[_i3] = -1 * yCoords[_i3];
2540
+ }
2541
+ }
2542
+ };
2543
+
2544
+ // find weakly connected components in undirected graph
2545
+ var findComponents = function findComponents(graph) {
2546
+ // find weakly connected components in dag
2547
+ var components = [];
2548
+ var queue = new LinkedList();
2549
+ var visited = new Set();
2550
+ var count = 0;
2551
+
2552
+ graph.forEach(function (value, key) {
2553
+ if (!visited.has(key)) {
2554
+ components[count] = [];
2555
+ var _currentNode = key;
2556
+ queue.push(_currentNode);
2557
+ visited.add(_currentNode);
2558
+ components[count].push(_currentNode);
2559
+
2560
+ while (queue.length != 0) {
2561
+ _currentNode = queue.shift();
2562
+ var neighbors = graph.get(_currentNode);
2563
+ neighbors.forEach(function (neighbor) {
2564
+ if (!visited.has(neighbor.id)) {
2565
+ queue.push(neighbor.id);
2566
+ visited.add(neighbor.id);
2567
+ components[count].push(neighbor.id);
2568
+ }
2569
+ });
2570
+ }
2571
+ count++;
2572
+ }
2573
+ });
2574
+ return components;
2575
+ };
2576
+
2577
+ // return undirected version of given dag
2578
+ var dagToUndirected = function dagToUndirected(dag) {
2579
+ var undirected = new Map();
2580
+
2581
+ dag.forEach(function (value, key) {
2582
+ undirected.set(key, []);
2583
+ });
2584
+
2585
+ dag.forEach(function (value, key) {
2586
+ value.forEach(function (adjacent) {
2587
+ undirected.get(key).push(adjacent);
2588
+ undirected.get(adjacent.id).push({ id: key, gap: adjacent.gap, direction: adjacent.direction });
2589
+ });
2590
+ });
2591
+
2592
+ return undirected;
2593
+ };
2594
+
2595
+ // return reversed (directions inverted) version of given dag
2596
+ var dagToReversed = function dagToReversed(dag) {
2597
+ var reversed = new Map();
2598
+
2599
+ dag.forEach(function (value, key) {
2600
+ reversed.set(key, []);
2601
+ });
2602
+
2603
+ dag.forEach(function (value, key) {
2604
+ value.forEach(function (adjacent) {
2605
+ reversed.get(adjacent.id).push({ id: key, gap: adjacent.gap, direction: adjacent.direction });
2606
+ });
2607
+ });
2608
+
2609
+ return reversed;
2610
+ };
2611
+
2612
+ /**** apply transformation to the initial draft layout to better align with constrained nodes ****/
2613
+ // solve the Orthogonal Procrustean Problem to rotate and/or reflect initial draft layout
2614
+ // here we follow the solution in Chapter 20.2 of Borg, I. & Groenen, P. (2005) Modern Multidimensional Scaling: Theory and Applications
2615
+
2616
+ /* construct source and target configurations */
2617
+
2618
+ var targetMatrix = []; // A - target configuration
2619
+ var sourceMatrix = []; // B - source configuration
2620
+ var standardTransformation = false; // false for no transformation, true for standart (Procrustes) transformation (rotation and/or reflection)
2621
+ var reflectionType = false; // false/true for reflection check, 'reflectOnX', 'reflectOnY' or 'reflectOnBoth' for reflection type if necessary
2622
+ var fixedNodes = new Set();
2623
+ var dag = new Map(); // adjacency list to keep directed acyclic graph (dag) that consists of relative placement constraints
2624
+ var dagUndirected = new Map(); // undirected version of the dag
2625
+ var components = []; // weakly connected components
2626
+
2627
+ // fill fixedNodes collection to use later
2628
+ if (constraints.fixedNodeConstraint) {
2629
+ constraints.fixedNodeConstraint.forEach(function (nodeData) {
2630
+ fixedNodes.add(nodeData.nodeId);
2631
+ });
2632
+ }
2633
+
2634
+ // construct dag from relative placement constraints
2635
+ if (constraints.relativePlacementConstraint) {
2636
+ // construct both directed and undirected version of the dag
2637
+ constraints.relativePlacementConstraint.forEach(function (constraint) {
2638
+ if (constraint.left) {
2639
+ if (dag.has(constraint.left)) {
2640
+ dag.get(constraint.left).push({ id: constraint.right, gap: constraint.gap, direction: "horizontal" });
2641
+ } else {
2642
+ dag.set(constraint.left, [{ id: constraint.right, gap: constraint.gap, direction: "horizontal" }]);
2643
+ }
2644
+ if (!dag.has(constraint.right)) {
2645
+ dag.set(constraint.right, []);
2646
+ }
2647
+ } else {
2648
+ if (dag.has(constraint.top)) {
2649
+ dag.get(constraint.top).push({ id: constraint.bottom, gap: constraint.gap, direction: "vertical" });
2650
+ } else {
2651
+ dag.set(constraint.top, [{ id: constraint.bottom, gap: constraint.gap, direction: "vertical" }]);
2652
+ }
2653
+ if (!dag.has(constraint.bottom)) {
2654
+ dag.set(constraint.bottom, []);
2655
+ }
2656
+ }
2657
+ });
2658
+
2659
+ dagUndirected = dagToUndirected(dag);
2660
+ components = findComponents(dagUndirected);
2661
+ }
2662
+
2663
+ if (CoSEConstants.TRANSFORM_ON_CONSTRAINT_HANDLING) {
2664
+ // first check fixed node constraint
2665
+ if (constraints.fixedNodeConstraint && constraints.fixedNodeConstraint.length > 1) {
2666
+ constraints.fixedNodeConstraint.forEach(function (nodeData, i) {
2667
+ targetMatrix[i] = [nodeData.position.x, nodeData.position.y];
2668
+ sourceMatrix[i] = [xCoords[nodeIndexes.get(nodeData.nodeId)], yCoords[nodeIndexes.get(nodeData.nodeId)]];
2669
+ });
2670
+ standardTransformation = true;
2671
+ } else if (constraints.alignmentConstraint) {
2672
+ (function () {
2673
+ // then check alignment constraint
2674
+ var count = 0;
2675
+ if (constraints.alignmentConstraint.vertical) {
2676
+ var verticalAlign = constraints.alignmentConstraint.vertical;
2677
+
2678
+ var _loop2 = function _loop2(_i4) {
2679
+ var alignmentSet = new Set();
2680
+ verticalAlign[_i4].forEach(function (nodeId) {
2681
+ alignmentSet.add(nodeId);
2682
+ });
2683
+ var intersection = new Set([].concat(_toConsumableArray(alignmentSet)).filter(function (x) {
2684
+ return fixedNodes.has(x);
2685
+ }));
2686
+ var xPos = void 0;
2687
+ if (intersection.size > 0) xPos = xCoords[nodeIndexes.get(intersection.values().next().value)];else xPos = calculateAvgPosition(alignmentSet).x;
2688
+
2689
+ verticalAlign[_i4].forEach(function (nodeId) {
2690
+ targetMatrix[count] = [xPos, yCoords[nodeIndexes.get(nodeId)]];
2691
+ sourceMatrix[count] = [xCoords[nodeIndexes.get(nodeId)], yCoords[nodeIndexes.get(nodeId)]];
2692
+ count++;
2693
+ });
2694
+ };
2695
+
2696
+ for (var _i4 = 0; _i4 < verticalAlign.length; _i4++) {
2697
+ _loop2(_i4);
2698
+ }
2699
+ standardTransformation = true;
2700
+ }
2701
+ if (constraints.alignmentConstraint.horizontal) {
2702
+ var horizontalAlign = constraints.alignmentConstraint.horizontal;
2703
+
2704
+ var _loop3 = function _loop3(_i5) {
2705
+ var alignmentSet = new Set();
2706
+ horizontalAlign[_i5].forEach(function (nodeId) {
2707
+ alignmentSet.add(nodeId);
2708
+ });
2709
+ var intersection = new Set([].concat(_toConsumableArray(alignmentSet)).filter(function (x) {
2710
+ return fixedNodes.has(x);
2711
+ }));
2712
+ var yPos = void 0;
2713
+ if (intersection.size > 0) yPos = xCoords[nodeIndexes.get(intersection.values().next().value)];else yPos = calculateAvgPosition(alignmentSet).y;
2714
+
2715
+ horizontalAlign[_i5].forEach(function (nodeId) {
2716
+ targetMatrix[count] = [xCoords[nodeIndexes.get(nodeId)], yPos];
2717
+ sourceMatrix[count] = [xCoords[nodeIndexes.get(nodeId)], yCoords[nodeIndexes.get(nodeId)]];
2718
+ count++;
2719
+ });
2720
+ };
2721
+
2722
+ for (var _i5 = 0; _i5 < horizontalAlign.length; _i5++) {
2723
+ _loop3(_i5);
2724
+ }
2725
+ standardTransformation = true;
2726
+ }
2727
+ if (constraints.relativePlacementConstraint) {
2728
+ reflectionType = true;
2729
+ }
2730
+ })();
2731
+ } else if (constraints.relativePlacementConstraint) {
2732
+ // finally check relative placement constraint
2733
+ // find largest component in dag
2734
+ var largestComponentSize = 0;
2735
+ var largestComponentIndex = 0;
2736
+ for (var _i6 = 0; _i6 < components.length; _i6++) {
2737
+ if (components[_i6].length > largestComponentSize) {
2738
+ largestComponentSize = components[_i6].length;
2739
+ largestComponentIndex = _i6;
2740
+ }
2741
+ }
2742
+ // if largest component isn't dominant, then take the votes for reflection
2743
+ if (largestComponentSize < dagUndirected.size / 2) {
2744
+ applyReflectionForRelativePlacement(constraints.relativePlacementConstraint);
2745
+ standardTransformation = false;
2746
+ reflectionType = false;
2747
+ } else {
2748
+ // use largest component for transformation
2749
+ // construct horizontal and vertical subgraphs in the largest component
2750
+ var subGraphOnHorizontal = new Map();
2751
+ var subGraphOnVertical = new Map();
2752
+ var constraintsInlargestComponent = [];
2753
+
2754
+ components[largestComponentIndex].forEach(function (nodeId) {
2755
+ dag.get(nodeId).forEach(function (adjacent) {
2756
+ if (adjacent.direction == "horizontal") {
2757
+ if (subGraphOnHorizontal.has(nodeId)) {
2758
+ subGraphOnHorizontal.get(nodeId).push(adjacent);
2759
+ } else {
2760
+ subGraphOnHorizontal.set(nodeId, [adjacent]);
2761
+ }
2762
+ if (!subGraphOnHorizontal.has(adjacent.id)) {
2763
+ subGraphOnHorizontal.set(adjacent.id, []);
2764
+ }
2765
+ constraintsInlargestComponent.push({ left: nodeId, right: adjacent.id });
2766
+ } else {
2767
+ if (subGraphOnVertical.has(nodeId)) {
2768
+ subGraphOnVertical.get(nodeId).push(adjacent);
2769
+ } else {
2770
+ subGraphOnVertical.set(nodeId, [adjacent]);
2771
+ }
2772
+ if (!subGraphOnVertical.has(adjacent.id)) {
2773
+ subGraphOnVertical.set(adjacent.id, []);
2774
+ }
2775
+ constraintsInlargestComponent.push({ top: nodeId, bottom: adjacent.id });
2776
+ }
2777
+ });
2778
+ });
2779
+
2780
+ applyReflectionForRelativePlacement(constraintsInlargestComponent);
2781
+ reflectionType = false;
2782
+
2783
+ // calculate appropriate positioning for subgraphs
2784
+ var positionMapHorizontal = findAppropriatePositionForRelativePlacement(subGraphOnHorizontal, "horizontal");
2785
+ var positionMapVertical = findAppropriatePositionForRelativePlacement(subGraphOnVertical, "vertical");
2786
+
2787
+ // construct source and target configuration
2788
+ components[largestComponentIndex].forEach(function (nodeId, i) {
2789
+ sourceMatrix[i] = [xCoords[nodeIndexes.get(nodeId)], yCoords[nodeIndexes.get(nodeId)]];
2790
+ targetMatrix[i] = [];
2791
+ if (positionMapHorizontal.has(nodeId)) {
2792
+ targetMatrix[i][0] = positionMapHorizontal.get(nodeId);
2793
+ } else {
2794
+ targetMatrix[i][0] = xCoords[nodeIndexes.get(nodeId)];
2795
+ }
2796
+ if (positionMapVertical.has(nodeId)) {
2797
+ targetMatrix[i][1] = positionMapVertical.get(nodeId);
2798
+ } else {
2799
+ targetMatrix[i][1] = yCoords[nodeIndexes.get(nodeId)];
2800
+ }
2801
+ });
2802
+
2803
+ standardTransformation = true;
2804
+ }
2805
+ }
2806
+
2807
+ // if transformation is required, then calculate and apply transformation matrix
2808
+ if (standardTransformation) {
2809
+ /* calculate transformation matrix */
2810
+ var transformationMatrix = void 0;
2811
+ var targetMatrixTranspose = Matrix.transpose(targetMatrix); // A'
2812
+ var sourceMatrixTranspose = Matrix.transpose(sourceMatrix); // B'
2813
+
2814
+ // centralize transpose matrices
2815
+ for (var _i7 = 0; _i7 < targetMatrixTranspose.length; _i7++) {
2816
+ targetMatrixTranspose[_i7] = Matrix.multGamma(targetMatrixTranspose[_i7]);
2817
+ sourceMatrixTranspose[_i7] = Matrix.multGamma(sourceMatrixTranspose[_i7]);
2818
+ }
2819
+
2820
+ // do actual calculation for transformation matrix
2821
+ var tempMatrix = Matrix.multMat(targetMatrixTranspose, Matrix.transpose(sourceMatrixTranspose)); // tempMatrix = A'B
2822
+ var SVDResult = SVD.svd(tempMatrix); // SVD(A'B) = USV', svd function returns U, S and V
2823
+ transformationMatrix = Matrix.multMat(SVDResult.V, Matrix.transpose(SVDResult.U)); // transformationMatrix = T = VU'
2824
+
2825
+ /* apply found transformation matrix to obtain final draft layout */
2826
+ for (var _i8 = 0; _i8 < nodeIndexes.size; _i8++) {
2827
+ var temp1 = [xCoords[_i8], yCoords[_i8]];
2828
+ var temp2 = [transformationMatrix[0][0], transformationMatrix[1][0]];
2829
+ var temp3 = [transformationMatrix[0][1], transformationMatrix[1][1]];
2830
+ xCoords[_i8] = Matrix.dotProduct(temp1, temp2);
2831
+ yCoords[_i8] = Matrix.dotProduct(temp1, temp3);
2832
+ }
2833
+
2834
+ // applied only both alignment and rel. placement constraints exist
2835
+ if (reflectionType) {
2836
+ applyReflectionForRelativePlacement(constraints.relativePlacementConstraint);
2837
+ }
2838
+ }
2839
+ }
2840
+
2841
+ if (CoSEConstants.ENFORCE_CONSTRAINTS) {
2842
+ /**** enforce constraints on the transformed draft layout ****/
2843
+
2844
+ /* first enforce fixed node constraint */
2845
+
2846
+ if (constraints.fixedNodeConstraint && constraints.fixedNodeConstraint.length > 0) {
2847
+ var translationAmount = { x: 0, y: 0 };
2848
+ constraints.fixedNodeConstraint.forEach(function (nodeData, i) {
2849
+ var posInTheory = { x: xCoords[nodeIndexes.get(nodeData.nodeId)], y: yCoords[nodeIndexes.get(nodeData.nodeId)] };
2850
+ var posDesired = nodeData.position;
2851
+ var posDiff = calculatePositionDiff(posDesired, posInTheory);
2852
+ translationAmount.x += posDiff.x;
2853
+ translationAmount.y += posDiff.y;
2854
+ });
2855
+ translationAmount.x /= constraints.fixedNodeConstraint.length;
2856
+ translationAmount.y /= constraints.fixedNodeConstraint.length;
2857
+
2858
+ xCoords.forEach(function (value, i) {
2859
+ xCoords[i] += translationAmount.x;
2860
+ });
2861
+
2862
+ yCoords.forEach(function (value, i) {
2863
+ yCoords[i] += translationAmount.y;
2864
+ });
2865
+
2866
+ constraints.fixedNodeConstraint.forEach(function (nodeData) {
2867
+ xCoords[nodeIndexes.get(nodeData.nodeId)] = nodeData.position.x;
2868
+ yCoords[nodeIndexes.get(nodeData.nodeId)] = nodeData.position.y;
2869
+ });
2870
+ }
2871
+
2872
+ /* then enforce alignment constraint */
2873
+
2874
+ if (constraints.alignmentConstraint) {
2875
+ if (constraints.alignmentConstraint.vertical) {
2876
+ var xAlign = constraints.alignmentConstraint.vertical;
2877
+
2878
+ var _loop4 = function _loop4(_i9) {
2879
+ var alignmentSet = new Set();
2880
+ xAlign[_i9].forEach(function (nodeId) {
2881
+ alignmentSet.add(nodeId);
2882
+ });
2883
+ var intersection = new Set([].concat(_toConsumableArray(alignmentSet)).filter(function (x) {
2884
+ return fixedNodes.has(x);
2885
+ }));
2886
+ var xPos = void 0;
2887
+ if (intersection.size > 0) xPos = xCoords[nodeIndexes.get(intersection.values().next().value)];else xPos = calculateAvgPosition(alignmentSet).x;
2888
+
2889
+ alignmentSet.forEach(function (nodeId) {
2890
+ if (!fixedNodes.has(nodeId)) xCoords[nodeIndexes.get(nodeId)] = xPos;
2891
+ });
2892
+ };
2893
+
2894
+ for (var _i9 = 0; _i9 < xAlign.length; _i9++) {
2895
+ _loop4(_i9);
2896
+ }
2897
+ }
2898
+ if (constraints.alignmentConstraint.horizontal) {
2899
+ var yAlign = constraints.alignmentConstraint.horizontal;
2900
+
2901
+ var _loop5 = function _loop5(_i10) {
2902
+ var alignmentSet = new Set();
2903
+ yAlign[_i10].forEach(function (nodeId) {
2904
+ alignmentSet.add(nodeId);
2905
+ });
2906
+ var intersection = new Set([].concat(_toConsumableArray(alignmentSet)).filter(function (x) {
2907
+ return fixedNodes.has(x);
2908
+ }));
2909
+ var yPos = void 0;
2910
+ if (intersection.size > 0) yPos = yCoords[nodeIndexes.get(intersection.values().next().value)];else yPos = calculateAvgPosition(alignmentSet).y;
2911
+
2912
+ alignmentSet.forEach(function (nodeId) {
2913
+ if (!fixedNodes.has(nodeId)) yCoords[nodeIndexes.get(nodeId)] = yPos;
2914
+ });
2915
+ };
2916
+
2917
+ for (var _i10 = 0; _i10 < yAlign.length; _i10++) {
2918
+ _loop5(_i10);
2919
+ }
2920
+ }
2921
+ }
2922
+
2923
+ /* finally enforce relative placement constraint */
2924
+
2925
+ if (constraints.relativePlacementConstraint) {
2926
+ (function () {
2927
+ var nodeToDummyForVerticalAlignment = new Map();
2928
+ var nodeToDummyForHorizontalAlignment = new Map();
2929
+ var dummyToNodeForVerticalAlignment = new Map();
2930
+ var dummyToNodeForHorizontalAlignment = new Map();
2931
+ var dummyPositionsForVerticalAlignment = new Map();
2932
+ var dummyPositionsForHorizontalAlignment = new Map();
2933
+ var fixedNodesOnHorizontal = new Set();
2934
+ var fixedNodesOnVertical = new Set();
2935
+
2936
+ // fill maps and sets
2937
+ fixedNodes.forEach(function (nodeId) {
2938
+ fixedNodesOnHorizontal.add(nodeId);
2939
+ fixedNodesOnVertical.add(nodeId);
2940
+ });
2941
+
2942
+ if (constraints.alignmentConstraint) {
2943
+ if (constraints.alignmentConstraint.vertical) {
2944
+ var verticalAlignment = constraints.alignmentConstraint.vertical;
2945
+
2946
+ var _loop6 = function _loop6(_i11) {
2947
+ dummyToNodeForVerticalAlignment.set("dummy" + _i11, []);
2948
+ verticalAlignment[_i11].forEach(function (nodeId) {
2949
+ nodeToDummyForVerticalAlignment.set(nodeId, "dummy" + _i11);
2950
+ dummyToNodeForVerticalAlignment.get("dummy" + _i11).push(nodeId);
2951
+ if (fixedNodes.has(nodeId)) {
2952
+ fixedNodesOnHorizontal.add("dummy" + _i11);
2953
+ }
2954
+ });
2955
+ dummyPositionsForVerticalAlignment.set("dummy" + _i11, xCoords[nodeIndexes.get(verticalAlignment[_i11][0])]);
2956
+ };
2957
+
2958
+ for (var _i11 = 0; _i11 < verticalAlignment.length; _i11++) {
2959
+ _loop6(_i11);
2960
+ }
2961
+ }
2962
+ if (constraints.alignmentConstraint.horizontal) {
2963
+ var horizontalAlignment = constraints.alignmentConstraint.horizontal;
2964
+
2965
+ var _loop7 = function _loop7(_i12) {
2966
+ dummyToNodeForHorizontalAlignment.set("dummy" + _i12, []);
2967
+ horizontalAlignment[_i12].forEach(function (nodeId) {
2968
+ nodeToDummyForHorizontalAlignment.set(nodeId, "dummy" + _i12);
2969
+ dummyToNodeForHorizontalAlignment.get("dummy" + _i12).push(nodeId);
2970
+ if (fixedNodes.has(nodeId)) {
2971
+ fixedNodesOnVertical.add("dummy" + _i12);
2972
+ }
2973
+ });
2974
+ dummyPositionsForHorizontalAlignment.set("dummy" + _i12, yCoords[nodeIndexes.get(horizontalAlignment[_i12][0])]);
2975
+ };
2976
+
2977
+ for (var _i12 = 0; _i12 < horizontalAlignment.length; _i12++) {
2978
+ _loop7(_i12);
2979
+ }
2980
+ }
2981
+ }
2982
+
2983
+ // construct horizontal and vertical dags (subgraphs) from overall dag
2984
+ var dagOnHorizontal = new Map();
2985
+ var dagOnVertical = new Map();
2986
+
2987
+ var _loop8 = function _loop8(nodeId) {
2988
+ dag.get(nodeId).forEach(function (adjacent) {
2989
+ var sourceId = void 0;
2990
+ var targetNode = void 0;
2991
+ if (adjacent["direction"] == "horizontal") {
2992
+ sourceId = nodeToDummyForVerticalAlignment.get(nodeId) ? nodeToDummyForVerticalAlignment.get(nodeId) : nodeId;
2993
+ if (nodeToDummyForVerticalAlignment.get(adjacent.id)) {
2994
+ targetNode = { id: nodeToDummyForVerticalAlignment.get(adjacent.id), gap: adjacent.gap, direction: adjacent.direction };
2995
+ } else {
2996
+ targetNode = adjacent;
2997
+ }
2998
+ if (dagOnHorizontal.has(sourceId)) {
2999
+ dagOnHorizontal.get(sourceId).push(targetNode);
3000
+ } else {
3001
+ dagOnHorizontal.set(sourceId, [targetNode]);
3002
+ }
3003
+ if (!dagOnHorizontal.has(targetNode.id)) {
3004
+ dagOnHorizontal.set(targetNode.id, []);
3005
+ }
3006
+ } else {
3007
+ sourceId = nodeToDummyForHorizontalAlignment.get(nodeId) ? nodeToDummyForHorizontalAlignment.get(nodeId) : nodeId;
3008
+ if (nodeToDummyForHorizontalAlignment.get(adjacent.id)) {
3009
+ targetNode = { id: nodeToDummyForHorizontalAlignment.get(adjacent.id), gap: adjacent.gap, direction: adjacent.direction };
3010
+ } else {
3011
+ targetNode = adjacent;
3012
+ }
3013
+ if (dagOnVertical.has(sourceId)) {
3014
+ dagOnVertical.get(sourceId).push(targetNode);
3015
+ } else {
3016
+ dagOnVertical.set(sourceId, [targetNode]);
3017
+ }
3018
+ if (!dagOnVertical.has(targetNode.id)) {
3019
+ dagOnVertical.set(targetNode.id, []);
3020
+ }
3021
+ }
3022
+ });
3023
+ };
3024
+
3025
+ var _iteratorNormalCompletion5 = true;
3026
+ var _didIteratorError5 = false;
3027
+ var _iteratorError5 = undefined;
3028
+
3029
+ try {
3030
+ for (var _iterator5 = dag.keys()[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
3031
+ var nodeId = _step5.value;
3032
+
3033
+ _loop8(nodeId);
3034
+ }
3035
+
3036
+ // find source nodes of each component in horizontal and vertical dags
3037
+ } catch (err) {
3038
+ _didIteratorError5 = true;
3039
+ _iteratorError5 = err;
3040
+ } finally {
3041
+ try {
3042
+ if (!_iteratorNormalCompletion5 && _iterator5.return) {
3043
+ _iterator5.return();
3044
+ }
3045
+ } finally {
3046
+ if (_didIteratorError5) {
3047
+ throw _iteratorError5;
3048
+ }
3049
+ }
3050
+ }
3051
+
3052
+ var undirectedOnHorizontal = dagToUndirected(dagOnHorizontal);
3053
+ var undirectedOnVertical = dagToUndirected(dagOnVertical);
3054
+ var componentsOnHorizontal = findComponents(undirectedOnHorizontal);
3055
+ var componentsOnVertical = findComponents(undirectedOnVertical);
3056
+ var reversedDagOnHorizontal = dagToReversed(dagOnHorizontal);
3057
+ var reversedDagOnVertical = dagToReversed(dagOnVertical);
3058
+ var componentSourcesOnHorizontal = [];
3059
+ var componentSourcesOnVertical = [];
3060
+
3061
+ componentsOnHorizontal.forEach(function (component, index) {
3062
+ componentSourcesOnHorizontal[index] = [];
3063
+ component.forEach(function (nodeId) {
3064
+ if (reversedDagOnHorizontal.get(nodeId).length == 0) {
3065
+ componentSourcesOnHorizontal[index].push(nodeId);
3066
+ }
3067
+ });
3068
+ });
3069
+
3070
+ componentsOnVertical.forEach(function (component, index) {
3071
+ componentSourcesOnVertical[index] = [];
3072
+ component.forEach(function (nodeId) {
3073
+ if (reversedDagOnVertical.get(nodeId).length == 0) {
3074
+ componentSourcesOnVertical[index].push(nodeId);
3075
+ }
3076
+ });
3077
+ });
3078
+
3079
+ // calculate appropriate positioning for subgraphs
3080
+ var positionMapHorizontal = findAppropriatePositionForRelativePlacement(dagOnHorizontal, "horizontal", fixedNodesOnHorizontal, dummyPositionsForVerticalAlignment, componentSourcesOnHorizontal);
3081
+ var positionMapVertical = findAppropriatePositionForRelativePlacement(dagOnVertical, "vertical", fixedNodesOnVertical, dummyPositionsForHorizontalAlignment, componentSourcesOnVertical);
3082
+
3083
+ // update positions of the nodes based on relative placement constraints
3084
+
3085
+ var _loop9 = function _loop9(key) {
3086
+ if (dummyToNodeForVerticalAlignment.get(key)) {
3087
+ dummyToNodeForVerticalAlignment.get(key).forEach(function (nodeId) {
3088
+ xCoords[nodeIndexes.get(nodeId)] = positionMapHorizontal.get(key);
3089
+ });
3090
+ } else {
3091
+ xCoords[nodeIndexes.get(key)] = positionMapHorizontal.get(key);
3092
+ }
3093
+ };
3094
+
3095
+ var _iteratorNormalCompletion6 = true;
3096
+ var _didIteratorError6 = false;
3097
+ var _iteratorError6 = undefined;
3098
+
3099
+ try {
3100
+ for (var _iterator6 = positionMapHorizontal.keys()[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
3101
+ var key = _step6.value;
3102
+
3103
+ _loop9(key);
3104
+ }
3105
+ } catch (err) {
3106
+ _didIteratorError6 = true;
3107
+ _iteratorError6 = err;
3108
+ } finally {
3109
+ try {
3110
+ if (!_iteratorNormalCompletion6 && _iterator6.return) {
3111
+ _iterator6.return();
3112
+ }
3113
+ } finally {
3114
+ if (_didIteratorError6) {
3115
+ throw _iteratorError6;
3116
+ }
3117
+ }
3118
+ }
3119
+
3120
+ var _loop10 = function _loop10(key) {
3121
+ if (dummyToNodeForHorizontalAlignment.get(key)) {
3122
+ dummyToNodeForHorizontalAlignment.get(key).forEach(function (nodeId) {
3123
+ yCoords[nodeIndexes.get(nodeId)] = positionMapVertical.get(key);
3124
+ });
3125
+ } else {
3126
+ yCoords[nodeIndexes.get(key)] = positionMapVertical.get(key);
3127
+ }
3128
+ };
3129
+
3130
+ var _iteratorNormalCompletion7 = true;
3131
+ var _didIteratorError7 = false;
3132
+ var _iteratorError7 = undefined;
3133
+
3134
+ try {
3135
+ for (var _iterator7 = positionMapVertical.keys()[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
3136
+ var key = _step7.value;
3137
+
3138
+ _loop10(key);
3139
+ }
3140
+ } catch (err) {
3141
+ _didIteratorError7 = true;
3142
+ _iteratorError7 = err;
3143
+ } finally {
3144
+ try {
3145
+ if (!_iteratorNormalCompletion7 && _iterator7.return) {
3146
+ _iterator7.return();
3147
+ }
3148
+ } finally {
3149
+ if (_didIteratorError7) {
3150
+ throw _iteratorError7;
3151
+ }
3152
+ }
3153
+ }
3154
+ })();
3155
+ }
3156
+ }
3157
+
3158
+ // assign new coordinates to nodes after constraint handling
3159
+ for (var _i13 = 0; _i13 < allNodes.length; _i13++) {
3160
+ var _node = allNodes[_i13];
3161
+ if (_node.getChild() == null) {
3162
+ _node.setCenter(xCoords[nodeIndexes.get(_node.id)], yCoords[nodeIndexes.get(_node.id)]);
3163
+ }
3164
+ }
3165
+ };
3166
+
3167
+ module.exports = ConstraintHandler;
3168
+
3169
+ /***/ }),
3170
+
3171
+ /***/ 551:
3172
+ /***/ ((module) => {
3173
+
3174
+ module.exports = __WEBPACK_EXTERNAL_MODULE__551__;
3175
+
3176
+ /***/ })
3177
+
3178
+ /******/ });
3179
+ /************************************************************************/
3180
+ /******/ // The module cache
3181
+ /******/ var __webpack_module_cache__ = {};
3182
+ /******/
3183
+ /******/ // The require function
3184
+ /******/ function __webpack_require__(moduleId) {
3185
+ /******/ // Check if module is in cache
3186
+ /******/ var cachedModule = __webpack_module_cache__[moduleId];
3187
+ /******/ if (cachedModule !== undefined) {
3188
+ /******/ return cachedModule.exports;
3189
+ /******/ }
3190
+ /******/ // Create a new module (and put it into the cache)
3191
+ /******/ var module = __webpack_module_cache__[moduleId] = {
3192
+ /******/ // no module.id needed
3193
+ /******/ // no module.loaded needed
3194
+ /******/ exports: {}
3195
+ /******/ };
3196
+ /******/
3197
+ /******/ // Execute the module function
3198
+ /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
3199
+ /******/
3200
+ /******/ // Return the exports of the module
3201
+ /******/ return module.exports;
3202
+ /******/ }
3203
+ /******/
3204
+ /************************************************************************/
3205
+ /******/
3206
+ /******/ // startup
3207
+ /******/ // Load entry module and return exports
3208
+ /******/ // This entry module is referenced by other modules so it can't be inlined
3209
+ /******/ var __webpack_exports__ = __webpack_require__(45);
3210
+ /******/
3211
+ /******/ return __webpack_exports__;
3212
+ /******/ })()
3213
+ ;
3214
+ });