欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

D3.js實(shí)現(xiàn)力向?qū)D的繪制教程詳解

 更新時(shí)間:2022年11月21日 14:07:41   作者:FinGet  
力向?qū)D是繪圖的一種算法,實(shí)現(xiàn)了用以模擬粒子物理運(yùn)動(dòng)的?velocity?Verlet?數(shù)值積分器。本文將利用D3.js實(shí)現(xiàn)力向?qū)D的繪制,需要的可以參考一下

力向?qū)D是繪圖的一種算法,實(shí)現(xiàn)了用以模擬粒子物理運(yùn)動(dòng)的 velocity Verlet 數(shù)值積分器。仿真思路如下: 它假設(shè)任意單位時(shí)間步長 Δt = 1,所有的粒子的單位質(zhì)量常量 m = 1。作用在每個(gè)粒子上的合力 F 相當(dāng)于在單位時(shí)間 Δt 內(nèi)的恒定加速度 a。并且可以簡單的通過為每個(gè)粒子添加速度并計(jì)算粒子的位置來模擬仿真。

在二維或三維空間里配置節(jié)點(diǎn)。節(jié)點(diǎn)之間用線連接,稱為連線。各連線的長度幾乎相等,且盡可能不相交。節(jié)點(diǎn)和連線都被施加了力的作用。力的大小是根據(jù)節(jié)點(diǎn)和連線的相對(duì)位置計(jì)算的。根據(jù)力的作用來計(jì)算節(jié)點(diǎn)和連線的運(yùn)動(dòng)軌跡,并不斷降低它們的能量,最終達(dá)到一種能量很低的穩(wěn)定狀態(tài)

D3 Force 是一種模擬物理運(yùn)動(dòng)原理的繪圖算法,一開始給所有節(jié)點(diǎn)設(shè)置任意的初始值配置,接著根據(jù)配置的屬性,讓每個(gè)節(jié)點(diǎn)按屬性去運(yùn)動(dòng)——這就是每個(gè)節(jié)點(diǎn)之間的力。

力又分為斥力引力,每個(gè)節(jié)點(diǎn)之間的力就是斥力,而整個(gè)圖形又存在引力,就像人可以在地面上起跳,但是由于地心引力,我們不會(huì)跳的很高,最終也都會(huì)落回地面。節(jié)點(diǎn)在各種力的交互作用下,碰撞聚攏,逐漸收攏到一個(gè)穩(wěn)定的位置,可以通過alpha屬性去設(shè)置整個(gè)過程的速度,還可以設(shè)置摩擦力velocityDecay去調(diào)整速度。

五種力

D3 一共給我們提供了五種力點(diǎn)擊查看Demo:

向心力

  • d3.forceCenter([x, y]) - 創(chuàng)建一個(gè)中心作用力.
  • center.x - 設(shè)置中心作用力的 x -坐標(biāo).
  • center.y - 設(shè)置中心作用力的 y -坐標(biāo).

向心力可以將所有的節(jié)點(diǎn)的中心統(tǒng)一整體的向指定的位置 ⟨x,y⟩ 移動(dòng)。這種力強(qiáng)制修改每個(gè)節(jié)點(diǎn)的位置,但是不會(huì)修改速度,因?yàn)樾薷乃俣葧?huì)造成節(jié)點(diǎn)在期望的位置附近抖動(dòng)。這種力可以輔助保持所有的節(jié)點(diǎn)在視口中心。

碰撞力

節(jié)點(diǎn)之間相互碰撞的力,這個(gè)斥力會(huì)防止節(jié)點(diǎn)重合,可以使用 strength設(shè)置斥力的強(qiáng)弱。

  • d3.forceCollide - 創(chuàng)建一個(gè)圓形區(qū)域的碰撞檢測力模型.
  • collide.radius - 設(shè)置碰撞半徑.
  • collide.strength - 設(shè)置碰撞檢測力模型的強(qiáng)度.
  • collide.iterations - 設(shè)置迭代次數(shù).

連接力(彈簧力)

使用d3.forceLink 將兩個(gè)節(jié)點(diǎn)添加連線到一起之后,就可以設(shè)置連接力了,它會(huì)根據(jù)兩節(jié)點(diǎn)之間的距離,拉近或推遠(yuǎn)節(jié)點(diǎn),力的強(qiáng)弱和兩節(jié)點(diǎn)間的距離成正比,就像彈簧一樣,所以也叫彈簧力。

  • d3.forceLink - 創(chuàng)建一個(gè) link(彈簧) 作用力.
  • link.links - 設(shè)置彈簧作用力的邊.
  • link.id - 設(shè)置邊元素中節(jié)點(diǎn)的查找方式是索引還是 id 字符串.
  • link.distance - 設(shè)置 link 的距離.
  • link.strength - 設(shè)置 link 的強(qiáng)度.
  • link.iterations - 設(shè)置迭代次數(shù).

電荷力

模擬所有節(jié)點(diǎn)之間的相互作用力,如果是正值,則相互吸引,如果是負(fù)值,則相互排斥。這樣就可以模擬電荷的吸引力,力的強(qiáng)弱也和節(jié)點(diǎn)間的距離有關(guān)。

  • d3.forceManyBody - 創(chuàng)建一個(gè)電荷作用力模型.
  • manyBody.strength - 設(shè)置電荷力模型的強(qiáng)度.
  • manyBody.theta - 設(shè)置 Barnes–Hut 算法的精度.
  • manyBody.distanceMin - 限制節(jié)點(diǎn)之間的最小距離.
  • manyBody.distanceMax - 限制節(jié)點(diǎn)之間的最大距離.

徑向力

設(shè)定一個(gè)圓,這樣所有的節(jié)點(diǎn)都會(huì)有一個(gè)指向圓心的力,這樣每個(gè)節(jié)點(diǎn)都會(huì)集中到圓上。

  • d3.forceRadial - 創(chuàng)建一個(gè)環(huán)形布局的作用力.
  • radial.strength - 設(shè)置力強(qiáng)度.
  • radial.radius - 設(shè)置目標(biāo)半徑.
  • radial.x - 設(shè)置環(huán)形作用力的目標(biāo)中心 x -坐標(biāo).
  • radial.y - 設(shè)置環(huán)形作用力的目標(biāo)中心 y -坐標(biāo).

五種力是可以疊加使用的!

力向?qū)D

在創(chuàng)建力學(xué)導(dǎo)圖時(shí),我們需要先創(chuàng)建一個(gè)新的力學(xué)模型d3.forceSimulation,并指定節(jié)點(diǎn)nodes

1.d3.forceSimulation - 創(chuàng)建一個(gè)新的力學(xué)仿真.

2.simulation.restart - 重新啟動(dòng)仿真的定時(shí)器.

3.simulation.stop - 停止仿真的定時(shí)器.

4.simulation.tick - 進(jìn)行一步仿真模擬.

5.simulation.nodes - 設(shè)置仿真的節(jié)點(diǎn).

每個(gè) node 必須是一個(gè)對(duì)象類型,下面的幾個(gè)屬性將會(huì)被仿真系統(tǒng)添加:

  • index - 節(jié)點(diǎn)在 nodes 數(shù)組中的索引
  • x - 節(jié)點(diǎn)當(dāng)前的 x-坐標(biāo)
  • y - 節(jié)點(diǎn)當(dāng)前的 y-坐標(biāo)
  • vx - 節(jié)點(diǎn)當(dāng)前的 x-方向速度
  • vy - 節(jié)點(diǎn)當(dāng)前的 y-方向速度

5.simulation.alpha - 設(shè)置當(dāng)前的 alpha 值.

6.simulation.alphaMin - 設(shè)置最小 alpha 閾值.

7.simulation.alphaDecay - 設(shè)置 alpha 衰減率.

為0的話,永遠(yuǎn)都不會(huì)停

8.simulation.alphaTarget - 設(shè)置目標(biāo) alpha 值.

9.simulation.velocityDecay - 設(shè)置速度衰減率.

10.simulation.force - 添加或移除一個(gè)力模型.

11.simulation.find - 根據(jù)指定的位置找出最近的節(jié)點(diǎn).

12.simulation.on - 添加或移除事件監(jiān)聽器.

  • tick - 仿真內(nèi)部定時(shí)器每次 tick 之后。
  • end - 當(dāng) alpha < alphaMin 時(shí)仿真內(nèi)部定時(shí)器停止。
const simulation = d3.forceSimulation(nodes) 
// 連接力
.force('link', d3.forceLink()) 
// 在 y軸方向上施加一個(gè)力 
.force('y', d3.forceY().strength(0.025)) 
// 電荷力 
.force('charge', d3.forceManyBody()) 
// 碰撞力
.force('collision', d3.forceCollide().radius(d => 4)) 
//  向心力
.force('center', d3.forceCenter(width / 2, height / 2))

接下來我們繪制一下文章開頭的那張關(guān)系圖點(diǎn)擊查看Demo

創(chuàng)建模擬數(shù)據(jù)

const nodes = [
    {name: "張三"}
    ...
]

const links = [
    { source: 0, target: 1, relation: "關(guān)系1"}
    ...
]

創(chuàng)建力模型

let simulation = d3.forceSimulation(nodes)
    .force("link", d3.forceLink(links).distance(100)) // 連接力

繪制節(jié)點(diǎn)和連線

// 畫線
function drawLine() {
    let lines = svg.append("g")
        .selectAll(".force-line")
        .data(links)
        .enter()
        .append("line")
        .attr("class", "line")
        .attr("stroke", "#999")
        .attr("stroke-width", "1px");
    return lines;
}
let lines = drawLine();

// 畫節(jié)點(diǎn)節(jié)點(diǎn)盒子

function drawCircle() {
    let nodeGroups = svg.append("g")
        .attr("class", "nodes-box")
        .selectAll(".force-node")
        .data(nodes)
        .enter()
        .append("g")
        .attr("class", "force-circle")

    nodeGroups.append("circle")
        .attr("class", "force-circle")
        .attr("r", 20)
        .style("fill",(d, i) => color(i));

    nodeGroups.append("text")
        .attr("class", "force-text")
        .attr("dy", ".33em")
        .attr("font-size", "12px")
        .attr("text-anchor", "middle")
        .style("fill", "#eee")
        .text(d => d.name);
    return nodeGroups;
}
let nodesCircle = drawCircle();

到這一步呀,就只能看到畫布的左上角,原點(diǎn)位置 有circle圖形,因?yàn)榱W(xué)模型,是動(dòng)態(tài)計(jì)算節(jié)點(diǎn)和連線的位置,所以我們需要?jiǎng)討B(tài)的去更新它們的位置<x, y>,此時(shí)我們需要監(jiān)聽的就是tick.

監(jiān)聽 tick

let simulation = d3.forceSimulation(nodes)
    .force("link", d3.forceLink(links).distance(100));
    .on("tick", ticked);
    
function ticked() 
    lines
        .attr("x1", (d) => d.source.x)
        .attr("y1", (d) => d.source.y)
        .attr("x2", (d) => d.target.x)
        .attr("y2", (d) => d.target.y);

    // 這里就不適合 去改變circle的圓心位置了,因?yàn)橛形淖执嬖?,改變整個(gè)circleGroup的transform
    nodesCircle.attr("transform", function (d) {
        // d.fx=d.x;d.fy=d.y; 固定位置
        return "translate(" + d.x + ", " + d.y + ")";
    });
}

我們可以添加一個(gè)向心力,讓整個(gè)圖形出現(xiàn)在畫布中心。

添加向心力

let simulation = d3.forceSimulation(nodes)
    .force("center", d3.forceCenter(width / 2, height / 2)) // 用指定的x坐標(biāo)和y坐標(biāo)創(chuàng)建一個(gè)居中力
    .force("link", d3.forceLink(links).distance(100)) //
    .on("tick", ticked);

到這里,我們可以發(fā)現(xiàn),節(jié)點(diǎn)出現(xiàn)了重合的現(xiàn)象,我們可以給節(jié)點(diǎn)添加一個(gè)碰撞力,讓它們分開。

添加碰撞力

let simulation = d3.forceSimulation(nodes)
    .force("charge", d3.forceManyBody().strength(-200)) // 電荷力 相互之間的作用力
    .force("center", d3.forceCenter(width / 2, height / 2)) // 用指定的x坐標(biāo)和y坐標(biāo)創(chuàng)建一個(gè)居中力
    .force("link", d3.forceLink(links).distance(100)) //
    .on("tick", ticked);

添加拖拽效果

d3.drag后面再詳細(xì)介紹,本章就不深入了。

let nodeGroups = svg.append("g")
    ...
    .call(
        d3.drag().on("start", started).on("drag", dragged).on("end", ended)
    );
// 拖拽
function started(event) {
    if (!event.active) simulation.alphaTarget(0.3).restart();
    event.subject.fx = event.subject.x;
    event.subject.fy = event.subject.y;
}

function dragged(event) {
    event.subject.fx = event.x;
    event.subject.fy = event.y;
}

function ended(event) {
    if (!event.active) simulation.alphaTarget(0);
    event.subject.fx = null;
    event.subject.fy = null;
}

整個(gè)拖拽的過程中:

  • 連接力:拖拽任意節(jié)點(diǎn),其余節(jié)點(diǎn)都會(huì)同向運(yùn)動(dòng)
  • 碰撞力:在拖拽的過程中,各節(jié)點(diǎn)之間不會(huì)重合
  • 向心力:拖拽不能拖到任意位置,由于向心力的存在,最后還是會(huì)向中心靠攏

以上就是D3.js實(shí)現(xiàn)力向?qū)D的繪制教程詳解的詳細(xì)內(nèi)容,更多關(guān)于D3.js力向?qū)D的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論