国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

d3-force 力導(dǎo)圖 源碼解讀與原理分析【一】

luckyyulin / 2603人閱讀

摘要:設(shè)置力導(dǎo)圖點(diǎn)陣中心碰撞其他引用模塊構(gòu)造常量函數(shù)微小晃動(dòng)隨機(jī)數(shù)四叉樹模塊設(shè)置力導(dǎo)圖點(diǎn)陣中心此處代碼使用的是單例對(duì)象模式,讀者要注意,切勿與類對(duì)象理解混了。

首先先推薦一下某呆翻譯的d3-force的中文文檔:https://github.com/xswei/D3-V... 。
在我們解讀源碼前還請(qǐng)讀者先熟悉一下force相關(guān)的API,以及es6語法 .

如有分析不當(dāng)之處還請(qǐng)留言指出,謝謝~

那我們進(jìn)入正題吧

D3-force 有什么

我們來看一下index.js 這個(gè)文件大家可以理解為force的對(duì)外統(tǒng)一出口。當(dāng)然你也可以自定義使用這些模塊。

// index.js
export {default as forceCenter} from "./src/center"; // 設(shè)置力導(dǎo)圖點(diǎn)陣中心
export {default as forceCollide} from "./src/collide"; // 碰撞
export {default as forceLink} from "./src/link";
export {default as forceManyBody} from "./src/manyBody";
export {default as forceSimulation} from "./src/simulation";
export {default as forceX} from "./src/x";
export {default as forceY} from "./src/y";

其他引用模塊

//collide.js
import constant from "./constant";    // 構(gòu)造常量函數(shù)
import jiggle from "./jiggle";        // 微小晃動(dòng)隨機(jī)數(shù)
import {quadtree} from "d3-quadtree"; // 四叉樹
模塊1:center.js 設(shè)置力導(dǎo)圖點(diǎn)陣中心

此處代碼使用的是單例對(duì)象模式,讀者要注意,切勿與類對(duì)象理解混了。

export default function(x, y) {
  var nodes; // 使用閉包構(gòu)建私有變量,存儲(chǔ)nodes。

  if (x == null) x = 0; // 力導(dǎo)圖中心位置 x 默認(rèn)值為0
  if (y == null) y = 0; // 力導(dǎo)圖中心位置 y 默認(rèn)值為0
   
  // force 單例對(duì)象
  function force() {
    var i,
        n = nodes.length,
        node,   // 臨時(shí)變量用于循環(huán)
        sx = 0, // 臨時(shí)變量用于計(jì)算
        sy = 0; // 臨時(shí)變量用于計(jì)算
    
    for (i = 0; i < n; ++i) {
      // sx = sum(node.x);  節(jié)點(diǎn)x之和
      // sy = sum(node.y);  節(jié)點(diǎn)y之和
      node = nodes[i], sx += node.x, sy += node.y;
    }

    for (sx = sx / n - x, sy = sy / n - y, i = 0; i < n; ++i) {
      // sx / n 是點(diǎn)陣的中心x坐標(biāo);sy / n 是點(diǎn)陣的中心y坐標(biāo)。
      // node.x = node.x + (x - (sx / n)); 該計(jì)算與此表達(dá)式等價(jià),這樣讀者應(yīng)該更好理解;
      // 坐標(biāo)加減即平移坐標(biāo),即將整個(gè)點(diǎn)陣中心平移到坐標(biāo)(x,y)
      node = nodes[i], node.x -= sx, node.y -= sy;
    }
  }
  // 初始化,為nodes私有變量賦值
  force.initialize = function(_) {
    nodes = _;
  };
  // 如果傳入?yún)?shù)x則設(shè)置x,否則返回當(dāng)前力導(dǎo)圖中心位置 x
  force.x = function(_) {
    return arguments.length ? (x = +_, force) : x; 
  };
  // 如果傳入?yún)?shù)y則設(shè)置y,否則返回當(dāng)前力導(dǎo)圖中心位置 y
  force.y = function(_) {
    return arguments.length ? (y = +_, force) : y;  
  };

  return force; // 返回 force對(duì)象
}
模塊2:constant.js 創(chuàng)建一個(gè)常量函數(shù)
// 構(gòu)造一個(gè)返回參數(shù)值的常量函數(shù)
// let a = constant(123); a() 輸出: 123
export default function(x) {
  return function() {
    return x;
  };
}
模塊3:jiggle.js 微小晃動(dòng)隨機(jī)數(shù)
// jiggle.js
// 微小晃動(dòng)隨機(jī)數(shù)
export default function() {
  return (Math.random() - 0.5) * 1e-6; // 1e-6 ==> 1*10的-6次方
}
模塊4:collide.js 碰撞
import constant from "./constant";    // 構(gòu)造常量函數(shù)
import jiggle from "./jiggle";        // 微小晃動(dòng)隨機(jī)數(shù)
import {quadtree} from "d3-quadtree"; // 四叉樹

// vx vy 是指當(dāng)前節(jié)點(diǎn)的運(yùn)動(dòng)速度
function x(d) {
  return d.x + d.vx; // 運(yùn)動(dòng)一步 x + vx 
}

function y(d) {
  return d.y + d.vy; // 運(yùn)動(dòng)一步 y + vy
}

export default function(radius) {
  var nodes,
      radii,
      strength = 1, // 力度
      iterations = 1;
      
  // radius 設(shè)置默認(rèn)值,值類型為常量函數(shù);
  if (typeof radius !== "function") radius = constant(radius == null ? 1 : +radius);

  // 單例對(duì)象模式
  function force() {
    var i, n = nodes.length,
        tree,
        node,
        xi,
        yi,
        ri,  // 半徑
        ri2; // 半徑平方
// -------------- 四叉樹相關(guān),**后文有詳細(xì)分析**----------
    for (var k = 0; k < iterations; ++k) {
      // 以x,y訪問器構(gòu)建一個(gè)四叉樹,即節(jié)點(diǎn)運(yùn)動(dòng)到下一步位置為坐標(biāo)(就像我們走夜路,探出一步試試看)
      // visitAfter是后序遍歷樹的節(jié)點(diǎn),執(zhí)行prepare為每個(gè)節(jié)點(diǎn)求半徑r,參數(shù)為各個(gè)節(jié)點(diǎn),
      // 返回樹的跟節(jié)點(diǎn)root。
      tree = quadtree(nodes, x, y).visitAfter(prepare); 
      // for循環(huán)普通遍歷節(jié)點(diǎn)
      for (i = 0; i < n; ++i) {
        node = nodes[i];
        ri = radii[node.index], ri2 = ri * ri; // r平方(勾股定理用)
        xi = node.x + node.vx;// 運(yùn)動(dòng)一步 x + vx 
        yi = node.y + node.vy;// 運(yùn)動(dòng)一步 y + vy 
        // 前序遍歷所有節(jié)點(diǎn),apply返回true則不訪問其子節(jié)點(diǎn)
        tree.visit(apply); 
      }
    }

    function apply(quad, x0, y0, x1, y1) {
      var data = quad.data, rj = quad.r, r = ri + rj;// 兩個(gè)點(diǎn)與其作用域構(gòu)成兩個(gè)圓,請(qǐng)參考之前的文章,圓與圓的碰撞測(cè)驗(yàn)。
      if (data) { // 存在data即葉子節(jié)點(diǎn),每個(gè)葉子節(jié)點(diǎn)為一個(gè)坐標(biāo)點(diǎn)
        if (data.index > node.index) {
          // 因?yàn)檫@是二重循環(huán),所有index小于自身的點(diǎn)坐標(biāo)已經(jīng)與自身判斷過了,此處是為了避免重復(fù)測(cè)驗(yàn)
          // 設(shè)第一重循環(huán)Node[i]為節(jié)點(diǎn)A(xi,yi) 第二重循環(huán)為節(jié)點(diǎn)B(data.x,data.y)下一步運(yùn)動(dòng)(+=vx,+=vy)
          var x = xi - data.x - data.vx, // Ax - Bx
              y = yi - data.y - data.vy, // Ay - By
              l = x * x + y * y;  // 勾股定理 d^2 = x^2 +y^2
          if (l < r * r) { // 判斷是否碰撞,如果碰撞執(zhí)行以下,l:實(shí)際距離平方,r:半徑之和
            if (x === 0) x = jiggle(), l += x * x; // 避免x值為0
            if (y === 0) y = jiggle(), l += y * y; // 避免y值為0
            // strength:碰撞力的強(qiáng)度,可以理解為兩點(diǎn)之間的斥力系數(shù)
            // 見后文碰撞測(cè)驗(yàn)的圖
            // l = 重疊長(zhǎng)度/實(shí)際距離 * 碰撞力度
            // 重疊約多,斥力越大。斥力影響點(diǎn)的運(yùn)動(dòng)速度
            l = (r - (l = Math.sqrt(l))) / l * strength; 
            // 根據(jù)求出的斥力計(jì)算AB點(diǎn)新的運(yùn)動(dòng)速度與方向
            // A點(diǎn)x方向的運(yùn)動(dòng)速度 
            // A速度 += B速度 -= 使得AB兩點(diǎn)往相反方向運(yùn)動(dòng)。注意,這里的x是B到A的距離,所有是A+= ,B-=
            // 但斥力的原因會(huì)使得節(jié)點(diǎn)的vx ,vy 趨近于0.
            // node.vx = B-A點(diǎn)x方向距離 *= 斥力 * B半徑平方(rj = B半徑平方)/( A半徑平方+B半徑平方);r = B半徑平方/( A半徑平方+B半徑平方)
            node.vx += (x *= l) * (r = (rj *= rj) / (ri2 + rj));
            // 同x方向
            node.vy += (y *= l) * r;
            data.vx -= x * (r = 1 - r);
            data.vy -= y * r;
          }
        }
        return;
      }
      // 如果是父節(jié)點(diǎn),這里需要讀者理解四叉樹【后面一篇文章會(huì)講解】
      // 節(jié)點(diǎn)坐標(biāo)為中心的正方形,如果沒有覆蓋到該父節(jié)點(diǎn)的正方形區(qū)域,這改點(diǎn)與此父節(jié)點(diǎn)的任何子節(jié)點(diǎn)都不會(huì)發(fā)生碰撞,則無需遍歷其子節(jié)點(diǎn)校驗(yàn)。
      // 返回true 不遍歷子節(jié)點(diǎn)
      // 這也是v4 相比v3對(duì)性能優(yōu)化最重要的一個(gè)步驟,成倍的減少計(jì)算量
      return x0 > xi + r || x1 < xi - r || y0 > yi + r || y1 < yi - r;
    }
  }
  // 遍歷樹節(jié)點(diǎn)過濾器,返回true節(jié)點(diǎn)不可見
  function prepare(quad) {
    // quad.data是葉子節(jié)點(diǎn)才有的,所以這里是判斷是否是葉子節(jié)點(diǎn)
    if (quad.data) return quad.r = radii[quad.data.index];
    for (var i = quad.r = 0; i < 4; ++i) {
      // 因?yàn)槭呛笮虮闅v,所以節(jié)點(diǎn)的葉子節(jié)點(diǎn)一定在之前已經(jīng)遍歷過。
      // 取葉子節(jié)點(diǎn)四個(gè)象限最大的r
      if (quad[i] && quad[i].r > quad.r) {
        quad.r = quad[i].r;
      }
    }
  }
//---------------------------------------------------------------------------------------
  function initialize() {
    if (!nodes) return; // 判斷是否有節(jié)點(diǎn)
    var i, n = nodes.length, node;
    radii = new Array(n);
    // 按照node.index索引排序nodes 并又 radius【后文解析】 計(jì)算出半徑 后 存儲(chǔ)在 radii 
    for (i = 0; i < n; ++i) node = nodes[i], radii[node.index] = +radius(node, i, nodes);
  }

  force.initialize = function(_) {
    nodes = _; // 賦值節(jié)點(diǎn)
    initialize(); // 初始化
  };

  force.iterations = function(_) {
    // get or set iterations (迭代次數(shù))
    return arguments.length ? (iterations = +_, force) : iterations;
  };
  
  force.strength = function(_) {
    // get or set strength(力度)
    return arguments.length ? (strength = +_, force) : strength;
  };

  force.radius = function(_) {
    // 前端加+號(hào) 將字符串轉(zhuǎn)為number  +"123" === 123
    // 有參數(shù):
    // 執(zhí)行1:(radius = typeof _ === "function" ? _ : constant(+_)
     //radius 值是一個(gè)返回自身的函數(shù)
    // 執(zhí)行2:initialize()
    // 執(zhí)行3:return force
    // 無參數(shù):
    // 執(zhí)行:return radius
    return arguments.length ? (radius = typeof _ === "function" ? _ : constant(+_), initialize(), force) : radius;
  };

  return force;
}


碰撞測(cè)驗(yàn)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/81936.html

相關(guān)文章

  • d3-force 導(dǎo)圖 源碼解讀原理分析【二 : 四叉樹()】

    摘要:我們?cè)谏衔脑创a解析發(fā)現(xiàn)版的節(jié)點(diǎn)碰撞采用四叉樹進(jìn)行了優(yōu)化。那么版本的力導(dǎo)圖具體和版的有何不同點(diǎn)呢,四叉樹又如何優(yōu)化碰撞校驗(yàn)的呢原文鏈接被重命名為。性能的提高歸功于的新的四叉樹。 我們?cè)谏衔脑创a解析發(fā)現(xiàn)v4版的節(jié)點(diǎn)碰撞采用四叉樹進(jìn)行了優(yōu)化。那么V4版本的力導(dǎo)圖具體和v3版的有何不同點(diǎn)呢,四叉樹又如何優(yōu)化碰撞校驗(yàn)的呢? v3-force VS v4-force https://github...

    pepperwang 評(píng)論0 收藏0
  • 高并發(fā)

    摘要:表示的是兩個(gè),當(dāng)其中任意一個(gè)計(jì)算完并發(fā)編程之是線程安全并且高效的,在并發(fā)編程中經(jīng)常可見它的使用,在開始分析它的高并發(fā)實(shí)現(xiàn)機(jī)制前,先講講廢話,看看它是如何被引入的。電商秒殺和搶購(gòu),是兩個(gè)比較典型的互聯(lián)網(wǎng)高并發(fā)場(chǎng)景。 干貨:深度剖析分布式搜索引擎設(shè)計(jì) 分布式,高可用,和機(jī)器學(xué)習(xí)一樣,最近幾年被提及得最多的名詞,聽名字多牛逼,來,我們一步一步來擊破前兩個(gè)名詞,今天我們首先來說說分布式。 探究...

    supernavy 評(píng)論0 收藏0
  • 高并發(fā)

    摘要:表示的是兩個(gè),當(dāng)其中任意一個(gè)計(jì)算完并發(fā)編程之是線程安全并且高效的,在并發(fā)編程中經(jīng)常可見它的使用,在開始分析它的高并發(fā)實(shí)現(xiàn)機(jī)制前,先講講廢話,看看它是如何被引入的。電商秒殺和搶購(gòu),是兩個(gè)比較典型的互聯(lián)網(wǎng)高并發(fā)場(chǎng)景。 干貨:深度剖析分布式搜索引擎設(shè)計(jì) 分布式,高可用,和機(jī)器學(xué)習(xí)一樣,最近幾年被提及得最多的名詞,聽名字多牛逼,來,我們一步一步來擊破前兩個(gè)名詞,今天我們首先來說說分布式。 探究...

    ddongjian0000 評(píng)論0 收藏0
  • 高并發(fā)

    摘要:表示的是兩個(gè),當(dāng)其中任意一個(gè)計(jì)算完并發(fā)編程之是線程安全并且高效的,在并發(fā)編程中經(jīng)常可見它的使用,在開始分析它的高并發(fā)實(shí)現(xiàn)機(jī)制前,先講講廢話,看看它是如何被引入的。電商秒殺和搶購(gòu),是兩個(gè)比較典型的互聯(lián)網(wǎng)高并發(fā)場(chǎng)景。 干貨:深度剖析分布式搜索引擎設(shè)計(jì) 分布式,高可用,和機(jī)器學(xué)習(xí)一樣,最近幾年被提及得最多的名詞,聽名字多牛逼,來,我們一步一步來擊破前兩個(gè)名詞,今天我們首先來說說分布式。 探究...

    wangdai 評(píng)論0 收藏0
  • ??思維導(dǎo)圖整理大廠面試高頻數(shù)組10: 3種方法徹底解決中位數(shù)問題, 力扣4??

    此專欄文章是對(duì)力扣上算法題目各種方法的總結(jié)和歸納, 整理出最重要的思路和知識(shí)重點(diǎn)并以思維導(dǎo)圖形式呈現(xiàn), 當(dāng)然也會(huì)加上我對(duì)導(dǎo)圖的詳解. 目的是為了更方便快捷的記憶和回憶算法重點(diǎn)(不用每次都重復(fù)看題解), 畢竟算法不是做了一遍就能完全記住的. 所以本文適合已經(jīng)知道解題思路和方法, 想進(jìn)一步加強(qiáng)理解和記憶的朋友, 并不適合第一次接觸此題的朋友(可以根據(jù)題號(hào)先去力扣看看官方題解, 然后再看本文內(nèi)容). 關(guān)...

    XanaHopper 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<