manyBody.js 多体力,用于模拟引力及静电力
布局中的理论:
- 交叉的边要尽量少
- 边长要尽量均衡
- 布局要尽量对称
- 单位面积能放尽量多的结点 我感觉这些基本在manyBody.js里边都能找到答案。
推荐先阅读的博客
初始化的时候做的事情
- 赋值nodes
- strengths [-30, -30, -30, -30, -30, -30, -30, -30]
代码
force方法
function force(_) {
var i, n = nodes.length, tree = quadtree(nodes, x, y).visitAfter(accumulate);
for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply);
}
复制代码
accumulate 方法
function accumulate(quad) {
var strength = 0, q, c, weight = 0, x, y, i;
// For internal nodes, accumulate forces from child quadrants.
// 对于内部节点,从子象限中累积力
if (quad.length) {
for (x = y = i = 0; i < 4; ++i) {
if ((q = quad[i]) && (c = Math.abs(q.value))) {
strength += q.value, weight += c, x += c * q.x, y += c * q.y;
}
}
// 这里的weight,x,y计算都是累加计算的会更具总统的节点数,推测你属于哪个像限。
quad.x = x / weight;
quad.y = y / weight;
}
// For leaf nodes, accumulate forces from coincident quadrants.
// 对于叶节点,从共同的象限中累积力。
else {
q = quad;
q.x = q.data.x;
q.y = q.data.y;
do strength += strengths[q.data.index];
while (q = q.next);
}
quad.value = strength;
}
复制代码
apply 方法
function apply(quad, x1, _, x2) {
if (!quad.value) return true;
var x = quad.x - node.x,
y = quad.y - node.y,
w = x2 - x1,
l = x * x + y * y;
// Apply the Barnes-Hut approximation if possible.
// 如果可能的话,应用Barnes-Hut近似
// Limit forces for very close nodes; randomize direction if coincident.
// 限制非常近的节点的力;如果发生意外,随机化方向。
if (w * w / theta2 < l) {
if (l < distanceMax2) {
if (x === 0) x = jiggle(), l += x * x;
if (y === 0) y = jiggle(), l += y * y;
if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
node.vx += x * quad.value * alpha / l;
node.vy += y * quad.value * alpha / l;
}
return true;
}
// Otherwise, process points directly.
else if (quad.length || l >= distanceMax2) return;
// Limit forces for very close nodes; randomize direction if coincident.
if (quad.data !== node || quad.next) {
if (x === 0) x = jiggle(), l += x * x;
if (y === 0) y = jiggle(), l += y * y;
if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
}
do if (quad.data !== node) {
w = strengths[quad.data.index] * alpha / l;
node.vx += x * w;
node.vy += y * w;
} while (quad = quad.next);
}
复制代码
数据跟踪
数据处理前的数据
accumulate
ps: 这个函数的作用是为了确定三个值,quad.x,quad.y,quad.value
来分析下每一次quad打印出的内容
第1次
第2次
第3次
第4次
第5次 有了变化了
第6次
第7次
第8次
第9次
第10次
第11次
第12次 分两个图
apply
第一次执行
ps: 这里的w是_x0和_x1计算得来了。if没有执行。数据和accumulate的一样没有改变。
第二次执行
第三次执行 node name0 匹配 quad name7
第四次执行
第五次执行
第六次执行 node name0 匹配 quad name4
第七次执行 node name0 匹配 quad name1
第八次执行
第九次执行
第十次执行
第十一次执行 node name0 匹配 quad name6
第十二次执行
第十三次执行 开始name1
第十四次执行
第十五次执行 node name1 匹配 quad name7
第十六次执行 node name1 匹配 quad name2
第十七次执行
第十八次执行 node name1 匹配 quad name4
第十九次执行
第二次执行
第二十二次执行
第二十二次执行
第二十三次执行
第二十四次执行 node name1 匹配 quad name3
第二十五次执行 name2开始
第二十六次执行 name2开始
第二十七次执行
第二十八次执行
第二十九次执行
ps: 这个值得看,数据居然进去了。
第三十次执行
第三十一次执行
第三十二次执行
第三十三次执行
第三十四次
中间有省略的没有命中的
第三十五次
第三十六次
第三十七次
第三十八次
第三十九次
第四十次
第四十一次
第四十二次
第四十三次
第四十四次
第四十五次
第四十六次
第四十七次
第四十八次
第四十九次
第五十次
第五十一次
第五十二次
第五十三次
第五十四次
第五十五次
第五十六次
第五十七次
第五十八次
第五十九次
第六十次
图画
结论
d3-quadtree 四叉树的这个库进行了一个事情,就是把数据进行了分类,存储。 manyBody.js就是利用四叉树就行x,y计算的一个例子。 而你可以调用visitAfter这个后序遍历方法,先遍历子节点,在遍历高层结点方法计算出每个节点对应的x,y,strength排斥力。 然后在调用visit方法利用x,y,strength对每个节点的vx,vy进行矫正。 这两个方法的实现另一种方法请看 第三版本的visit和visitAfter的实现
好像不同的时间,初始化的图形还不同。
9.23 12:46