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.
- checksums.yaml +4 -4
- data/lib/vis/rails/version.rb +1 -1
- data/vendor/assets/javascripts/vis.js +26 -26
- metadata +16 -85
- data/vendor/assets/vis/DataSet.js +0 -926
- data/vendor/assets/vis/DataView.js +0 -283
- data/vendor/assets/vis/graph/Edge.js +0 -957
- data/vendor/assets/vis/graph/Graph.js +0 -2291
- data/vendor/assets/vis/graph/Groups.js +0 -80
- data/vendor/assets/vis/graph/Images.js +0 -41
- data/vendor/assets/vis/graph/Node.js +0 -966
- data/vendor/assets/vis/graph/Popup.js +0 -132
- data/vendor/assets/vis/graph/css/graph-manipulation.css +0 -128
- data/vendor/assets/vis/graph/css/graph-navigation.css +0 -66
- data/vendor/assets/vis/graph/dotparser.js +0 -829
- data/vendor/assets/vis/graph/graphMixins/ClusterMixin.js +0 -1143
- data/vendor/assets/vis/graph/graphMixins/HierarchicalLayoutMixin.js +0 -311
- data/vendor/assets/vis/graph/graphMixins/ManipulationMixin.js +0 -576
- data/vendor/assets/vis/graph/graphMixins/MixinLoader.js +0 -199
- data/vendor/assets/vis/graph/graphMixins/NavigationMixin.js +0 -205
- data/vendor/assets/vis/graph/graphMixins/SectorsMixin.js +0 -552
- data/vendor/assets/vis/graph/graphMixins/SelectionMixin.js +0 -648
- data/vendor/assets/vis/graph/graphMixins/physics/BarnesHut.js +0 -398
- data/vendor/assets/vis/graph/graphMixins/physics/HierarchialRepulsion.js +0 -64
- data/vendor/assets/vis/graph/graphMixins/physics/PhysicsMixin.js +0 -697
- data/vendor/assets/vis/graph/graphMixins/physics/Repulsion.js +0 -66
- data/vendor/assets/vis/graph/img/acceptDeleteIcon.png +0 -0
- data/vendor/assets/vis/graph/img/addNodeIcon.png +0 -0
- data/vendor/assets/vis/graph/img/backIcon.png +0 -0
- data/vendor/assets/vis/graph/img/connectIcon.png +0 -0
- data/vendor/assets/vis/graph/img/cross.png +0 -0
- data/vendor/assets/vis/graph/img/cross2.png +0 -0
- data/vendor/assets/vis/graph/img/deleteIcon.png +0 -0
- data/vendor/assets/vis/graph/img/downArrow.png +0 -0
- data/vendor/assets/vis/graph/img/editIcon.png +0 -0
- data/vendor/assets/vis/graph/img/leftArrow.png +0 -0
- data/vendor/assets/vis/graph/img/minus.png +0 -0
- data/vendor/assets/vis/graph/img/plus.png +0 -0
- data/vendor/assets/vis/graph/img/rightArrow.png +0 -0
- data/vendor/assets/vis/graph/img/upArrow.png +0 -0
- data/vendor/assets/vis/graph/img/zoomExtends.png +0 -0
- data/vendor/assets/vis/graph/shapes.js +0 -225
- data/vendor/assets/vis/graph3d/Graph3d.js +0 -3306
- data/vendor/assets/vis/module/exports.js +0 -65
- data/vendor/assets/vis/module/header.js +0 -24
- data/vendor/assets/vis/module/imports.js +0 -31
- data/vendor/assets/vis/shim.js +0 -252
- data/vendor/assets/vis/timeline/Range.js +0 -532
- data/vendor/assets/vis/timeline/TimeStep.js +0 -466
- data/vendor/assets/vis/timeline/Timeline.js +0 -851
- data/vendor/assets/vis/timeline/component/Component.js +0 -52
- data/vendor/assets/vis/timeline/component/CurrentTime.js +0 -128
- data/vendor/assets/vis/timeline/component/CustomTime.js +0 -182
- data/vendor/assets/vis/timeline/component/Group.js +0 -470
- data/vendor/assets/vis/timeline/component/ItemSet.js +0 -1332
- data/vendor/assets/vis/timeline/component/TimeAxis.js +0 -389
- data/vendor/assets/vis/timeline/component/css/animation.css +0 -33
- data/vendor/assets/vis/timeline/component/css/currenttime.css +0 -5
- data/vendor/assets/vis/timeline/component/css/customtime.css +0 -6
- data/vendor/assets/vis/timeline/component/css/item.css +0 -107
- data/vendor/assets/vis/timeline/component/css/itemset.css +0 -33
- data/vendor/assets/vis/timeline/component/css/labelset.css +0 -36
- data/vendor/assets/vis/timeline/component/css/panel.css +0 -71
- data/vendor/assets/vis/timeline/component/css/timeaxis.css +0 -48
- data/vendor/assets/vis/timeline/component/css/timeline.css +0 -2
- data/vendor/assets/vis/timeline/component/item/Item.js +0 -139
- data/vendor/assets/vis/timeline/component/item/ItemBox.js +0 -230
- data/vendor/assets/vis/timeline/component/item/ItemPoint.js +0 -190
- data/vendor/assets/vis/timeline/component/item/ItemRange.js +0 -262
- data/vendor/assets/vis/timeline/component/item/ItemRangeOverflow.js +0 -57
- data/vendor/assets/vis/timeline/img/delete.png +0 -0
- data/vendor/assets/vis/timeline/stack.js +0 -112
- data/vendor/assets/vis/util.js +0 -990
@@ -1,398 +0,0 @@
|
|
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
|
-
if (this.constants.physics.barnesHut.gravitationalConstant != 0) {
|
15
|
-
var node;
|
16
|
-
var nodes = this.calculationNodes;
|
17
|
-
var nodeIndices = this.calculationNodeIndices;
|
18
|
-
var nodeCount = nodeIndices.length;
|
19
|
-
|
20
|
-
this._formBarnesHutTree(nodes,nodeIndices);
|
21
|
-
|
22
|
-
var barnesHutTree = this.barnesHutTree;
|
23
|
-
|
24
|
-
// place the nodes one by one recursively
|
25
|
-
for (var i = 0; i < nodeCount; i++) {
|
26
|
-
node = nodes[nodeIndices[i]];
|
27
|
-
// starting with root is irrelevant, it never passes the BarnesHut condition
|
28
|
-
this._getForceContribution(barnesHutTree.root.children.NW,node);
|
29
|
-
this._getForceContribution(barnesHutTree.root.children.NE,node);
|
30
|
-
this._getForceContribution(barnesHutTree.root.children.SW,node);
|
31
|
-
this._getForceContribution(barnesHutTree.root.children.SE,node);
|
32
|
-
}
|
33
|
-
}
|
34
|
-
},
|
35
|
-
|
36
|
-
|
37
|
-
/**
|
38
|
-
* This function traverses the barnesHutTree. It checks when it can approximate distant nodes with their center of mass.
|
39
|
-
* If a region contains a single node, we check if it is not itself, then we apply the force.
|
40
|
-
*
|
41
|
-
* @param parentBranch
|
42
|
-
* @param node
|
43
|
-
* @private
|
44
|
-
*/
|
45
|
-
_getForceContribution : function(parentBranch,node) {
|
46
|
-
// we get no force contribution from an empty region
|
47
|
-
if (parentBranch.childrenCount > 0) {
|
48
|
-
var dx,dy,distance;
|
49
|
-
|
50
|
-
// get the distance from the center of mass to the node.
|
51
|
-
dx = parentBranch.centerOfMass.x - node.x;
|
52
|
-
dy = parentBranch.centerOfMass.y - node.y;
|
53
|
-
distance = Math.sqrt(dx * dx + dy * dy);
|
54
|
-
|
55
|
-
// BarnesHut condition
|
56
|
-
// original condition : s/d < theta = passed === d/s > 1/theta = passed
|
57
|
-
// calcSize = 1/s --> d * 1/s > 1/theta = passed
|
58
|
-
if (distance * parentBranch.calcSize > this.constants.physics.barnesHut.theta) {
|
59
|
-
// duplicate code to reduce function calls to speed up program
|
60
|
-
if (distance == 0) {
|
61
|
-
distance = 0.1*Math.random();
|
62
|
-
dx = distance;
|
63
|
-
}
|
64
|
-
var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.mass / (distance * distance * distance);
|
65
|
-
var fx = dx * gravityForce;
|
66
|
-
var fy = dy * gravityForce;
|
67
|
-
node.fx += fx;
|
68
|
-
node.fy += fy;
|
69
|
-
}
|
70
|
-
else {
|
71
|
-
// Did not pass the condition, go into children if available
|
72
|
-
if (parentBranch.childrenCount == 4) {
|
73
|
-
this._getForceContribution(parentBranch.children.NW,node);
|
74
|
-
this._getForceContribution(parentBranch.children.NE,node);
|
75
|
-
this._getForceContribution(parentBranch.children.SW,node);
|
76
|
-
this._getForceContribution(parentBranch.children.SE,node);
|
77
|
-
}
|
78
|
-
else { // parentBranch must have only one node, if it was empty we wouldnt be here
|
79
|
-
if (parentBranch.children.data.id != node.id) { // if it is not self
|
80
|
-
// duplicate code to reduce function calls to speed up program
|
81
|
-
if (distance == 0) {
|
82
|
-
distance = 0.5*Math.random();
|
83
|
-
dx = distance;
|
84
|
-
}
|
85
|
-
var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.mass / (distance * distance * distance);
|
86
|
-
var fx = dx * gravityForce;
|
87
|
-
var fy = dy * gravityForce;
|
88
|
-
node.fx += fx;
|
89
|
-
node.fy += fy;
|
90
|
-
}
|
91
|
-
}
|
92
|
-
}
|
93
|
-
}
|
94
|
-
},
|
95
|
-
|
96
|
-
/**
|
97
|
-
* This function constructs the barnesHut tree recursively. It creates the root, splits it and starts placing the nodes.
|
98
|
-
*
|
99
|
-
* @param nodes
|
100
|
-
* @param nodeIndices
|
101
|
-
* @private
|
102
|
-
*/
|
103
|
-
_formBarnesHutTree : function(nodes,nodeIndices) {
|
104
|
-
var node;
|
105
|
-
var nodeCount = nodeIndices.length;
|
106
|
-
|
107
|
-
var minX = Number.MAX_VALUE,
|
108
|
-
minY = Number.MAX_VALUE,
|
109
|
-
maxX =-Number.MAX_VALUE,
|
110
|
-
maxY =-Number.MAX_VALUE;
|
111
|
-
|
112
|
-
// get the range of the nodes
|
113
|
-
for (var i = 0; i < nodeCount; i++) {
|
114
|
-
var x = nodes[nodeIndices[i]].x;
|
115
|
-
var y = nodes[nodeIndices[i]].y;
|
116
|
-
if (x < minX) { minX = x; }
|
117
|
-
if (x > maxX) { maxX = x; }
|
118
|
-
if (y < minY) { minY = y; }
|
119
|
-
if (y > maxY) { maxY = y; }
|
120
|
-
}
|
121
|
-
// make the range a square
|
122
|
-
var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y
|
123
|
-
if (sizeDiff > 0) {minY -= 0.5 * sizeDiff; maxY += 0.5 * sizeDiff;} // xSize > ySize
|
124
|
-
else {minX += 0.5 * sizeDiff; maxX -= 0.5 * sizeDiff;} // xSize < ySize
|
125
|
-
|
126
|
-
|
127
|
-
var minimumTreeSize = 1e-5;
|
128
|
-
var rootSize = Math.max(minimumTreeSize,Math.abs(maxX - minX));
|
129
|
-
var halfRootSize = 0.5 * rootSize;
|
130
|
-
var centerX = 0.5 * (minX + maxX), centerY = 0.5 * (minY + maxY);
|
131
|
-
|
132
|
-
// construct the barnesHutTree
|
133
|
-
var barnesHutTree = {root:{
|
134
|
-
centerOfMass:{x:0,y:0}, // Center of Mass
|
135
|
-
mass:0,
|
136
|
-
range: {minX:centerX-halfRootSize,maxX:centerX+halfRootSize,
|
137
|
-
minY:centerY-halfRootSize,maxY:centerY+halfRootSize},
|
138
|
-
|
139
|
-
size: rootSize,
|
140
|
-
calcSize: 1 / rootSize,
|
141
|
-
children: {data:null},
|
142
|
-
maxWidth: 0,
|
143
|
-
level: 0,
|
144
|
-
childrenCount: 4
|
145
|
-
}};
|
146
|
-
this._splitBranch(barnesHutTree.root);
|
147
|
-
|
148
|
-
// place the nodes one by one recursively
|
149
|
-
for (i = 0; i < nodeCount; i++) {
|
150
|
-
node = nodes[nodeIndices[i]];
|
151
|
-
this._placeInTree(barnesHutTree.root,node);
|
152
|
-
}
|
153
|
-
|
154
|
-
// make global
|
155
|
-
this.barnesHutTree = barnesHutTree
|
156
|
-
},
|
157
|
-
|
158
|
-
|
159
|
-
/**
|
160
|
-
* this updates the mass of a branch. this is increased by adding a node.
|
161
|
-
*
|
162
|
-
* @param parentBranch
|
163
|
-
* @param node
|
164
|
-
* @private
|
165
|
-
*/
|
166
|
-
_updateBranchMass : function(parentBranch, node) {
|
167
|
-
var totalMass = parentBranch.mass + node.mass;
|
168
|
-
var totalMassInv = 1/totalMass;
|
169
|
-
|
170
|
-
parentBranch.centerOfMass.x = parentBranch.centerOfMass.x * parentBranch.mass + node.x * node.mass;
|
171
|
-
parentBranch.centerOfMass.x *= totalMassInv;
|
172
|
-
|
173
|
-
parentBranch.centerOfMass.y = parentBranch.centerOfMass.y * parentBranch.mass + node.y * node.mass;
|
174
|
-
parentBranch.centerOfMass.y *= totalMassInv;
|
175
|
-
|
176
|
-
parentBranch.mass = totalMass;
|
177
|
-
var biggestSize = Math.max(Math.max(node.height,node.radius),node.width);
|
178
|
-
parentBranch.maxWidth = (parentBranch.maxWidth < biggestSize) ? biggestSize : parentBranch.maxWidth;
|
179
|
-
|
180
|
-
},
|
181
|
-
|
182
|
-
|
183
|
-
/**
|
184
|
-
* determine in which branch the node will be placed.
|
185
|
-
*
|
186
|
-
* @param parentBranch
|
187
|
-
* @param node
|
188
|
-
* @param skipMassUpdate
|
189
|
-
* @private
|
190
|
-
*/
|
191
|
-
_placeInTree : function(parentBranch,node,skipMassUpdate) {
|
192
|
-
if (skipMassUpdate != true || skipMassUpdate === undefined) {
|
193
|
-
// update the mass of the branch.
|
194
|
-
this._updateBranchMass(parentBranch,node);
|
195
|
-
}
|
196
|
-
|
197
|
-
if (parentBranch.children.NW.range.maxX > node.x) { // in NW or SW
|
198
|
-
if (parentBranch.children.NW.range.maxY > node.y) { // in NW
|
199
|
-
this._placeInRegion(parentBranch,node,"NW");
|
200
|
-
}
|
201
|
-
else { // in SW
|
202
|
-
this._placeInRegion(parentBranch,node,"SW");
|
203
|
-
}
|
204
|
-
}
|
205
|
-
else { // in NE or SE
|
206
|
-
if (parentBranch.children.NW.range.maxY > node.y) { // in NE
|
207
|
-
this._placeInRegion(parentBranch,node,"NE");
|
208
|
-
}
|
209
|
-
else { // in SE
|
210
|
-
this._placeInRegion(parentBranch,node,"SE");
|
211
|
-
}
|
212
|
-
}
|
213
|
-
},
|
214
|
-
|
215
|
-
|
216
|
-
/**
|
217
|
-
* actually place the node in a region (or branch)
|
218
|
-
*
|
219
|
-
* @param parentBranch
|
220
|
-
* @param node
|
221
|
-
* @param region
|
222
|
-
* @private
|
223
|
-
*/
|
224
|
-
_placeInRegion : function(parentBranch,node,region) {
|
225
|
-
switch (parentBranch.children[region].childrenCount) {
|
226
|
-
case 0: // place node here
|
227
|
-
parentBranch.children[region].children.data = node;
|
228
|
-
parentBranch.children[region].childrenCount = 1;
|
229
|
-
this._updateBranchMass(parentBranch.children[region],node);
|
230
|
-
break;
|
231
|
-
case 1: // convert into children
|
232
|
-
// if there are two nodes exactly overlapping (on init, on opening of cluster etc.)
|
233
|
-
// we move one node a pixel and we do not put it in the tree.
|
234
|
-
if (parentBranch.children[region].children.data.x == node.x &&
|
235
|
-
parentBranch.children[region].children.data.y == node.y) {
|
236
|
-
node.x += Math.random();
|
237
|
-
node.y += Math.random();
|
238
|
-
}
|
239
|
-
else {
|
240
|
-
this._splitBranch(parentBranch.children[region]);
|
241
|
-
this._placeInTree(parentBranch.children[region],node);
|
242
|
-
}
|
243
|
-
break;
|
244
|
-
case 4: // place in branch
|
245
|
-
this._placeInTree(parentBranch.children[region],node);
|
246
|
-
break;
|
247
|
-
}
|
248
|
-
},
|
249
|
-
|
250
|
-
|
251
|
-
/**
|
252
|
-
* this function splits a branch into 4 sub branches. If the branch contained a node, we place it in the subbranch
|
253
|
-
* after the split is complete.
|
254
|
-
*
|
255
|
-
* @param parentBranch
|
256
|
-
* @private
|
257
|
-
*/
|
258
|
-
_splitBranch : function(parentBranch) {
|
259
|
-
// if the branch is filled with a node, replace the node in the new subset.
|
260
|
-
var containedNode = null;
|
261
|
-
if (parentBranch.childrenCount == 1) {
|
262
|
-
containedNode = parentBranch.children.data;
|
263
|
-
parentBranch.mass = 0; parentBranch.centerOfMass.x = 0; parentBranch.centerOfMass.y = 0;
|
264
|
-
}
|
265
|
-
parentBranch.childrenCount = 4;
|
266
|
-
parentBranch.children.data = null;
|
267
|
-
this._insertRegion(parentBranch,"NW");
|
268
|
-
this._insertRegion(parentBranch,"NE");
|
269
|
-
this._insertRegion(parentBranch,"SW");
|
270
|
-
this._insertRegion(parentBranch,"SE");
|
271
|
-
|
272
|
-
if (containedNode != null) {
|
273
|
-
this._placeInTree(parentBranch,containedNode);
|
274
|
-
}
|
275
|
-
},
|
276
|
-
|
277
|
-
|
278
|
-
/**
|
279
|
-
* This function subdivides the region into four new segments.
|
280
|
-
* Specifically, this inserts a single new segment.
|
281
|
-
* It fills the children section of the parentBranch
|
282
|
-
*
|
283
|
-
* @param parentBranch
|
284
|
-
* @param region
|
285
|
-
* @param parentRange
|
286
|
-
* @private
|
287
|
-
*/
|
288
|
-
_insertRegion : function(parentBranch, region) {
|
289
|
-
var minX,maxX,minY,maxY;
|
290
|
-
var childSize = 0.5 * parentBranch.size;
|
291
|
-
switch (region) {
|
292
|
-
case "NW":
|
293
|
-
minX = parentBranch.range.minX;
|
294
|
-
maxX = parentBranch.range.minX + childSize;
|
295
|
-
minY = parentBranch.range.minY;
|
296
|
-
maxY = parentBranch.range.minY + childSize;
|
297
|
-
break;
|
298
|
-
case "NE":
|
299
|
-
minX = parentBranch.range.minX + childSize;
|
300
|
-
maxX = parentBranch.range.maxX;
|
301
|
-
minY = parentBranch.range.minY;
|
302
|
-
maxY = parentBranch.range.minY + childSize;
|
303
|
-
break;
|
304
|
-
case "SW":
|
305
|
-
minX = parentBranch.range.minX;
|
306
|
-
maxX = parentBranch.range.minX + childSize;
|
307
|
-
minY = parentBranch.range.minY + childSize;
|
308
|
-
maxY = parentBranch.range.maxY;
|
309
|
-
break;
|
310
|
-
case "SE":
|
311
|
-
minX = parentBranch.range.minX + childSize;
|
312
|
-
maxX = parentBranch.range.maxX;
|
313
|
-
minY = parentBranch.range.minY + childSize;
|
314
|
-
maxY = parentBranch.range.maxY;
|
315
|
-
break;
|
316
|
-
}
|
317
|
-
|
318
|
-
|
319
|
-
parentBranch.children[region] = {
|
320
|
-
centerOfMass:{x:0,y:0},
|
321
|
-
mass:0,
|
322
|
-
range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY},
|
323
|
-
size: 0.5 * parentBranch.size,
|
324
|
-
calcSize: 2 * parentBranch.calcSize,
|
325
|
-
children: {data:null},
|
326
|
-
maxWidth: 0,
|
327
|
-
level: parentBranch.level+1,
|
328
|
-
childrenCount: 0
|
329
|
-
};
|
330
|
-
},
|
331
|
-
|
332
|
-
|
333
|
-
/**
|
334
|
-
* This function is for debugging purposed, it draws the tree.
|
335
|
-
*
|
336
|
-
* @param ctx
|
337
|
-
* @param color
|
338
|
-
* @private
|
339
|
-
*/
|
340
|
-
_drawTree : function(ctx,color) {
|
341
|
-
if (this.barnesHutTree !== undefined) {
|
342
|
-
|
343
|
-
ctx.lineWidth = 1;
|
344
|
-
|
345
|
-
this._drawBranch(this.barnesHutTree.root,ctx,color);
|
346
|
-
}
|
347
|
-
},
|
348
|
-
|
349
|
-
|
350
|
-
/**
|
351
|
-
* This function is for debugging purposes. It draws the branches recursively.
|
352
|
-
*
|
353
|
-
* @param branch
|
354
|
-
* @param ctx
|
355
|
-
* @param color
|
356
|
-
* @private
|
357
|
-
*/
|
358
|
-
_drawBranch : function(branch,ctx,color) {
|
359
|
-
if (color === undefined) {
|
360
|
-
color = "#FF0000";
|
361
|
-
}
|
362
|
-
|
363
|
-
if (branch.childrenCount == 4) {
|
364
|
-
this._drawBranch(branch.children.NW,ctx);
|
365
|
-
this._drawBranch(branch.children.NE,ctx);
|
366
|
-
this._drawBranch(branch.children.SE,ctx);
|
367
|
-
this._drawBranch(branch.children.SW,ctx);
|
368
|
-
}
|
369
|
-
ctx.strokeStyle = color;
|
370
|
-
ctx.beginPath();
|
371
|
-
ctx.moveTo(branch.range.minX,branch.range.minY);
|
372
|
-
ctx.lineTo(branch.range.maxX,branch.range.minY);
|
373
|
-
ctx.stroke();
|
374
|
-
|
375
|
-
ctx.beginPath();
|
376
|
-
ctx.moveTo(branch.range.maxX,branch.range.minY);
|
377
|
-
ctx.lineTo(branch.range.maxX,branch.range.maxY);
|
378
|
-
ctx.stroke();
|
379
|
-
|
380
|
-
ctx.beginPath();
|
381
|
-
ctx.moveTo(branch.range.maxX,branch.range.maxY);
|
382
|
-
ctx.lineTo(branch.range.minX,branch.range.maxY);
|
383
|
-
ctx.stroke();
|
384
|
-
|
385
|
-
ctx.beginPath();
|
386
|
-
ctx.moveTo(branch.range.minX,branch.range.maxY);
|
387
|
-
ctx.lineTo(branch.range.minX,branch.range.minY);
|
388
|
-
ctx.stroke();
|
389
|
-
|
390
|
-
/*
|
391
|
-
if (branch.mass > 0) {
|
392
|
-
ctx.circle(branch.centerOfMass.x, branch.centerOfMass.y, 3*branch.mass);
|
393
|
-
ctx.stroke();
|
394
|
-
}
|
395
|
-
*/
|
396
|
-
}
|
397
|
-
|
398
|
-
};
|
@@ -1,64 +0,0 @@
|
|
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
|
-
};
|