d3.js 关于力引导图的manyBody.js的简单阅读

manyBody.js 多体力,用于模拟引力及静电力

布局中的理论:
  • 交叉的边要尽量少
  • 边长要尽量均衡
  • 布局要尽量对称
  • 单位面积能放尽量多的结点 我感觉这些基本在manyBody.js里边都能找到答案。
推荐先阅读的博客

自己的力引导图 安安博客1 安安博客2 力引导算法深入理解

初始化的时候做的事情

  • 赋值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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值