source: node_modules/d3-force/src/manyBody.js

Last change on this file was e4c61dd, checked in by istevanoska <ilinastevanoska@…>, 6 months ago

Prototype 1.1

  • Property mode set to 100644
File size: 3.2 KB
Line 
1import {quadtree} from "d3-quadtree";
2import constant from "./constant.js";
3import jiggle from "./jiggle.js";
4import {x, y} from "./simulation.js";
5
6export default function() {
7 var nodes,
8 node,
9 random,
10 alpha,
11 strength = constant(-30),
12 strengths,
13 distanceMin2 = 1,
14 distanceMax2 = Infinity,
15 theta2 = 0.81;
16
17 function force(_) {
18 var i, n = nodes.length, tree = quadtree(nodes, x, y).visitAfter(accumulate);
19 for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply);
20 }
21
22 function initialize() {
23 if (!nodes) return;
24 var i, n = nodes.length, node;
25 strengths = new Array(n);
26 for (i = 0; i < n; ++i) node = nodes[i], strengths[node.index] = +strength(node, i, nodes);
27 }
28
29 function accumulate(quad) {
30 var strength = 0, q, c, weight = 0, x, y, i;
31
32 // For internal nodes, accumulate forces from child quadrants.
33 if (quad.length) {
34 for (x = y = i = 0; i < 4; ++i) {
35 if ((q = quad[i]) && (c = Math.abs(q.value))) {
36 strength += q.value, weight += c, x += c * q.x, y += c * q.y;
37 }
38 }
39 quad.x = x / weight;
40 quad.y = y / weight;
41 }
42
43 // For leaf nodes, accumulate forces from coincident quadrants.
44 else {
45 q = quad;
46 q.x = q.data.x;
47 q.y = q.data.y;
48 do strength += strengths[q.data.index];
49 while (q = q.next);
50 }
51
52 quad.value = strength;
53 }
54
55 function apply(quad, x1, _, x2) {
56 if (!quad.value) return true;
57
58 var x = quad.x - node.x,
59 y = quad.y - node.y,
60 w = x2 - x1,
61 l = x * x + y * y;
62
63 // Apply the Barnes-Hut approximation if possible.
64 // Limit forces for very close nodes; randomize direction if coincident.
65 if (w * w / theta2 < l) {
66 if (l < distanceMax2) {
67 if (x === 0) x = jiggle(random), l += x * x;
68 if (y === 0) y = jiggle(random), l += y * y;
69 if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
70 node.vx += x * quad.value * alpha / l;
71 node.vy += y * quad.value * alpha / l;
72 }
73 return true;
74 }
75
76 // Otherwise, process points directly.
77 else if (quad.length || l >= distanceMax2) return;
78
79 // Limit forces for very close nodes; randomize direction if coincident.
80 if (quad.data !== node || quad.next) {
81 if (x === 0) x = jiggle(random), l += x * x;
82 if (y === 0) y = jiggle(random), l += y * y;
83 if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
84 }
85
86 do if (quad.data !== node) {
87 w = strengths[quad.data.index] * alpha / l;
88 node.vx += x * w;
89 node.vy += y * w;
90 } while (quad = quad.next);
91 }
92
93 force.initialize = function(_nodes, _random) {
94 nodes = _nodes;
95 random = _random;
96 initialize();
97 };
98
99 force.strength = function(_) {
100 return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initialize(), force) : strength;
101 };
102
103 force.distanceMin = function(_) {
104 return arguments.length ? (distanceMin2 = _ * _, force) : Math.sqrt(distanceMin2);
105 };
106
107 force.distanceMax = function(_) {
108 return arguments.length ? (distanceMax2 = _ * _, force) : Math.sqrt(distanceMax2);
109 };
110
111 force.theta = function(_) {
112 return arguments.length ? (theta2 = _ * _, force) : Math.sqrt(theta2);
113 };
114
115 return force;
116}
Note: See TracBrowser for help on using the repository browser.