vis-rails 2.0.0 → 2.0.1

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/lib/vis/rails/version.rb +1 -1
  3. data/vendor/assets/javascripts/vis.js +26 -26
  4. metadata +16 -85
  5. data/vendor/assets/vis/DataSet.js +0 -926
  6. data/vendor/assets/vis/DataView.js +0 -283
  7. data/vendor/assets/vis/graph/Edge.js +0 -957
  8. data/vendor/assets/vis/graph/Graph.js +0 -2291
  9. data/vendor/assets/vis/graph/Groups.js +0 -80
  10. data/vendor/assets/vis/graph/Images.js +0 -41
  11. data/vendor/assets/vis/graph/Node.js +0 -966
  12. data/vendor/assets/vis/graph/Popup.js +0 -132
  13. data/vendor/assets/vis/graph/css/graph-manipulation.css +0 -128
  14. data/vendor/assets/vis/graph/css/graph-navigation.css +0 -66
  15. data/vendor/assets/vis/graph/dotparser.js +0 -829
  16. data/vendor/assets/vis/graph/graphMixins/ClusterMixin.js +0 -1143
  17. data/vendor/assets/vis/graph/graphMixins/HierarchicalLayoutMixin.js +0 -311
  18. data/vendor/assets/vis/graph/graphMixins/ManipulationMixin.js +0 -576
  19. data/vendor/assets/vis/graph/graphMixins/MixinLoader.js +0 -199
  20. data/vendor/assets/vis/graph/graphMixins/NavigationMixin.js +0 -205
  21. data/vendor/assets/vis/graph/graphMixins/SectorsMixin.js +0 -552
  22. data/vendor/assets/vis/graph/graphMixins/SelectionMixin.js +0 -648
  23. data/vendor/assets/vis/graph/graphMixins/physics/BarnesHut.js +0 -398
  24. data/vendor/assets/vis/graph/graphMixins/physics/HierarchialRepulsion.js +0 -64
  25. data/vendor/assets/vis/graph/graphMixins/physics/PhysicsMixin.js +0 -697
  26. data/vendor/assets/vis/graph/graphMixins/physics/Repulsion.js +0 -66
  27. data/vendor/assets/vis/graph/img/acceptDeleteIcon.png +0 -0
  28. data/vendor/assets/vis/graph/img/addNodeIcon.png +0 -0
  29. data/vendor/assets/vis/graph/img/backIcon.png +0 -0
  30. data/vendor/assets/vis/graph/img/connectIcon.png +0 -0
  31. data/vendor/assets/vis/graph/img/cross.png +0 -0
  32. data/vendor/assets/vis/graph/img/cross2.png +0 -0
  33. data/vendor/assets/vis/graph/img/deleteIcon.png +0 -0
  34. data/vendor/assets/vis/graph/img/downArrow.png +0 -0
  35. data/vendor/assets/vis/graph/img/editIcon.png +0 -0
  36. data/vendor/assets/vis/graph/img/leftArrow.png +0 -0
  37. data/vendor/assets/vis/graph/img/minus.png +0 -0
  38. data/vendor/assets/vis/graph/img/plus.png +0 -0
  39. data/vendor/assets/vis/graph/img/rightArrow.png +0 -0
  40. data/vendor/assets/vis/graph/img/upArrow.png +0 -0
  41. data/vendor/assets/vis/graph/img/zoomExtends.png +0 -0
  42. data/vendor/assets/vis/graph/shapes.js +0 -225
  43. data/vendor/assets/vis/graph3d/Graph3d.js +0 -3306
  44. data/vendor/assets/vis/module/exports.js +0 -65
  45. data/vendor/assets/vis/module/header.js +0 -24
  46. data/vendor/assets/vis/module/imports.js +0 -31
  47. data/vendor/assets/vis/shim.js +0 -252
  48. data/vendor/assets/vis/timeline/Range.js +0 -532
  49. data/vendor/assets/vis/timeline/TimeStep.js +0 -466
  50. data/vendor/assets/vis/timeline/Timeline.js +0 -851
  51. data/vendor/assets/vis/timeline/component/Component.js +0 -52
  52. data/vendor/assets/vis/timeline/component/CurrentTime.js +0 -128
  53. data/vendor/assets/vis/timeline/component/CustomTime.js +0 -182
  54. data/vendor/assets/vis/timeline/component/Group.js +0 -470
  55. data/vendor/assets/vis/timeline/component/ItemSet.js +0 -1332
  56. data/vendor/assets/vis/timeline/component/TimeAxis.js +0 -389
  57. data/vendor/assets/vis/timeline/component/css/animation.css +0 -33
  58. data/vendor/assets/vis/timeline/component/css/currenttime.css +0 -5
  59. data/vendor/assets/vis/timeline/component/css/customtime.css +0 -6
  60. data/vendor/assets/vis/timeline/component/css/item.css +0 -107
  61. data/vendor/assets/vis/timeline/component/css/itemset.css +0 -33
  62. data/vendor/assets/vis/timeline/component/css/labelset.css +0 -36
  63. data/vendor/assets/vis/timeline/component/css/panel.css +0 -71
  64. data/vendor/assets/vis/timeline/component/css/timeaxis.css +0 -48
  65. data/vendor/assets/vis/timeline/component/css/timeline.css +0 -2
  66. data/vendor/assets/vis/timeline/component/item/Item.js +0 -139
  67. data/vendor/assets/vis/timeline/component/item/ItemBox.js +0 -230
  68. data/vendor/assets/vis/timeline/component/item/ItemPoint.js +0 -190
  69. data/vendor/assets/vis/timeline/component/item/ItemRange.js +0 -262
  70. data/vendor/assets/vis/timeline/component/item/ItemRangeOverflow.js +0 -57
  71. data/vendor/assets/vis/timeline/img/delete.png +0 -0
  72. data/vendor/assets/vis/timeline/stack.js +0 -112
  73. data/vendor/assets/vis/util.js +0 -990
@@ -1,80 +0,0 @@
1
- /**
2
- * @class Groups
3
- * This class can store groups and properties specific for groups.
4
- */
5
- function Groups() {
6
- this.clear();
7
- this.defaultIndex = 0;
8
- }
9
-
10
-
11
- /**
12
- * default constants for group colors
13
- */
14
- Groups.DEFAULT = [
15
- {border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue
16
- {border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}}, // yellow
17
- {border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}}, // red
18
- {border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}}, // green
19
- {border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}}, // magenta
20
- {border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}}, // purple
21
- {border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}}, // orange
22
- {border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue
23
- {border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}}, // pink
24
- {border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}} // mint
25
- ];
26
-
27
-
28
- /**
29
- * Clear all groups
30
- */
31
- Groups.prototype.clear = function () {
32
- this.groups = {};
33
- this.groups.length = function()
34
- {
35
- var i = 0;
36
- for ( var p in this ) {
37
- if (this.hasOwnProperty(p)) {
38
- i++;
39
- }
40
- }
41
- return i;
42
- }
43
- };
44
-
45
-
46
- /**
47
- * get group properties of a groupname. If groupname is not found, a new group
48
- * is added.
49
- * @param {*} groupname Can be a number, string, Date, etc.
50
- * @return {Object} group The created group, containing all group properties
51
- */
52
- Groups.prototype.get = function (groupname) {
53
- var group = this.groups[groupname];
54
-
55
- if (group == undefined) {
56
- // create new group
57
- var index = this.defaultIndex % Groups.DEFAULT.length;
58
- this.defaultIndex++;
59
- group = {};
60
- group.color = Groups.DEFAULT[index];
61
- this.groups[groupname] = group;
62
- }
63
-
64
- return group;
65
- };
66
-
67
- /**
68
- * Add a custom group style
69
- * @param {String} groupname
70
- * @param {Object} style An object containing borderColor,
71
- * backgroundColor, etc.
72
- * @return {Object} group The created group object
73
- */
74
- Groups.prototype.add = function (groupname, style) {
75
- this.groups[groupname] = style;
76
- if (style.color) {
77
- style.color = util.parseColor(style.color);
78
- }
79
- return style;
80
- };
@@ -1,41 +0,0 @@
1
- /**
2
- * @class Images
3
- * This class loads images and keeps them stored.
4
- */
5
- function Images() {
6
- this.images = {};
7
-
8
- this.callback = undefined;
9
- }
10
-
11
- /**
12
- * Set an onload callback function. This will be called each time an image
13
- * is loaded
14
- * @param {function} callback
15
- */
16
- Images.prototype.setOnloadCallback = function(callback) {
17
- this.callback = callback;
18
- };
19
-
20
- /**
21
- *
22
- * @param {string} url Url of the image
23
- * @return {Image} img The image object
24
- */
25
- Images.prototype.load = function(url) {
26
- var img = this.images[url];
27
- if (img == undefined) {
28
- // create the image
29
- var images = this;
30
- img = new Image();
31
- this.images[url] = img;
32
- img.onload = function() {
33
- if (images.callback) {
34
- images.callback(this);
35
- }
36
- };
37
- img.src = url;
38
- }
39
-
40
- return img;
41
- };
@@ -1,966 +0,0 @@
1
- /**
2
- * @class Node
3
- * A node. A node can be connected to other nodes via one or multiple edges.
4
- * @param {object} properties An object containing properties for the node. All
5
- * properties are optional, except for the id.
6
- * {number} id Id of the node. Required
7
- * {string} label Text label for the node
8
- * {number} x Horizontal position of the node
9
- * {number} y Vertical position of the node
10
- * {string} shape Node shape, available:
11
- * "database", "circle", "ellipse",
12
- * "box", "image", "text", "dot",
13
- * "star", "triangle", "triangleDown",
14
- * "square"
15
- * {string} image An image url
16
- * {string} title An title text, can be HTML
17
- * {anytype} group A group name or number
18
- * @param {Graph.Images} imagelist A list with images. Only needed
19
- * when the node has an image
20
- * @param {Graph.Groups} grouplist A list with groups. Needed for
21
- * retrieving group properties
22
- * @param {Object} constants An object with default values for
23
- * example for the color
24
- *
25
- */
26
- function Node(properties, imagelist, grouplist, constants) {
27
- this.selected = false;
28
- this.hover = false;
29
-
30
- this.edges = []; // all edges connected to this node
31
- this.dynamicEdges = [];
32
- this.reroutedEdges = {};
33
-
34
- this.group = constants.nodes.group;
35
- this.fontSize = Number(constants.nodes.fontSize);
36
- this.fontFace = constants.nodes.fontFace;
37
- this.fontColor = constants.nodes.fontColor;
38
- this.fontDrawThreshold = 3;
39
-
40
- this.color = constants.nodes.color;
41
-
42
- // set defaults for the properties
43
- this.id = undefined;
44
- this.shape = constants.nodes.shape;
45
- this.image = constants.nodes.image;
46
- this.x = null;
47
- this.y = null;
48
- this.xFixed = false;
49
- this.yFixed = false;
50
- this.horizontalAlignLeft = true; // these are for the navigation controls
51
- this.verticalAlignTop = true; // these are for the navigation controls
52
- this.radius = constants.nodes.radius;
53
- this.baseRadiusValue = constants.nodes.radius;
54
- this.radiusFixed = false;
55
- this.radiusMin = constants.nodes.radiusMin;
56
- this.radiusMax = constants.nodes.radiusMax;
57
- this.level = -1;
58
- this.preassignedLevel = false;
59
-
60
-
61
- this.imagelist = imagelist;
62
- this.grouplist = grouplist;
63
-
64
- // physics properties
65
- this.fx = 0.0; // external force x
66
- this.fy = 0.0; // external force y
67
- this.vx = 0.0; // velocity x
68
- this.vy = 0.0; // velocity y
69
- this.minForce = constants.minForce;
70
- this.damping = constants.physics.damping;
71
- this.mass = 1; // kg
72
- this.fixedData = {x:null,y:null};
73
-
74
- this.setProperties(properties, constants);
75
-
76
- // creating the variables for clustering
77
- this.resetCluster();
78
- this.dynamicEdgesLength = 0;
79
- this.clusterSession = 0;
80
- this.clusterSizeWidthFactor = constants.clustering.nodeScaling.width;
81
- this.clusterSizeHeightFactor = constants.clustering.nodeScaling.height;
82
- this.clusterSizeRadiusFactor = constants.clustering.nodeScaling.radius;
83
- this.maxNodeSizeIncrements = constants.clustering.maxNodeSizeIncrements;
84
- this.growthIndicator = 0;
85
-
86
- // variables to tell the node about the graph.
87
- this.graphScaleInv = 1;
88
- this.graphScale = 1;
89
- this.canvasTopLeft = {"x": -300, "y": -300};
90
- this.canvasBottomRight = {"x": 300, "y": 300};
91
- this.parentEdgeId = null;
92
- }
93
-
94
- /**
95
- * (re)setting the clustering variables and objects
96
- */
97
- Node.prototype.resetCluster = function() {
98
- // clustering variables
99
- this.formationScale = undefined; // this is used to determine when to open the cluster
100
- this.clusterSize = 1; // this signifies the total amount of nodes in this cluster
101
- this.containedNodes = {};
102
- this.containedEdges = {};
103
- this.clusterSessions = [];
104
- };
105
-
106
- /**
107
- * Attach a edge to the node
108
- * @param {Edge} edge
109
- */
110
- Node.prototype.attachEdge = function(edge) {
111
- if (this.edges.indexOf(edge) == -1) {
112
- this.edges.push(edge);
113
- }
114
- if (this.dynamicEdges.indexOf(edge) == -1) {
115
- this.dynamicEdges.push(edge);
116
- }
117
- this.dynamicEdgesLength = this.dynamicEdges.length;
118
- };
119
-
120
- /**
121
- * Detach a edge from the node
122
- * @param {Edge} edge
123
- */
124
- Node.prototype.detachEdge = function(edge) {
125
- var index = this.edges.indexOf(edge);
126
- if (index != -1) {
127
- this.edges.splice(index, 1);
128
- this.dynamicEdges.splice(index, 1);
129
- }
130
- this.dynamicEdgesLength = this.dynamicEdges.length;
131
- };
132
-
133
-
134
- /**
135
- * Set or overwrite properties for the node
136
- * @param {Object} properties an object with properties
137
- * @param {Object} constants and object with default, global properties
138
- */
139
- Node.prototype.setProperties = function(properties, constants) {
140
- if (!properties) {
141
- return;
142
- }
143
- this.originalLabel = undefined;
144
- // basic properties
145
- if (properties.id !== undefined) {this.id = properties.id;}
146
- if (properties.label !== undefined) {this.label = properties.label; this.originalLabel = properties.label;}
147
- if (properties.title !== undefined) {this.title = properties.title;}
148
- if (properties.group !== undefined) {this.group = properties.group;}
149
- if (properties.x !== undefined) {this.x = properties.x;}
150
- if (properties.y !== undefined) {this.y = properties.y;}
151
- if (properties.value !== undefined) {this.value = properties.value;}
152
- if (properties.level !== undefined) {this.level = properties.level; this.preassignedLevel = true;}
153
-
154
-
155
- // physics
156
- if (properties.mass !== undefined) {this.mass = properties.mass;}
157
-
158
- // navigation controls properties
159
- if (properties.horizontalAlignLeft !== undefined) {this.horizontalAlignLeft = properties.horizontalAlignLeft;}
160
- if (properties.verticalAlignTop !== undefined) {this.verticalAlignTop = properties.verticalAlignTop;}
161
- if (properties.triggerFunction !== undefined) {this.triggerFunction = properties.triggerFunction;}
162
-
163
- if (this.id === undefined) {
164
- throw "Node must have an id";
165
- }
166
-
167
- // copy group properties
168
- if (this.group) {
169
- var groupObj = this.grouplist.get(this.group);
170
- for (var prop in groupObj) {
171
- if (groupObj.hasOwnProperty(prop)) {
172
- this[prop] = groupObj[prop];
173
- }
174
- }
175
- }
176
-
177
- // individual shape properties
178
- if (properties.shape !== undefined) {this.shape = properties.shape;}
179
- if (properties.image !== undefined) {this.image = properties.image;}
180
- if (properties.radius !== undefined) {this.radius = properties.radius;}
181
- if (properties.color !== undefined) {this.color = util.parseColor(properties.color);}
182
-
183
- if (properties.fontColor !== undefined) {this.fontColor = properties.fontColor;}
184
- if (properties.fontSize !== undefined) {this.fontSize = properties.fontSize;}
185
- if (properties.fontFace !== undefined) {this.fontFace = properties.fontFace;}
186
-
187
- if (this.image !== undefined && this.image != "") {
188
- if (this.imagelist) {
189
- this.imageObj = this.imagelist.load(this.image);
190
- }
191
- else {
192
- throw "No imagelist provided";
193
- }
194
- }
195
-
196
- this.xFixed = this.xFixed || (properties.x !== undefined && !properties.allowedToMoveX);
197
- this.yFixed = this.yFixed || (properties.y !== undefined && !properties.allowedToMoveY);
198
- this.radiusFixed = this.radiusFixed || (properties.radius !== undefined);
199
-
200
- if (this.shape == 'image') {
201
- this.radiusMin = constants.nodes.widthMin;
202
- this.radiusMax = constants.nodes.widthMax;
203
- }
204
-
205
- // choose draw method depending on the shape
206
- switch (this.shape) {
207
- case 'database': this.draw = this._drawDatabase; this.resize = this._resizeDatabase; break;
208
- case 'box': this.draw = this._drawBox; this.resize = this._resizeBox; break;
209
- case 'circle': this.draw = this._drawCircle; this.resize = this._resizeCircle; break;
210
- case 'ellipse': this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break;
211
- // TODO: add diamond shape
212
- case 'image': this.draw = this._drawImage; this.resize = this._resizeImage; break;
213
- case 'text': this.draw = this._drawText; this.resize = this._resizeText; break;
214
- case 'dot': this.draw = this._drawDot; this.resize = this._resizeShape; break;
215
- case 'square': this.draw = this._drawSquare; this.resize = this._resizeShape; break;
216
- case 'triangle': this.draw = this._drawTriangle; this.resize = this._resizeShape; break;
217
- case 'triangleDown': this.draw = this._drawTriangleDown; this.resize = this._resizeShape; break;
218
- case 'star': this.draw = this._drawStar; this.resize = this._resizeShape; break;
219
- default: this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break;
220
- }
221
- // reset the size of the node, this can be changed
222
- this._reset();
223
- };
224
-
225
- /**
226
- * select this node
227
- */
228
- Node.prototype.select = function() {
229
- this.selected = true;
230
- this._reset();
231
- };
232
-
233
- /**
234
- * unselect this node
235
- */
236
- Node.prototype.unselect = function() {
237
- this.selected = false;
238
- this._reset();
239
- };
240
-
241
-
242
- /**
243
- * Reset the calculated size of the node, forces it to recalculate its size
244
- */
245
- Node.prototype.clearSizeCache = function() {
246
- this._reset();
247
- };
248
-
249
- /**
250
- * Reset the calculated size of the node, forces it to recalculate its size
251
- * @private
252
- */
253
- Node.prototype._reset = function() {
254
- this.width = undefined;
255
- this.height = undefined;
256
- };
257
-
258
- /**
259
- * get the title of this node.
260
- * @return {string} title The title of the node, or undefined when no title
261
- * has been set.
262
- */
263
- Node.prototype.getTitle = function() {
264
- return typeof this.title === "function" ? this.title() : this.title;
265
- };
266
-
267
- /**
268
- * Calculate the distance to the border of the Node
269
- * @param {CanvasRenderingContext2D} ctx
270
- * @param {Number} angle Angle in radians
271
- * @returns {number} distance Distance to the border in pixels
272
- */
273
- Node.prototype.distanceToBorder = function (ctx, angle) {
274
- var borderWidth = 1;
275
-
276
- if (!this.width) {
277
- this.resize(ctx);
278
- }
279
-
280
- switch (this.shape) {
281
- case 'circle':
282
- case 'dot':
283
- return this.radius + borderWidth;
284
-
285
- case 'ellipse':
286
- var a = this.width / 2;
287
- var b = this.height / 2;
288
- var w = (Math.sin(angle) * a);
289
- var h = (Math.cos(angle) * b);
290
- return a * b / Math.sqrt(w * w + h * h);
291
-
292
- // TODO: implement distanceToBorder for database
293
- // TODO: implement distanceToBorder for triangle
294
- // TODO: implement distanceToBorder for triangleDown
295
-
296
- case 'box':
297
- case 'image':
298
- case 'text':
299
- default:
300
- if (this.width) {
301
- return Math.min(
302
- Math.abs(this.width / 2 / Math.cos(angle)),
303
- Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth;
304
- // TODO: reckon with border radius too in case of box
305
- }
306
- else {
307
- return 0;
308
- }
309
-
310
- }
311
- // TODO: implement calculation of distance to border for all shapes
312
- };
313
-
314
- /**
315
- * Set forces acting on the node
316
- * @param {number} fx Force in horizontal direction
317
- * @param {number} fy Force in vertical direction
318
- */
319
- Node.prototype._setForce = function(fx, fy) {
320
- this.fx = fx;
321
- this.fy = fy;
322
- };
323
-
324
- /**
325
- * Add forces acting on the node
326
- * @param {number} fx Force in horizontal direction
327
- * @param {number} fy Force in vertical direction
328
- * @private
329
- */
330
- Node.prototype._addForce = function(fx, fy) {
331
- this.fx += fx;
332
- this.fy += fy;
333
- };
334
-
335
- /**
336
- * Perform one discrete step for the node
337
- * @param {number} interval Time interval in seconds
338
- */
339
- Node.prototype.discreteStep = function(interval) {
340
- if (!this.xFixed) {
341
- var dx = this.damping * this.vx; // damping force
342
- var ax = (this.fx - dx) / this.mass; // acceleration
343
- this.vx += ax * interval; // velocity
344
- this.x += this.vx * interval; // position
345
- }
346
-
347
- if (!this.yFixed) {
348
- var dy = this.damping * this.vy; // damping force
349
- var ay = (this.fy - dy) / this.mass; // acceleration
350
- this.vy += ay * interval; // velocity
351
- this.y += this.vy * interval; // position
352
- }
353
- };
354
-
355
-
356
-
357
- /**
358
- * Perform one discrete step for the node
359
- * @param {number} interval Time interval in seconds
360
- * @param {number} maxVelocity The speed limit imposed on the velocity
361
- */
362
- Node.prototype.discreteStepLimited = function(interval, maxVelocity) {
363
- if (!this.xFixed) {
364
- var dx = this.damping * this.vx; // damping force
365
- var ax = (this.fx - dx) / this.mass; // acceleration
366
- this.vx += ax * interval; // velocity
367
- this.vx = (Math.abs(this.vx) > maxVelocity) ? ((this.vx > 0) ? maxVelocity : -maxVelocity) : this.vx;
368
- this.x += this.vx * interval; // position
369
- }
370
- else {
371
- this.fx = 0;
372
- }
373
-
374
- if (!this.yFixed) {
375
- var dy = this.damping * this.vy; // damping force
376
- var ay = (this.fy - dy) / this.mass; // acceleration
377
- this.vy += ay * interval; // velocity
378
- this.vy = (Math.abs(this.vy) > maxVelocity) ? ((this.vy > 0) ? maxVelocity : -maxVelocity) : this.vy;
379
- this.y += this.vy * interval; // position
380
- }
381
- else {
382
- this.fy = 0;
383
- }
384
- };
385
-
386
- /**
387
- * Check if this node has a fixed x and y position
388
- * @return {boolean} true if fixed, false if not
389
- */
390
- Node.prototype.isFixed = function() {
391
- return (this.xFixed && this.yFixed);
392
- };
393
-
394
- /**
395
- * Check if this node is moving
396
- * @param {number} vmin the minimum velocity considered as "moving"
397
- * @return {boolean} true if moving, false if it has no velocity
398
- */
399
- // TODO: replace this method with calculating the kinetic energy
400
- Node.prototype.isMoving = function(vmin) {
401
- return (Math.abs(this.vx) > vmin || Math.abs(this.vy) > vmin);
402
- };
403
-
404
- /**
405
- * check if this node is selecte
406
- * @return {boolean} selected True if node is selected, else false
407
- */
408
- Node.prototype.isSelected = function() {
409
- return this.selected;
410
- };
411
-
412
- /**
413
- * Retrieve the value of the node. Can be undefined
414
- * @return {Number} value
415
- */
416
- Node.prototype.getValue = function() {
417
- return this.value;
418
- };
419
-
420
- /**
421
- * Calculate the distance from the nodes location to the given location (x,y)
422
- * @param {Number} x
423
- * @param {Number} y
424
- * @return {Number} value
425
- */
426
- Node.prototype.getDistance = function(x, y) {
427
- var dx = this.x - x,
428
- dy = this.y - y;
429
- return Math.sqrt(dx * dx + dy * dy);
430
- };
431
-
432
-
433
- /**
434
- * Adjust the value range of the node. The node will adjust it's radius
435
- * based on its value.
436
- * @param {Number} min
437
- * @param {Number} max
438
- */
439
- Node.prototype.setValueRange = function(min, max) {
440
- if (!this.radiusFixed && this.value !== undefined) {
441
- if (max == min) {
442
- this.radius = (this.radiusMin + this.radiusMax) / 2;
443
- }
444
- else {
445
- var scale = (this.radiusMax - this.radiusMin) / (max - min);
446
- this.radius = (this.value - min) * scale + this.radiusMin;
447
- }
448
- }
449
- this.baseRadiusValue = this.radius;
450
- };
451
-
452
- /**
453
- * Draw this node in the given canvas
454
- * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
455
- * @param {CanvasRenderingContext2D} ctx
456
- */
457
- Node.prototype.draw = function(ctx) {
458
- throw "Draw method not initialized for node";
459
- };
460
-
461
- /**
462
- * Recalculate the size of this node in the given canvas
463
- * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
464
- * @param {CanvasRenderingContext2D} ctx
465
- */
466
- Node.prototype.resize = function(ctx) {
467
- throw "Resize method not initialized for node";
468
- };
469
-
470
- /**
471
- * Check if this object is overlapping with the provided object
472
- * @param {Object} obj an object with parameters left, top, right, bottom
473
- * @return {boolean} True if location is located on node
474
- */
475
- Node.prototype.isOverlappingWith = function(obj) {
476
- return (this.left < obj.right &&
477
- this.left + this.width > obj.left &&
478
- this.top < obj.bottom &&
479
- this.top + this.height > obj.top);
480
- };
481
-
482
- Node.prototype._resizeImage = function (ctx) {
483
- // TODO: pre calculate the image size
484
-
485
- if (!this.width || !this.height) { // undefined or 0
486
- var width, height;
487
- if (this.value) {
488
- this.radius = this.baseRadiusValue;
489
- var scale = this.imageObj.height / this.imageObj.width;
490
- if (scale !== undefined) {
491
- width = this.radius || this.imageObj.width;
492
- height = this.radius * scale || this.imageObj.height;
493
- }
494
- else {
495
- width = 0;
496
- height = 0;
497
- }
498
- }
499
- else {
500
- width = this.imageObj.width;
501
- height = this.imageObj.height;
502
- }
503
- this.width = width;
504
- this.height = height;
505
-
506
- this.growthIndicator = 0;
507
- if (this.width > 0 && this.height > 0) {
508
- this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
509
- this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
510
- this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
511
- this.growthIndicator = this.width - width;
512
- }
513
- }
514
-
515
- };
516
-
517
- Node.prototype._drawImage = function (ctx) {
518
- this._resizeImage(ctx);
519
-
520
- this.left = this.x - this.width / 2;
521
- this.top = this.y - this.height / 2;
522
-
523
- var yLabel;
524
- if (this.imageObj.width != 0 ) {
525
- // draw the shade
526
- if (this.clusterSize > 1) {
527
- var lineWidth = ((this.clusterSize > 1) ? 10 : 0.0);
528
- lineWidth *= this.graphScaleInv;
529
- lineWidth = Math.min(0.2 * this.width,lineWidth);
530
-
531
- ctx.globalAlpha = 0.5;
532
- ctx.drawImage(this.imageObj, this.left - lineWidth, this.top - lineWidth, this.width + 2*lineWidth, this.height + 2*lineWidth);
533
- }
534
-
535
- // draw the image
536
- ctx.globalAlpha = 1.0;
537
- ctx.drawImage(this.imageObj, this.left, this.top, this.width, this.height);
538
- yLabel = this.y + this.height / 2;
539
- }
540
- else {
541
- // image still loading... just draw the label for now
542
- yLabel = this.y;
543
- }
544
-
545
- this._label(ctx, this.label, this.x, yLabel, undefined, "top");
546
- };
547
-
548
-
549
- Node.prototype._resizeBox = function (ctx) {
550
- if (!this.width) {
551
- var margin = 5;
552
- var textSize = this.getTextSize(ctx);
553
- this.width = textSize.width + 2 * margin;
554
- this.height = textSize.height + 2 * margin;
555
-
556
- this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor;
557
- this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor;
558
- this.growthIndicator = this.width - (textSize.width + 2 * margin);
559
- // this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor;
560
-
561
- }
562
- };
563
-
564
- Node.prototype._drawBox = function (ctx) {
565
- this._resizeBox(ctx);
566
-
567
- this.left = this.x - this.width / 2;
568
- this.top = this.y - this.height / 2;
569
-
570
- var clusterLineWidth = 2.5;
571
- var selectionLineWidth = 2;
572
-
573
- ctx.strokeStyle = this.selected ? this.color.highlight.border : this.hover ? this.color.hover.border : this.color.border;
574
-
575
- // draw the outer border
576
- if (this.clusterSize > 1) {
577
- ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
578
- ctx.lineWidth *= this.graphScaleInv;
579
- ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
580
-
581
- ctx.roundRect(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth, this.radius);
582
- ctx.stroke();
583
- }
584
- ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
585
- ctx.lineWidth *= this.graphScaleInv;
586
- ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
587
-
588
- ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background;
589
-
590
- ctx.roundRect(this.left, this.top, this.width, this.height, this.radius);
591
- ctx.fill();
592
- ctx.stroke();
593
-
594
- this._label(ctx, this.label, this.x, this.y);
595
- };
596
-
597
-
598
- Node.prototype._resizeDatabase = function (ctx) {
599
- if (!this.width) {
600
- var margin = 5;
601
- var textSize = this.getTextSize(ctx);
602
- var size = textSize.width + 2 * margin;
603
- this.width = size;
604
- this.height = size;
605
-
606
- // scaling used for clustering
607
- this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
608
- this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
609
- this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
610
- this.growthIndicator = this.width - size;
611
- }
612
- };
613
-
614
- Node.prototype._drawDatabase = function (ctx) {
615
- this._resizeDatabase(ctx);
616
- this.left = this.x - this.width / 2;
617
- this.top = this.y - this.height / 2;
618
-
619
- var clusterLineWidth = 2.5;
620
- var selectionLineWidth = 2;
621
-
622
- ctx.strokeStyle = this.selected ? this.color.highlight.border : this.hover ? this.color.hover.border : this.color.border;
623
-
624
- // draw the outer border
625
- if (this.clusterSize > 1) {
626
- ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
627
- ctx.lineWidth *= this.graphScaleInv;
628
- ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
629
-
630
- ctx.database(this.x - this.width/2 - 2*ctx.lineWidth, this.y - this.height*0.5 - 2*ctx.lineWidth, this.width + 4*ctx.lineWidth, this.height + 4*ctx.lineWidth);
631
- ctx.stroke();
632
- }
633
- ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
634
- ctx.lineWidth *= this.graphScaleInv;
635
- ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
636
-
637
- ctx.fillStyle = this.selected ? this.color.highlight.background : this.hover ? this.color.hover.background : this.color.background;
638
- ctx.database(this.x - this.width/2, this.y - this.height*0.5, this.width, this.height);
639
- ctx.fill();
640
- ctx.stroke();
641
-
642
- this._label(ctx, this.label, this.x, this.y);
643
- };
644
-
645
-
646
- Node.prototype._resizeCircle = function (ctx) {
647
- if (!this.width) {
648
- var margin = 5;
649
- var textSize = this.getTextSize(ctx);
650
- var diameter = Math.max(textSize.width, textSize.height) + 2 * margin;
651
- this.radius = diameter / 2;
652
-
653
- this.width = diameter;
654
- this.height = diameter;
655
-
656
- // scaling used for clustering
657
- // this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor;
658
- // this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor;
659
- this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor;
660
- this.growthIndicator = this.radius - 0.5*diameter;
661
- }
662
- };
663
-
664
- Node.prototype._drawCircle = function (ctx) {
665
- this._resizeCircle(ctx);
666
- this.left = this.x - this.width / 2;
667
- this.top = this.y - this.height / 2;
668
-
669
- var clusterLineWidth = 2.5;
670
- var selectionLineWidth = 2;
671
-
672
- ctx.strokeStyle = this.selected ? this.color.highlight.border : this.hover ? this.color.hover.border : this.color.border;
673
-
674
- // draw the outer border
675
- if (this.clusterSize > 1) {
676
- ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
677
- ctx.lineWidth *= this.graphScaleInv;
678
- ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
679
-
680
- ctx.circle(this.x, this.y, this.radius+2*ctx.lineWidth);
681
- ctx.stroke();
682
- }
683
- ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
684
- ctx.lineWidth *= this.graphScaleInv;
685
- ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
686
-
687
- ctx.fillStyle = this.selected ? this.color.highlight.background : this.hover ? this.color.hover.background : this.color.background;
688
- ctx.circle(this.x, this.y, this.radius);
689
- ctx.fill();
690
- ctx.stroke();
691
-
692
- this._label(ctx, this.label, this.x, this.y);
693
- };
694
-
695
- Node.prototype._resizeEllipse = function (ctx) {
696
- if (!this.width) {
697
- var textSize = this.getTextSize(ctx);
698
-
699
- this.width = textSize.width * 1.5;
700
- this.height = textSize.height * 2;
701
- if (this.width < this.height) {
702
- this.width = this.height;
703
- }
704
- var defaultSize = this.width;
705
-
706
- // scaling used for clustering
707
- this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
708
- this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
709
- this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
710
- this.growthIndicator = this.width - defaultSize;
711
- }
712
- };
713
-
714
- Node.prototype._drawEllipse = function (ctx) {
715
- this._resizeEllipse(ctx);
716
- this.left = this.x - this.width / 2;
717
- this.top = this.y - this.height / 2;
718
-
719
- var clusterLineWidth = 2.5;
720
- var selectionLineWidth = 2;
721
-
722
- ctx.strokeStyle = this.selected ? this.color.highlight.border : this.hover ? this.color.hover.border : this.color.border;
723
-
724
- // draw the outer border
725
- if (this.clusterSize > 1) {
726
- ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
727
- ctx.lineWidth *= this.graphScaleInv;
728
- ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
729
-
730
- ctx.ellipse(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth);
731
- ctx.stroke();
732
- }
733
- ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
734
- ctx.lineWidth *= this.graphScaleInv;
735
- ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
736
-
737
- ctx.fillStyle = this.selected ? this.color.highlight.background : this.hover ? this.color.hover.background : this.color.background;
738
-
739
- ctx.ellipse(this.left, this.top, this.width, this.height);
740
- ctx.fill();
741
- ctx.stroke();
742
- this._label(ctx, this.label, this.x, this.y);
743
- };
744
-
745
- Node.prototype._drawDot = function (ctx) {
746
- this._drawShape(ctx, 'circle');
747
- };
748
-
749
- Node.prototype._drawTriangle = function (ctx) {
750
- this._drawShape(ctx, 'triangle');
751
- };
752
-
753
- Node.prototype._drawTriangleDown = function (ctx) {
754
- this._drawShape(ctx, 'triangleDown');
755
- };
756
-
757
- Node.prototype._drawSquare = function (ctx) {
758
- this._drawShape(ctx, 'square');
759
- };
760
-
761
- Node.prototype._drawStar = function (ctx) {
762
- this._drawShape(ctx, 'star');
763
- };
764
-
765
- Node.prototype._resizeShape = function (ctx) {
766
- if (!this.width) {
767
- this.radius = this.baseRadiusValue;
768
- var size = 2 * this.radius;
769
- this.width = size;
770
- this.height = size;
771
-
772
- // scaling used for clustering
773
- this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
774
- this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
775
- this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor;
776
- this.growthIndicator = this.width - size;
777
- }
778
- };
779
-
780
- Node.prototype._drawShape = function (ctx, shape) {
781
- this._resizeShape(ctx);
782
-
783
- this.left = this.x - this.width / 2;
784
- this.top = this.y - this.height / 2;
785
-
786
- var clusterLineWidth = 2.5;
787
- var selectionLineWidth = 2;
788
- var radiusMultiplier = 2;
789
-
790
- // choose draw method depending on the shape
791
- switch (shape) {
792
- case 'dot': radiusMultiplier = 2; break;
793
- case 'square': radiusMultiplier = 2; break;
794
- case 'triangle': radiusMultiplier = 3; break;
795
- case 'triangleDown': radiusMultiplier = 3; break;
796
- case 'star': radiusMultiplier = 4; break;
797
- }
798
-
799
- ctx.strokeStyle = this.selected ? this.color.highlight.border : this.hover ? this.color.hover.border : this.color.border;
800
-
801
- // draw the outer border
802
- if (this.clusterSize > 1) {
803
- ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
804
- ctx.lineWidth *= this.graphScaleInv;
805
- ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
806
-
807
- ctx[shape](this.x, this.y, this.radius + radiusMultiplier * ctx.lineWidth);
808
- ctx.stroke();
809
- }
810
- ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
811
- ctx.lineWidth *= this.graphScaleInv;
812
- ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
813
-
814
- ctx.fillStyle = this.selected ? this.color.highlight.background : this.hover ? this.color.hover.background : this.color.background;
815
- ctx[shape](this.x, this.y, this.radius);
816
- ctx.fill();
817
- ctx.stroke();
818
-
819
- if (this.label) {
820
- this._label(ctx, this.label, this.x, this.y + this.height / 2, undefined, 'top');
821
- }
822
- };
823
-
824
- Node.prototype._resizeText = function (ctx) {
825
- if (!this.width) {
826
- var margin = 5;
827
- var textSize = this.getTextSize(ctx);
828
- this.width = textSize.width + 2 * margin;
829
- this.height = textSize.height + 2 * margin;
830
-
831
- // scaling used for clustering
832
- this.width += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
833
- this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
834
- this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
835
- this.growthIndicator = this.width - (textSize.width + 2 * margin);
836
- }
837
- };
838
-
839
- Node.prototype._drawText = function (ctx) {
840
- this._resizeText(ctx);
841
- this.left = this.x - this.width / 2;
842
- this.top = this.y - this.height / 2;
843
-
844
- this._label(ctx, this.label, this.x, this.y);
845
- };
846
-
847
-
848
- Node.prototype._label = function (ctx, text, x, y, align, baseline) {
849
- if (text && this.fontSize * this.graphScale > this.fontDrawThreshold) {
850
- ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace;
851
- ctx.fillStyle = this.fontColor || "black";
852
- ctx.textAlign = align || "center";
853
- ctx.textBaseline = baseline || "middle";
854
-
855
- var lines = text.split('\n'),
856
- lineCount = lines.length,
857
- fontSize = (this.fontSize + 4),
858
- yLine = y + (1 - lineCount) / 2 * fontSize;
859
-
860
- for (var i = 0; i < lineCount; i++) {
861
- ctx.fillText(lines[i], x, yLine);
862
- yLine += fontSize;
863
- }
864
- }
865
- };
866
-
867
-
868
- Node.prototype.getTextSize = function(ctx) {
869
- if (this.label !== undefined) {
870
- ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace;
871
-
872
- var lines = this.label.split('\n'),
873
- height = (this.fontSize + 4) * lines.length,
874
- width = 0;
875
-
876
- for (var i = 0, iMax = lines.length; i < iMax; i++) {
877
- width = Math.max(width, ctx.measureText(lines[i]).width);
878
- }
879
-
880
- return {"width": width, "height": height};
881
- }
882
- else {
883
- return {"width": 0, "height": 0};
884
- }
885
- };
886
-
887
- /**
888
- * this is used to determine if a node is visible at all. this is used to determine when it needs to be drawn.
889
- * there is a safety margin of 0.3 * width;
890
- *
891
- * @returns {boolean}
892
- */
893
- Node.prototype.inArea = function() {
894
- if (this.width !== undefined) {
895
- return (this.x + this.width *this.graphScaleInv >= this.canvasTopLeft.x &&
896
- this.x - this.width *this.graphScaleInv < this.canvasBottomRight.x &&
897
- this.y + this.height*this.graphScaleInv >= this.canvasTopLeft.y &&
898
- this.y - this.height*this.graphScaleInv < this.canvasBottomRight.y);
899
- }
900
- else {
901
- return true;
902
- }
903
- };
904
-
905
- /**
906
- * checks if the core of the node is in the display area, this is used for opening clusters around zoom
907
- * @returns {boolean}
908
- */
909
- Node.prototype.inView = function() {
910
- return (this.x >= this.canvasTopLeft.x &&
911
- this.x < this.canvasBottomRight.x &&
912
- this.y >= this.canvasTopLeft.y &&
913
- this.y < this.canvasBottomRight.y);
914
- };
915
-
916
- /**
917
- * This allows the zoom level of the graph to influence the rendering
918
- * We store the inverted scale and the coordinates of the top left, and bottom right points of the canvas
919
- *
920
- * @param scale
921
- * @param canvasTopLeft
922
- * @param canvasBottomRight
923
- */
924
- Node.prototype.setScaleAndPos = function(scale,canvasTopLeft,canvasBottomRight) {
925
- this.graphScaleInv = 1.0/scale;
926
- this.graphScale = scale;
927
- this.canvasTopLeft = canvasTopLeft;
928
- this.canvasBottomRight = canvasBottomRight;
929
- };
930
-
931
-
932
- /**
933
- * This allows the zoom level of the graph to influence the rendering
934
- *
935
- * @param scale
936
- */
937
- Node.prototype.setScale = function(scale) {
938
- this.graphScaleInv = 1.0/scale;
939
- this.graphScale = scale;
940
- };
941
-
942
-
943
-
944
- /**
945
- * set the velocity at 0. Is called when this node is contained in another during clustering
946
- */
947
- Node.prototype.clearVelocity = function() {
948
- this.vx = 0;
949
- this.vy = 0;
950
- };
951
-
952
-
953
- /**
954
- * Basic preservation of (kinectic) energy
955
- *
956
- * @param massBeforeClustering
957
- */
958
- Node.prototype.updateVelocity = function(massBeforeClustering) {
959
- var energyBefore = this.vx * this.vx * massBeforeClustering;
960
- //this.vx = (this.vx < 0) ? -Math.sqrt(energyBefore/this.mass) : Math.sqrt(energyBefore/this.mass);
961
- this.vx = Math.sqrt(energyBefore/this.mass);
962
- energyBefore = this.vy * this.vy * massBeforeClustering;
963
- //this.vy = (this.vy < 0) ? -Math.sqrt(energyBefore/this.mass) : Math.sqrt(energyBefore/this.mass);
964
- this.vy = Math.sqrt(energyBefore/this.mass);
965
- };
966
-