vis-rails 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +5 -13
  2. data/lib/vis/rails/version.rb +1 -1
  3. data/vendor/assets/component/emitter.js +162 -0
  4. data/vendor/assets/javascripts/vis.js +1 -0
  5. data/vendor/assets/vis/DataSet.js +8 -2
  6. data/vendor/assets/vis/DataView.js +8 -4
  7. data/vendor/assets/vis/graph/Edge.js +210 -78
  8. data/vendor/assets/vis/graph/Graph.js +474 -652
  9. data/vendor/assets/vis/graph/Node.js +119 -82
  10. data/vendor/assets/vis/graph/css/graph-manipulation.css +128 -0
  11. data/vendor/assets/vis/graph/css/graph-navigation.css +62 -0
  12. data/vendor/assets/vis/graph/graphMixins/ClusterMixin.js +1141 -0
  13. data/vendor/assets/vis/graph/graphMixins/HierarchicalLayoutMixin.js +296 -0
  14. data/vendor/assets/vis/graph/graphMixins/ManipulationMixin.js +433 -0
  15. data/vendor/assets/vis/graph/graphMixins/MixinLoader.js +201 -0
  16. data/vendor/assets/vis/graph/graphMixins/NavigationMixin.js +173 -0
  17. data/vendor/assets/vis/graph/graphMixins/SectorsMixin.js +552 -0
  18. data/vendor/assets/vis/graph/graphMixins/SelectionMixin.js +558 -0
  19. data/vendor/assets/vis/graph/graphMixins/physics/BarnesHut.js +373 -0
  20. data/vendor/assets/vis/graph/graphMixins/physics/HierarchialRepulsion.js +64 -0
  21. data/vendor/assets/vis/graph/graphMixins/physics/PhysicsMixin.js +513 -0
  22. data/vendor/assets/vis/graph/graphMixins/physics/Repulsion.js +66 -0
  23. data/vendor/assets/vis/graph/img/acceptDeleteIcon.png +0 -0
  24. data/vendor/assets/vis/graph/img/addNodeIcon.png +0 -0
  25. data/vendor/assets/vis/graph/img/backIcon.png +0 -0
  26. data/vendor/assets/vis/graph/img/connectIcon.png +0 -0
  27. data/vendor/assets/vis/graph/img/cross.png +0 -0
  28. data/vendor/assets/vis/graph/img/cross2.png +0 -0
  29. data/vendor/assets/vis/graph/img/deleteIcon.png +0 -0
  30. data/vendor/assets/vis/graph/img/downArrow.png +0 -0
  31. data/vendor/assets/vis/graph/img/editIcon.png +0 -0
  32. data/vendor/assets/vis/graph/img/leftArrow.png +0 -0
  33. data/vendor/assets/vis/graph/img/rightArrow.png +0 -0
  34. data/vendor/assets/vis/graph/img/upArrow.png +0 -0
  35. data/vendor/assets/vis/module/exports.js +0 -2
  36. data/vendor/assets/vis/module/header.js +2 -2
  37. data/vendor/assets/vis/module/imports.js +1 -2
  38. data/vendor/assets/vis/timeline/Controller.js +56 -45
  39. data/vendor/assets/vis/timeline/Range.js +68 -62
  40. data/vendor/assets/vis/timeline/Stack.js +11 -13
  41. data/vendor/assets/vis/timeline/TimeStep.js +43 -38
  42. data/vendor/assets/vis/timeline/Timeline.js +215 -93
  43. data/vendor/assets/vis/timeline/component/Component.js +19 -3
  44. data/vendor/assets/vis/timeline/component/CurrentTime.js +1 -1
  45. data/vendor/assets/vis/timeline/component/CustomTime.js +39 -120
  46. data/vendor/assets/vis/timeline/component/GroupSet.js +35 -1
  47. data/vendor/assets/vis/timeline/component/ItemSet.js +272 -9
  48. data/vendor/assets/vis/timeline/component/RootPanel.js +59 -47
  49. data/vendor/assets/vis/timeline/component/TimeAxis.js +10 -0
  50. data/vendor/assets/vis/timeline/component/css/item.css +53 -22
  51. data/vendor/assets/vis/timeline/component/item/Item.js +40 -5
  52. data/vendor/assets/vis/timeline/component/item/ItemBox.js +3 -1
  53. data/vendor/assets/vis/timeline/component/item/ItemPoint.js +3 -1
  54. data/vendor/assets/vis/timeline/component/item/ItemRange.js +67 -3
  55. data/vendor/assets/vis/timeline/component/item/ItemRangeOverflow.js +37 -9
  56. data/vendor/assets/vis/timeline/img/delete.png +0 -0
  57. data/vendor/assets/vis/util.js +169 -30
  58. metadata +39 -12
@@ -0,0 +1,373 @@
1
+ /**
2
+ * Created by Alex on 2/10/14.
3
+ */
4
+
5
+ var barnesHutMixin = {
6
+
7
+ /**
8
+ * This function calculates the forces the nodes apply on eachother based on a gravitational model.
9
+ * The Barnes Hut method is used to speed up this N-body simulation.
10
+ *
11
+ * @private
12
+ */
13
+ _calculateNodeForces : function() {
14
+ var node;
15
+ var nodes = this.calculationNodes;
16
+ var nodeIndices = this.calculationNodeIndices;
17
+ var nodeCount = nodeIndices.length;
18
+
19
+ this._formBarnesHutTree(nodes,nodeIndices);
20
+
21
+ var barnesHutTree = this.barnesHutTree;
22
+
23
+ // place the nodes one by one recursively
24
+ for (var i = 0; i < nodeCount; i++) {
25
+ node = nodes[nodeIndices[i]];
26
+ // starting with root is irrelevant, it never passes the BarnesHut condition
27
+ this._getForceContribution(barnesHutTree.root.children.NW,node);
28
+ this._getForceContribution(barnesHutTree.root.children.NE,node);
29
+ this._getForceContribution(barnesHutTree.root.children.SW,node);
30
+ this._getForceContribution(barnesHutTree.root.children.SE,node);
31
+ }
32
+ },
33
+
34
+
35
+ /**
36
+ * This function traverses the barnesHutTree. It checks when it can approximate distant nodes with their center of mass.
37
+ * If a region contains a single node, we check if it is not itself, then we apply the force.
38
+ *
39
+ * @param parentBranch
40
+ * @param node
41
+ * @private
42
+ */
43
+ _getForceContribution : function(parentBranch,node) {
44
+ // we get no force contribution from an empty region
45
+ if (parentBranch.childrenCount > 0) {
46
+ var dx,dy,distance;
47
+
48
+ // get the distance from the center of mass to the node.
49
+ dx = parentBranch.centerOfMass.x - node.x;
50
+ dy = parentBranch.centerOfMass.y - node.y;
51
+ distance = Math.sqrt(dx * dx + dy * dy);
52
+
53
+ // BarnesHut condition
54
+ // original condition : s/d < theta = passed === d/s > 1/theta = passed
55
+ // calcSize = 1/s --> d * 1/s > 1/theta = passed
56
+ if (distance * parentBranch.calcSize > this.constants.physics.barnesHut.theta) {
57
+ // duplicate code to reduce function calls to speed up program
58
+ if (distance == 0) {
59
+ distance = 0.1*Math.random();
60
+ dx = distance;
61
+ }
62
+ var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.mass / (distance * distance * distance);
63
+ var fx = dx * gravityForce;
64
+ var fy = dy * gravityForce;
65
+ node.fx += fx;
66
+ node.fy += fy;
67
+ }
68
+ else {
69
+ // Did not pass the condition, go into children if available
70
+ if (parentBranch.childrenCount == 4) {
71
+ this._getForceContribution(parentBranch.children.NW,node);
72
+ this._getForceContribution(parentBranch.children.NE,node);
73
+ this._getForceContribution(parentBranch.children.SW,node);
74
+ this._getForceContribution(parentBranch.children.SE,node);
75
+ }
76
+ else { // parentBranch must have only one node, if it was empty we wouldnt be here
77
+ if (parentBranch.children.data.id != node.id) { // if it is not self
78
+ // duplicate code to reduce function calls to speed up program
79
+ if (distance == 0) {
80
+ distance = 0.5*Math.random();
81
+ dx = distance;
82
+ }
83
+ var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.mass / (distance * distance * distance);
84
+ var fx = dx * gravityForce;
85
+ var fy = dy * gravityForce;
86
+ node.fx += fx;
87
+ node.fy += fy;
88
+ }
89
+ }
90
+ }
91
+ }
92
+ },
93
+
94
+ /**
95
+ * This function constructs the barnesHut tree recursively. It creates the root, splits it and starts placing the nodes.
96
+ *
97
+ * @param nodes
98
+ * @param nodeIndices
99
+ * @private
100
+ */
101
+ _formBarnesHutTree : function(nodes,nodeIndices) {
102
+ var node;
103
+ var nodeCount = nodeIndices.length;
104
+
105
+ var minX = Number.MAX_VALUE,
106
+ minY = Number.MAX_VALUE,
107
+ maxX =-Number.MAX_VALUE,
108
+ maxY =-Number.MAX_VALUE;
109
+
110
+ // get the range of the nodes
111
+ for (var i = 0; i < nodeCount; i++) {
112
+ var x = nodes[nodeIndices[i]].x;
113
+ var y = nodes[nodeIndices[i]].y;
114
+ if (x < minX) { minX = x; }
115
+ if (x > maxX) { maxX = x; }
116
+ if (y < minY) { minY = y; }
117
+ if (y > maxY) { maxY = y; }
118
+ }
119
+ // make the range a square
120
+ var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y
121
+ if (sizeDiff > 0) {minY -= 0.5 * sizeDiff; maxY += 0.5 * sizeDiff;} // xSize > ySize
122
+ else {minX += 0.5 * sizeDiff; maxX -= 0.5 * sizeDiff;} // xSize < ySize
123
+
124
+
125
+ var minimumTreeSize = 1e-5;
126
+ var rootSize = Math.max(minimumTreeSize,Math.abs(maxX - minX));
127
+ var halfRootSize = 0.5 * rootSize;
128
+ var centerX = 0.5 * (minX + maxX), centerY = 0.5 * (minY + maxY);
129
+
130
+ // construct the barnesHutTree
131
+ var barnesHutTree = {root:{
132
+ centerOfMass:{x:0,y:0}, // Center of Mass
133
+ mass:0,
134
+ range: {minX:centerX-halfRootSize,maxX:centerX+halfRootSize,
135
+ minY:centerY-halfRootSize,maxY:centerY+halfRootSize},
136
+ size: rootSize,
137
+ calcSize: 1 / rootSize,
138
+ children: {data:null},
139
+ maxWidth: 0,
140
+ level: 0,
141
+ childrenCount: 4
142
+ }};
143
+ this._splitBranch(barnesHutTree.root);
144
+
145
+ // place the nodes one by one recursively
146
+ for (i = 0; i < nodeCount; i++) {
147
+ node = nodes[nodeIndices[i]];
148
+ this._placeInTree(barnesHutTree.root,node);
149
+ }
150
+
151
+ // make global
152
+ this.barnesHutTree = barnesHutTree
153
+ },
154
+
155
+
156
+ _updateBranchMass : function(parentBranch, node) {
157
+ var totalMass = parentBranch.mass + node.mass;
158
+ var totalMassInv = 1/totalMass;
159
+
160
+ parentBranch.centerOfMass.x = parentBranch.centerOfMass.x * parentBranch.mass + node.x * node.mass;
161
+ parentBranch.centerOfMass.x *= totalMassInv;
162
+
163
+ parentBranch.centerOfMass.y = parentBranch.centerOfMass.y * parentBranch.mass + node.y * node.mass;
164
+ parentBranch.centerOfMass.y *= totalMassInv;
165
+
166
+ parentBranch.mass = totalMass;
167
+ var biggestSize = Math.max(Math.max(node.height,node.radius),node.width);
168
+ parentBranch.maxWidth = (parentBranch.maxWidth < biggestSize) ? biggestSize : parentBranch.maxWidth;
169
+
170
+ },
171
+
172
+
173
+ _placeInTree : function(parentBranch,node,skipMassUpdate) {
174
+ if (skipMassUpdate != true || skipMassUpdate === undefined) {
175
+ // update the mass of the branch.
176
+ this._updateBranchMass(parentBranch,node);
177
+ }
178
+
179
+ if (parentBranch.children.NW.range.maxX > node.x) { // in NW or SW
180
+ if (parentBranch.children.NW.range.maxY > node.y) { // in NW
181
+ this._placeInRegion(parentBranch,node,"NW");
182
+ }
183
+ else { // in SW
184
+ this._placeInRegion(parentBranch,node,"SW");
185
+ }
186
+ }
187
+ else { // in NE or SE
188
+ if (parentBranch.children.NW.range.maxY > node.y) { // in NE
189
+ this._placeInRegion(parentBranch,node,"NE");
190
+ }
191
+ else { // in SE
192
+ this._placeInRegion(parentBranch,node,"SE");
193
+ }
194
+ }
195
+ },
196
+
197
+
198
+ _placeInRegion : function(parentBranch,node,region) {
199
+ switch (parentBranch.children[region].childrenCount) {
200
+ case 0: // place node here
201
+ parentBranch.children[region].children.data = node;
202
+ parentBranch.children[region].childrenCount = 1;
203
+ this._updateBranchMass(parentBranch.children[region],node);
204
+ break;
205
+ case 1: // convert into children
206
+ // if there are two nodes exactly overlapping (on init, on opening of cluster etc.)
207
+ // we move one node a pixel and we do not put it in the tree.
208
+ if (parentBranch.children[region].children.data.x == node.x &&
209
+ parentBranch.children[region].children.data.y == node.y) {
210
+ node.x += Math.random();
211
+ node.y += Math.random();
212
+ this._placeInTree(parentBranch,node, true);
213
+ }
214
+ else {
215
+ this._splitBranch(parentBranch.children[region]);
216
+ this._placeInTree(parentBranch.children[region],node);
217
+ }
218
+ break;
219
+ case 4: // place in branch
220
+ this._placeInTree(parentBranch.children[region],node);
221
+ break;
222
+ }
223
+ },
224
+
225
+
226
+ /**
227
+ * this function splits a branch into 4 sub branches. If the branch contained a node, we place it in the subbranch
228
+ * after the split is complete.
229
+ *
230
+ * @param parentBranch
231
+ * @private
232
+ */
233
+ _splitBranch : function(parentBranch) {
234
+ // if the branch is filled with a node, replace the node in the new subset.
235
+ var containedNode = null;
236
+ if (parentBranch.childrenCount == 1) {
237
+ containedNode = parentBranch.children.data;
238
+ parentBranch.mass = 0; parentBranch.centerOfMass.x = 0; parentBranch.centerOfMass.y = 0;
239
+ }
240
+ parentBranch.childrenCount = 4;
241
+ parentBranch.children.data = null;
242
+ this._insertRegion(parentBranch,"NW");
243
+ this._insertRegion(parentBranch,"NE");
244
+ this._insertRegion(parentBranch,"SW");
245
+ this._insertRegion(parentBranch,"SE");
246
+
247
+ if (containedNode != null) {
248
+ this._placeInTree(parentBranch,containedNode);
249
+ }
250
+ },
251
+
252
+
253
+ /**
254
+ * This function subdivides the region into four new segments.
255
+ * Specifically, this inserts a single new segment.
256
+ * It fills the children section of the parentBranch
257
+ *
258
+ * @param parentBranch
259
+ * @param region
260
+ * @param parentRange
261
+ * @private
262
+ */
263
+ _insertRegion : function(parentBranch, region) {
264
+ var minX,maxX,minY,maxY;
265
+ var childSize = 0.5 * parentBranch.size;
266
+ switch (region) {
267
+ case "NW":
268
+ minX = parentBranch.range.minX;
269
+ maxX = parentBranch.range.minX + childSize;
270
+ minY = parentBranch.range.minY;
271
+ maxY = parentBranch.range.minY + childSize;
272
+ break;
273
+ case "NE":
274
+ minX = parentBranch.range.minX + childSize;
275
+ maxX = parentBranch.range.maxX;
276
+ minY = parentBranch.range.minY;
277
+ maxY = parentBranch.range.minY + childSize;
278
+ break;
279
+ case "SW":
280
+ minX = parentBranch.range.minX;
281
+ maxX = parentBranch.range.minX + childSize;
282
+ minY = parentBranch.range.minY + childSize;
283
+ maxY = parentBranch.range.maxY;
284
+ break;
285
+ case "SE":
286
+ minX = parentBranch.range.minX + childSize;
287
+ maxX = parentBranch.range.maxX;
288
+ minY = parentBranch.range.minY + childSize;
289
+ maxY = parentBranch.range.maxY;
290
+ break;
291
+ }
292
+
293
+
294
+ parentBranch.children[region] = {
295
+ centerOfMass:{x:0,y:0},
296
+ mass:0,
297
+ range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY},
298
+ size: 0.5 * parentBranch.size,
299
+ calcSize: 2 * parentBranch.calcSize,
300
+ children: {data:null},
301
+ maxWidth: 0,
302
+ level: parentBranch.level+1,
303
+ childrenCount: 0
304
+ };
305
+ },
306
+
307
+
308
+ /**
309
+ * This function is for debugging purposed, it draws the tree.
310
+ *
311
+ * @param ctx
312
+ * @param color
313
+ * @private
314
+ */
315
+ _drawTree : function(ctx,color) {
316
+ if (this.barnesHutTree !== undefined) {
317
+
318
+ ctx.lineWidth = 1;
319
+
320
+ this._drawBranch(this.barnesHutTree.root,ctx,color);
321
+ }
322
+ },
323
+
324
+
325
+ /**
326
+ * This function is for debugging purposes. It draws the branches recursively.
327
+ *
328
+ * @param branch
329
+ * @param ctx
330
+ * @param color
331
+ * @private
332
+ */
333
+ _drawBranch : function(branch,ctx,color) {
334
+ if (color === undefined) {
335
+ color = "#FF0000";
336
+ }
337
+
338
+ if (branch.childrenCount == 4) {
339
+ this._drawBranch(branch.children.NW,ctx);
340
+ this._drawBranch(branch.children.NE,ctx);
341
+ this._drawBranch(branch.children.SE,ctx);
342
+ this._drawBranch(branch.children.SW,ctx);
343
+ }
344
+ ctx.strokeStyle = color;
345
+ ctx.beginPath();
346
+ ctx.moveTo(branch.range.minX,branch.range.minY);
347
+ ctx.lineTo(branch.range.maxX,branch.range.minY);
348
+ ctx.stroke();
349
+
350
+ ctx.beginPath();
351
+ ctx.moveTo(branch.range.maxX,branch.range.minY);
352
+ ctx.lineTo(branch.range.maxX,branch.range.maxY);
353
+ ctx.stroke();
354
+
355
+ ctx.beginPath();
356
+ ctx.moveTo(branch.range.maxX,branch.range.maxY);
357
+ ctx.lineTo(branch.range.minX,branch.range.maxY);
358
+ ctx.stroke();
359
+
360
+ ctx.beginPath();
361
+ ctx.moveTo(branch.range.minX,branch.range.maxY);
362
+ ctx.lineTo(branch.range.minX,branch.range.minY);
363
+ ctx.stroke();
364
+
365
+ /*
366
+ if (branch.mass > 0) {
367
+ ctx.circle(branch.centerOfMass.x, branch.centerOfMass.y, 3*branch.mass);
368
+ ctx.stroke();
369
+ }
370
+ */
371
+ }
372
+
373
+ };
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Created by Alex on 2/10/14.
3
+ */
4
+
5
+ var hierarchalRepulsionMixin = {
6
+
7
+
8
+ /**
9
+ * Calculate the forces the nodes apply on eachother based on a repulsion field.
10
+ * This field is linearly approximated.
11
+ *
12
+ * @private
13
+ */
14
+ _calculateNodeForces : function() {
15
+ var dx, dy, distance, fx, fy, combinedClusterSize,
16
+ repulsingForce, node1, node2, i, j;
17
+
18
+ var nodes = this.calculationNodes;
19
+ var nodeIndices = this.calculationNodeIndices;
20
+
21
+ // approximation constants
22
+ var b = 5;
23
+ var a_base = 0.5*-b;
24
+
25
+
26
+ // repulsing forces between nodes
27
+ var nodeDistance = this.constants.physics.hierarchicalRepulsion.nodeDistance;
28
+ var minimumDistance = nodeDistance;
29
+
30
+ // we loop from i over all but the last entree in the array
31
+ // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j
32
+ for (i = 0; i < nodeIndices.length-1; i++) {
33
+
34
+ node1 = nodes[nodeIndices[i]];
35
+ for (j = i+1; j < nodeIndices.length; j++) {
36
+ node2 = nodes[nodeIndices[j]];
37
+
38
+ dx = node2.x - node1.x;
39
+ dy = node2.y - node1.y;
40
+ distance = Math.sqrt(dx * dx + dy * dy);
41
+
42
+ var a = a_base / minimumDistance;
43
+ if (distance < 2*minimumDistance) {
44
+ repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness))
45
+
46
+ // normalize force with
47
+ if (distance == 0) {
48
+ distance = 0.01;
49
+ }
50
+ else {
51
+ repulsingForce = repulsingForce/distance;
52
+ }
53
+ fx = dx * repulsingForce;
54
+ fy = dy * repulsingForce;
55
+
56
+ node1.fx -= fx;
57
+ node1.fy -= fy;
58
+ node2.fx += fx;
59
+ node2.fy += fy;
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,513 @@
1
+ /**
2
+ * Created by Alex on 2/6/14.
3
+ */
4
+
5
+
6
+ var physicsMixin = {
7
+
8
+ /**
9
+ * Toggling barnes Hut calculation on and off.
10
+ *
11
+ * @private
12
+ */
13
+ _toggleBarnesHut : function() {
14
+ this.constants.physics.barnesHut.enabled = !this.constants.physics.barnesHut.enabled;
15
+ this._loadSelectedForceSolver();
16
+ this.moving = true;
17
+ this.start();
18
+ },
19
+
20
+
21
+
22
+ /**
23
+ * This loads the node force solver based on the barnes hut or repulsion algorithm
24
+ *
25
+ * @private
26
+ */
27
+ _loadSelectedForceSolver : function() {
28
+ // this overloads the this._calculateNodeForces
29
+ if (this.constants.physics.barnesHut.enabled == true) {
30
+ this._clearMixin(repulsionMixin);
31
+ this._clearMixin(hierarchalRepulsionMixin);
32
+
33
+ this.constants.physics.centralGravity = this.constants.physics.barnesHut.centralGravity;
34
+ this.constants.physics.springLength = this.constants.physics.barnesHut.springLength;
35
+ this.constants.physics.springConstant = this.constants.physics.barnesHut.springConstant;
36
+ this.constants.physics.damping = this.constants.physics.barnesHut.damping;
37
+
38
+ this._loadMixin(barnesHutMixin);
39
+ }
40
+ else if (this.constants.physics.hierarchicalRepulsion.enabled == true) {
41
+ this._clearMixin(barnesHutMixin);
42
+ this._clearMixin(repulsionMixin);
43
+
44
+ this.constants.physics.centralGravity = this.constants.physics.hierarchicalRepulsion.centralGravity;
45
+ this.constants.physics.springLength = this.constants.physics.hierarchicalRepulsion.springLength;
46
+ this.constants.physics.springConstant = this.constants.physics.hierarchicalRepulsion.springConstant;
47
+ this.constants.physics.damping = this.constants.physics.hierarchicalRepulsion.damping;
48
+
49
+ this._loadMixin(hierarchalRepulsionMixin);
50
+ }
51
+ else {
52
+ this._clearMixin(barnesHutMixin);
53
+ this._clearMixin(hierarchalRepulsionMixin);
54
+ this.barnesHutTree = undefined;
55
+
56
+ this.constants.physics.centralGravity = this.constants.physics.repulsion.centralGravity;
57
+ this.constants.physics.springLength = this.constants.physics.repulsion.springLength;
58
+ this.constants.physics.springConstant = this.constants.physics.repulsion.springConstant;
59
+ this.constants.physics.damping = this.constants.physics.repulsion.damping;
60
+
61
+ this._loadMixin(repulsionMixin);
62
+ }
63
+ },
64
+
65
+ /**
66
+ * Before calculating the forces, we check if we need to cluster to keep up performance and we check
67
+ * if there is more than one node. If it is just one node, we dont calculate anything.
68
+ *
69
+ * @private
70
+ */
71
+ _initializeForceCalculation : function() {
72
+ // stop calculation if there is only one node
73
+ if (this.nodeIndices.length == 1) {
74
+ this.nodes[this.nodeIndices[0]]._setForce(0,0);
75
+ }
76
+ else {
77
+ // if there are too many nodes on screen, we cluster without repositioning
78
+ if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) {
79
+ this.clusterToFit(this.constants.clustering.reduceToNodes, false);
80
+ }
81
+
82
+ // we now start the force calculation
83
+ this._calculateForces();
84
+ }
85
+ },
86
+
87
+
88
+ /**
89
+ * Calculate the external forces acting on the nodes
90
+ * Forces are caused by: edges, repulsing forces between nodes, gravity
91
+ * @private
92
+ */
93
+ _calculateForces : function() {
94
+ // Gravity is required to keep separated groups from floating off
95
+ // the forces are reset to zero in this loop by using _setForce instead
96
+ // of _addForce
97
+
98
+ this._calculateGravitationalForces();
99
+ this._calculateNodeForces();
100
+
101
+
102
+ if (this.constants.smoothCurves == true) {
103
+ this._calculateSpringForcesWithSupport();
104
+ }
105
+ else {
106
+ this._calculateSpringForces();
107
+ }
108
+ },
109
+
110
+
111
+ /**
112
+ * Smooth curves are created by adding invisible nodes in the center of the edges. These nodes are also
113
+ * handled in the calculateForces function. We then use a quadratic curve with the center node as control.
114
+ * This function joins the datanodes and invisible (called support) nodes into one object.
115
+ * We do this so we do not contaminate this.nodes with the support nodes.
116
+ *
117
+ * @private
118
+ */
119
+ _updateCalculationNodes : function() {
120
+ if (this.constants.smoothCurves == true) {
121
+ this.calculationNodes = {};
122
+ this.calculationNodeIndices = [];
123
+
124
+ for (var nodeId in this.nodes) {
125
+ if (this.nodes.hasOwnProperty(nodeId)) {
126
+ this.calculationNodes[nodeId] = this.nodes[nodeId];
127
+ }
128
+ }
129
+ var supportNodes = this.sectors['support']['nodes'];
130
+ for (var supportNodeId in supportNodes) {
131
+ if (supportNodes.hasOwnProperty(supportNodeId)) {
132
+ if (this.edges.hasOwnProperty(supportNodes[supportNodeId].parentEdgeId)) {
133
+ this.calculationNodes[supportNodeId] = supportNodes[supportNodeId];
134
+ }
135
+ else {
136
+ supportNodes[supportNodeId]._setForce(0,0);
137
+ }
138
+ }
139
+ }
140
+
141
+ for (var idx in this.calculationNodes) {
142
+ if (this.calculationNodes.hasOwnProperty(idx)) {
143
+ this.calculationNodeIndices.push(idx);
144
+ }
145
+ }
146
+ }
147
+ else {
148
+ this.calculationNodes = this.nodes;
149
+ this.calculationNodeIndices = this.nodeIndices;
150
+ }
151
+ },
152
+
153
+
154
+ /**
155
+ * this function applies the central gravity effect to keep groups from floating off
156
+ *
157
+ * @private
158
+ */
159
+ _calculateGravitationalForces : function() {
160
+ var dx, dy, distance, node, i;
161
+ var nodes = this.calculationNodes;
162
+ var gravity = this.constants.physics.centralGravity;
163
+ var gravityForce = 0;
164
+
165
+ for (i = 0; i < this.calculationNodeIndices.length; i++) {
166
+ node = nodes[this.calculationNodeIndices[i]];
167
+ node.damping = this.constants.physics.damping; // possibly add function to alter damping properties of clusters.
168
+ // gravity does not apply when we are in a pocket sector
169
+ if (this._sector() == "default" && gravity != 0) {
170
+ dx = -node.x;
171
+ dy = -node.y;
172
+ distance = Math.sqrt(dx*dx + dy*dy);
173
+ gravityForce = gravity / distance;
174
+
175
+ node.fx = dx * gravityForce;
176
+ node.fy = dy * gravityForce;
177
+ }
178
+ else {
179
+ node.fx = 0;
180
+ node.fy = 0;
181
+ }
182
+ }
183
+ },
184
+
185
+
186
+ /**
187
+ * this function calculates the effects of the springs in the case of unsmooth curves.
188
+ *
189
+ * @private
190
+ */
191
+ _calculateSpringForces : function() {
192
+ var edgeLength, edge, edgeId;
193
+ var dx, dy, fx, fy, springForce, length;
194
+ var edges = this.edges;
195
+
196
+ // forces caused by the edges, modelled as springs
197
+ for (edgeId in edges) {
198
+ if (edges.hasOwnProperty(edgeId)) {
199
+ edge = edges[edgeId];
200
+ if (edge.connected) {
201
+ // only calculate forces if nodes are in the same sector
202
+ if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) {
203
+ edgeLength = edge.customLength ? edge.length : this.constants.physics.springLength;
204
+ // this implies that the edges between big clusters are longer
205
+ edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth;
206
+
207
+ dx = (edge.from.x - edge.to.x);
208
+ dy = (edge.from.y - edge.to.y);
209
+ length = Math.sqrt(dx * dx + dy * dy);
210
+
211
+ if (length == 0) {
212
+ length = 0.01;
213
+ }
214
+
215
+ springForce = this.constants.physics.springConstant * (edgeLength - length) / length;
216
+
217
+ fx = dx * springForce;
218
+ fy = dy * springForce;
219
+
220
+ edge.from.fx += fx;
221
+ edge.from.fy += fy;
222
+ edge.to.fx -= fx;
223
+ edge.to.fy -= fy;
224
+ }
225
+ }
226
+ }
227
+ }
228
+ },
229
+
230
+
231
+ /**
232
+ * This function calculates the springforces on the nodes, accounting for the support nodes.
233
+ *
234
+ * @private
235
+ */
236
+ _calculateSpringForcesWithSupport : function() {
237
+ var edgeLength, edge, edgeId, combinedClusterSize;
238
+ var edges = this.edges;
239
+
240
+ // forces caused by the edges, modelled as springs
241
+ for (edgeId in edges) {
242
+ if (edges.hasOwnProperty(edgeId)) {
243
+ edge = edges[edgeId];
244
+ if (edge.connected) {
245
+ // only calculate forces if nodes are in the same sector
246
+ if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) {
247
+ if (edge.via != null) {
248
+ var node1 = edge.to;
249
+ var node2 = edge.via;
250
+ var node3 = edge.from;
251
+
252
+ edgeLength = edge.customLength ? edge.length : this.constants.physics.springLength;
253
+
254
+ combinedClusterSize = node1.clusterSize + node3.clusterSize - 2;
255
+
256
+ // this implies that the edges between big clusters are longer
257
+ edgeLength += combinedClusterSize * this.constants.clustering.edgeGrowth;
258
+ this._calculateSpringForce(node1,node2,0.5*edgeLength);
259
+ this._calculateSpringForce(node2,node3,0.5*edgeLength);
260
+ }
261
+ }
262
+ }
263
+ }
264
+ }
265
+ },
266
+
267
+
268
+ /**
269
+ * This is the code actually performing the calculation for the function above. It is split out to avoid repetition.
270
+ *
271
+ * @param node1
272
+ * @param node2
273
+ * @param edgeLength
274
+ * @private
275
+ */
276
+ _calculateSpringForce : function(node1,node2,edgeLength) {
277
+ var dx, dy, fx, fy, springForce, length;
278
+
279
+ dx = (node1.x - node2.x);
280
+ dy = (node1.y - node2.y);
281
+ length = Math.sqrt(dx * dx + dy * dy);
282
+
283
+ springForce = this.constants.physics.springConstant * (edgeLength - length) / length;
284
+
285
+ if (length == 0) {
286
+ length = 0.01;
287
+ }
288
+
289
+ fx = dx * springForce;
290
+ fy = dy * springForce;
291
+
292
+ node1.fx += fx;
293
+ node1.fy += fy;
294
+ node2.fx -= fx;
295
+ node2.fy -= fy;
296
+ },
297
+
298
+
299
+ /**
300
+ * Load the HTML for the physics config and bind it
301
+ * @private
302
+ */
303
+ _loadPhysicsConfiguration : function() {
304
+ if (this.physicsConfiguration === undefined) {
305
+ var hierarchicalLayoutDirections = ["LR","RL","UD","DU"];
306
+ this.physicsConfiguration = document.createElement('div');
307
+ this.physicsConfiguration.className = "PhysicsConfiguration";
308
+ this.physicsConfiguration.innerHTML = '' +
309
+ '<table><tr><td><b>Simulation Mode:</b></td></tr>' +
310
+ '<tr>' +
311
+ '<td width="120px"><input type="radio" name="graph_physicsMethod" id="graph_physicsMethod1" value="BH" checked="checked">Barnes Hut</td>' +
312
+ '<td width="120px"><input type="radio" name="graph_physicsMethod" id="graph_physicsMethod2" value="R">Repulsion</td>'+
313
+ '<td width="120px"><input type="radio" name="graph_physicsMethod" id="graph_physicsMethod3" value="H">Hierarchical</td>' +
314
+ '</tr>'+
315
+ '</table>' +
316
+ '<table id="graph_BH_table" style="display:none">'+
317
+ '<tr><td><b>Barnes Hut</b></td></tr>'+
318
+ '<tr>'+
319
+ '<td width="150px">gravitationalConstant</td><td>0</td><td><input type="range" min="500" max="20000" value="' + (-1* this.constants.physics.barnesHut.gravitationalConstant) + '" step="25" style="width:300px" id="graph_BH_gc"></td><td width="50px">-20000</td><td><input value="' + (-1* this.constants.physics.barnesHut.gravitationalConstant) + '" id="graph_BH_gc_value" style="width:60px"></td>'+
320
+ '</tr>'+
321
+ '<tr>'+
322
+ '<td width="150px">centralGravity</td><td>0</td><td><input type="range" min="0" max="3" value="' + this.constants.physics.barnesHut.centralGravity + '" step="0.05" style="width:300px" id="graph_BH_cg"></td><td>3</td><td><input value="' + this.constants.physics.barnesHut.centralGravity + '" id="graph_BH_cg_value" style="width:60px"></td>'+
323
+ '</tr>'+
324
+ '<tr>'+
325
+ '<td width="150px">springLength</td><td>0</td><td><input type="range" min="0" max="500" value="' + this.constants.physics.barnesHut.springLength + '" step="1" style="width:300px" id="graph_BH_sl"></td><td>500</td><td><input value="' + this.constants.physics.barnesHut.springLength + '" id="graph_BH_sl_value" style="width:60px"></td>'+
326
+ '</tr>'+
327
+ '<tr>'+
328
+ '<td width="150px">springConstant</td><td>0</td><td><input type="range" min="0" max="0.5" value="' + this.constants.physics.barnesHut.springConstant + '" step="0.001" style="width:300px" id="graph_BH_sc"></td><td>0.5</td><td><input value="' + this.constants.physics.barnesHut.springConstant + '" id="graph_BH_sc_value" style="width:60px"></td>'+
329
+ '</tr>'+
330
+ '<tr>'+
331
+ '<td width="150px">damping</td><td>0</td><td><input type="range" min="0" max="0.3" value="' + this.constants.physics.barnesHut.damping + '" step="0.005" style="width:300px" id="graph_BH_damp"></td><td>0.3</td><td><input value="' + this.constants.physics.barnesHut.damping + '" id="graph_BH_damp_value" style="width:60px"></td>'+
332
+ '</tr>'+
333
+ '</table>'+
334
+ '<table id="graph_R_table" style="display:none">'+
335
+ '<tr><td><b>Repulsion</b></td></tr>'+
336
+ '<tr>'+
337
+ '<td width="150px">nodeDistance</td><td>0</td><td><input type="range" min="0" max="300" value="' + this.constants.physics.repulsion.nodeDistance + '" step="1" style="width:300px" id="graph_R_nd"></td><td width="50px">300</td><td><input value="' + this.constants.physics.repulsion.nodeDistance + '" id="graph_R_nd_value" style="width:60px"></td>'+
338
+ '</tr>'+
339
+ '<tr>'+
340
+ '<td width="150px">centralGravity</td><td>0</td><td><input type="range" min="0" max="3" value="' + this.constants.physics.repulsion.centralGravity + '" step="0.05" style="width:300px" id="graph_R_cg"></td><td>3</td><td><input value="' + this.constants.physics.repulsion.centralGravity + '" id="graph_R_cg_value" style="width:60px"></td>'+
341
+ '</tr>'+
342
+ '<tr>'+
343
+ '<td width="150px">springLength</td><td>0</td><td><input type="range" min="0" max="500" value="' + this.constants.physics.repulsion.springLength + '" step="1" style="width:300px" id="graph_R_sl"></td><td>500</td><td><input value="' + this.constants.physics.repulsion.springLength + '" id="graph_R_sl_value" style="width:60px"></td>'+
344
+ '</tr>'+
345
+ '<tr>'+
346
+ '<td width="150px">springConstant</td><td>0</td><td><input type="range" min="0" max="0.5" value="' + this.constants.physics.repulsion.springConstant + '" step="0.001" style="width:300px" id="graph_R_sc"></td><td>0.5</td><td><input value="' + this.constants.physics.repulsion.springConstant + '" id="graph_R_sc_value" style="width:60px"></td>'+
347
+ '</tr>'+
348
+ '<tr>'+
349
+ '<td width="150px">damping</td><td>0</td><td><input type="range" min="0" max="0.3" value="' + this.constants.physics.repulsion.damping + '" step="0.005" style="width:300px" id="graph_R_damp"></td><td>0.3</td><td><input value="' + this.constants.physics.repulsion.damping + '" id="graph_R_damp_value" style="width:60px"></td>'+
350
+ '</tr>'+
351
+ '</table>'+
352
+ '<table id="graph_H_table" style="display:none">'+
353
+ '<tr><td width="150"><b>Hierarchical</b></td></tr>'+
354
+ '<tr>'+
355
+ '<td width="150px">nodeDistance</td><td>0</td><td><input type="range" min="0" max="300" value="' + this.constants.physics.hierarchicalRepulsion.nodeDistance + '" step="1" style="width:300px" id="graph_H_nd"></td><td width="50px">300</td><td><input value="' + this.constants.physics.hierarchicalRepulsion.nodeDistance + '" id="graph_H_nd_value" style="width:60px"></td>'+
356
+ '</tr>'+
357
+ '<tr>'+
358
+ '<td width="150px">centralGravity</td><td>0</td><td><input type="range" min="0" max="3" value="' + this.constants.physics.hierarchicalRepulsion.centralGravity + '" step="0.05" style="width:300px" id="graph_H_cg"></td><td>3</td><td><input value="' + this.constants.physics.hierarchicalRepulsion.centralGravity + '" id="graph_H_cg_value" style="width:60px"></td>'+
359
+ '</tr>'+
360
+ '<tr>'+
361
+ '<td width="150px">springLength</td><td>0</td><td><input type="range" min="0" max="500" value="' + this.constants.physics.hierarchicalRepulsion.springLength + '" step="1" style="width:300px" id="graph_H_sl"></td><td>500</td><td><input value="' + this.constants.physics.hierarchicalRepulsion.springLength + '" id="graph_H_sl_value" style="width:60px"></td>'+
362
+ '</tr>'+
363
+ '<tr>'+
364
+ '<td width="150px">springConstant</td><td>0</td><td><input type="range" min="0" max="0.5" value="' + this.constants.physics.hierarchicalRepulsion.springConstant + '" step="0.001" style="width:300px" id="graph_H_sc"></td><td>0.5</td><td><input value="' + this.constants.physics.hierarchicalRepulsion.springConstant + '" id="graph_H_sc_value" style="width:60px"></td>'+
365
+ '</tr>'+
366
+ '<tr>'+
367
+ '<td width="150px">damping</td><td>0</td><td><input type="range" min="0" max="0.3" value="' + this.constants.physics.hierarchicalRepulsion.damping + '" step="0.005" style="width:300px" id="graph_H_damp"></td><td>0.3</td><td><input value="' + this.constants.physics.hierarchicalRepulsion.damping + '" id="graph_H_damp_value" style="width:60px"></td>'+
368
+ '</tr>'+
369
+ '<tr>'+
370
+ '<td width="150px">direction</td><td>1</td><td><input type="range" min="0" max="3" value="' + hierarchicalLayoutDirections.indexOf(this.constants.hierarchicalLayout.direction) + '" step="1" style="width:300px" id="graph_H_direction"></td><td>4</td><td><input value="' + this.constants.hierarchicalLayout.direction + '" id="graph_H_direction_value" style="width:60px"></td>'+
371
+ '</tr>'+
372
+ '<tr>'+
373
+ '<td width="150px">levelSeparation</td><td>1</td><td><input type="range" min="0" max="' + this.constants.hierarchicalLayout.levelSeparation + '" value="150" step="1" style="width:300px" id="graph_H_levsep"></td><td>500</td><td><input value="' + this.constants.hierarchicalLayout.levelSeparation + '" id="graph_H_levsep_value" style="width:60px"></td>'+
374
+ '</tr>'+
375
+ '<tr>'+
376
+ '<td width="150px">nodeSpacing</td><td>1</td><td><input type="range" min="0" max="' + this.constants.hierarchicalLayout.nodeSpacing + '" value="100" step="1" style="width:300px" id="graph_H_nspac"></td><td>500</td><td><input value="' + this.constants.hierarchicalLayout.nodeSpacing + '" id="graph_H_nspac_value" style="width:60px"></td>'+
377
+ '</tr>'+
378
+ '</table>'
379
+ this.containerElement.parentElement.insertBefore(this.physicsConfiguration,this.containerElement);
380
+
381
+
382
+
383
+ var rangeElement;
384
+ rangeElement = document.getElementById('graph_BH_gc');
385
+ rangeElement.onchange = showValueOfRange.bind(this,'graph_BH_gc',-1,"physics_barnesHut_gravitationalConstant");
386
+ rangeElement = document.getElementById('graph_BH_cg');
387
+ rangeElement.onchange = showValueOfRange.bind(this,'graph_BH_cg',1,"physics_centralGravity");
388
+ rangeElement = document.getElementById('graph_BH_sc');
389
+ rangeElement.onchange = showValueOfRange.bind(this,'graph_BH_sc',1,"physics_springConstant");
390
+ rangeElement = document.getElementById('graph_BH_sl');
391
+ rangeElement.onchange = showValueOfRange.bind(this,'graph_BH_sl',1,"physics_springLength");
392
+ rangeElement = document.getElementById('graph_BH_damp');
393
+ rangeElement.onchange = showValueOfRange.bind(this,'graph_BH_damp',1,"physics_damping");
394
+
395
+
396
+ rangeElement = document.getElementById('graph_R_nd');
397
+ rangeElement.onchange = showValueOfRange.bind(this,'graph_R_nd',1,"physics_repulsion_nodeDistance");
398
+ rangeElement = document.getElementById('graph_R_cg');
399
+ rangeElement.onchange = showValueOfRange.bind(this,'graph_R_cg',1,"physics_centralGravity");
400
+ rangeElement = document.getElementById('graph_R_sc');
401
+ rangeElement.onchange = showValueOfRange.bind(this,'graph_R_sc',1,"physics_springConstant");
402
+ rangeElement = document.getElementById('graph_R_sl');
403
+ rangeElement.onchange = showValueOfRange.bind(this,'graph_R_sl',1,"physics_springLength");
404
+ rangeElement = document.getElementById('graph_R_damp');
405
+ rangeElement.onchange = showValueOfRange.bind(this,'graph_R_damp',1,"physics_damping");
406
+
407
+ rangeElement = document.getElementById('graph_H_nd');
408
+ rangeElement.onchange = showValueOfRange.bind(this,'graph_H_nd',1,"physics_hierarchicalRepulsion_nodeDistance");
409
+ rangeElement = document.getElementById('graph_H_cg');
410
+ rangeElement.onchange = showValueOfRange.bind(this,'graph_H_cg',1,"physics_centralGravity");
411
+ rangeElement = document.getElementById('graph_H_sc');
412
+ rangeElement.onchange = showValueOfRange.bind(this,'graph_H_sc',1,"physics_springConstant");
413
+ rangeElement = document.getElementById('graph_H_sl');
414
+ rangeElement.onchange = showValueOfRange.bind(this,'graph_H_sl',1,"physics_springLength");
415
+ rangeElement = document.getElementById('graph_H_damp');
416
+ rangeElement.onchange = showValueOfRange.bind(this,'graph_H_damp',1,"physics_damping");
417
+ rangeElement = document.getElementById('graph_H_direction');
418
+ rangeElement.onchange = showValueOfRange.bind(this,'graph_H_direction',hierarchicalLayoutDirections,"hierarchicalLayout_direction");
419
+ rangeElement = document.getElementById('graph_H_levsep');
420
+ rangeElement.onchange = showValueOfRange.bind(this,'graph_H_levsep',1,"hierarchicalLayout_levelSeparation");
421
+ rangeElement = document.getElementById('graph_H_nspac');
422
+ rangeElement.onchange = showValueOfRange.bind(this,'graph_H_nspac',1,"hierarchicalLayout_nodeSpacing");
423
+
424
+ var radioButton1 = document.getElementById("graph_physicsMethod1");
425
+ var radioButton2 = document.getElementById("graph_physicsMethod2");
426
+ var radioButton3 = document.getElementById("graph_physicsMethod3");
427
+
428
+ radioButton2.checked = true;
429
+ if (this.constants.physics.barnesHut.enabled) {
430
+ radioButton1.checked = true;
431
+ }
432
+ if (this.constants.hierarchicalLayout.enabled) {
433
+ radioButton3.checked = true;
434
+ }
435
+
436
+ switchConfigurations.apply(this);
437
+
438
+ radioButton1.onchange = switchConfigurations.bind(this);
439
+ radioButton2.onchange = switchConfigurations.bind(this);
440
+ radioButton3.onchange = switchConfigurations.bind(this);
441
+ }
442
+ },
443
+
444
+ _overWriteGraphConstants : function(constantsVariableName, value) {
445
+ var nameArray = constantsVariableName.split("_");
446
+ if (nameArray.length == 1) {
447
+ this.constants[nameArray[0]] = value;
448
+ }
449
+ else if (nameArray.length == 2) {
450
+ this.constants[nameArray[0]][nameArray[1]] = value;
451
+ }
452
+ else if (nameArray.length == 3) {
453
+ this.constants[nameArray[0]][nameArray[1]][nameArray[2]] = value;
454
+ }
455
+ }
456
+ }
457
+
458
+
459
+ function switchConfigurations () {
460
+ var ids = ["graph_BH_table","graph_R_table","graph_H_table"]
461
+ var radioButton = document.querySelector('input[name="graph_physicsMethod"]:checked').value;
462
+ var tableId = "graph_" + radioButton + "_table";
463
+ var table = document.getElementById(tableId);
464
+ table.style.display = "block";
465
+ for (var i = 0; i < ids.length; i++) {
466
+ if (ids[i] != tableId) {
467
+ table = document.getElementById(ids[i]);
468
+ table.style.display = "none";
469
+ }
470
+ }
471
+ this._restoreNodes();
472
+ if (radioButton == "R") {
473
+ this.constants.hierarchicalLayout.enabled = false;
474
+ this.constants.physics.hierarchicalRepulsion.enabeled = false;
475
+ this.constants.physics.barnesHut.enabled = false;
476
+ }
477
+ else if (radioButton == "H") {
478
+ this.constants.hierarchicalLayout.enabled = true;
479
+ this.constants.physics.hierarchicalRepulsion.enabeled = true;
480
+ this.constants.physics.barnesHut.enabled = false;
481
+ this._setupHierarchicalLayout();
482
+ }
483
+ else {
484
+ this.constants.hierarchicalLayout.enabled = false;
485
+ this.constants.physics.hierarchicalRepulsion.enabeled = false;
486
+ this.constants.physics.barnesHut.enabled = true;
487
+ }
488
+ this._loadSelectedForceSolver();
489
+ this.moving = true;
490
+ this.start();
491
+ }
492
+
493
+ function showValueOfRange (id,map,constantsVariableName) {
494
+ var valueId = id + "_value";
495
+ var rangeValue = document.getElementById(id).value;
496
+ if (constantsVariableName == "hierarchicalLayout_direction" ||
497
+ constantsVariableName == "hierarchicalLayout_levelSeparation" ||
498
+ constantsVariableName == "hierarchicalLayout_nodeSpacing") {
499
+ this._setupHierarchicalLayout();
500
+ }
501
+
502
+ if (map instanceof Array) {
503
+ document.getElementById(valueId).value = map[parseInt(rangeValue)];
504
+ this._overWriteGraphConstants(constantsVariableName,map[parseInt(rangeValue)]);
505
+ }
506
+ else {
507
+ document.getElementById(valueId).value = map * parseFloat(rangeValue);
508
+ this._overWriteGraphConstants(constantsVariableName,map * parseFloat(rangeValue));
509
+ }
510
+ this.moving = true;
511
+ this.start();
512
+ };
513
+