力學模擬
力學模擬實作 速度 Verlet 數值積分器,用於模擬作用在粒子(節點)上的物理力。模擬假設每個步驟的常數單位時間步長 Δt = 1,以及所有粒子的常數單位質量 m = 1。因此,作用在粒子上的力 F 等於時間間隔 Δt 上的常數加速度 a,並且可以透過簡單地加到粒子的速度(然後加到粒子的位置)來模擬。
forceSimulation(nodes)
來源 · 使用指定的 nodes 陣列和 力陣列建立新的模擬。如果未指定 nodes,則預設為空陣列。
警告
此函式不純,它會改變傳入的 nodes。請參閱 simulation.nodes。
const simulation = d3.forceSimulation(nodes);
模擬器 自動啟動;使用 simulation.on 在模擬執行時監聽刻度事件。如果您希望手動執行模擬,請呼叫 simulation.stop,然後視需要呼叫 simulation.tick。
simulation.restart()
來源 · 重新啟動模擬的內部計時器並傳回模擬。結合 simulation.alphaTarget 或 simulation.alpha,此方法可用於在互動期間「重新加熱」模擬,例如拖曳節點時,或在使用 simulation.stop 暫時暫停模擬後繼續模擬。
模擬.stop()
原始碼 · 停止模擬的內部計時器(如果正在執行),並傳回模擬。如果計時器已停止,此方法不會執行任何動作。此方法對於手動執行模擬很有用;請參閱 模擬.tick。
模擬.tick(反覆運算次數)
原始碼 · 手動以指定的反覆運算次數執行模擬,並傳回模擬。如果未指定反覆運算次數,則預設為 1(單一步驟)。
對於每個反覆運算,它會將目前的 alpha 增加 (alphaTarget - alpha) × alphaDecay;然後呼叫每個已註冊的 力,傳遞新的 alpha;然後將每個 節點 的速度減少 速度 × velocityDecay;最後將每個節點的位置增加 速度。
此方法不會傳送 事件;事件僅在模擬於 建立 時或呼叫 模擬.restart 時自動啟動時由內部計時器傳送。模擬啟動時的反覆運算自然數為 ⌈log(alphaMin) / log(1 - alphaDecay)⌉;預設為 300。
此方法可與 模擬.stop 搭配使用,以計算 靜態力導向配置。對於大型圖表,應在 網頁工作執行緒中 計算靜態配置,以避免使用者介面凍結。
模擬.nodes(節點)
原始碼 · 如果指定了 節點,則將模擬的節點設定為指定的物件陣列,必要時初始化其位置和速度,然後 重新初始化 任何已綁定的 力;傳回模擬。如果未指定 節點,則傳回模擬的節點陣列,如 建構函式 所指定。
警告
此函式是不純的;它會變異傳入的 節點,以指定索引 節點.index、位置 節點.x 和 節點.y,以及速度 節點.vx 和 節點.vy。位置和速度會進一步在模擬執行時由 模擬.tick 更新。
每個 節點 都必須是一個物件。模擬會指定下列屬性
index
- 節點在 節點 中的 0 為基礎的索引x
- 節點目前的 x 位置y
- 節點目前的 y 位置vx
- 節點目前的 x 速度vy
- 節點目前的 y 速度
位置 ⟨x,y⟩ 和速度 ⟨vx,vy⟩ 可能會隨後由 力 和模擬修改。如果 vx 或 vy 是 NaN,則速度會初始化為 ⟨0,0⟩。如果 x 或 y 是 NaN,則位置會在 葉序排列 中初始化,如此選擇是為了確保確定性的均勻分佈。
若要將節點固定在給定的位置,您可以指定兩個額外的屬性
fx
- 節點固定的 x 位置fy
- 節點固定的 y 位置
在每次 tick 的結尾,在套用任何力之後,具有已定義 節點.fx 的節點會將 節點.x 重設為此值,並將 節點.vx 設定為零;同樣地,具有已定義 節點.fy 的節點會將 節點.y 重設為此值,並將 節點.vy 設定為零。若要取消先前固定的節點固定,請將 節點.fx 和 節點.fy 設定為 null,或刪除這些屬性。
如果指定的 節點 陣列被修改,例如當節點被新增到模擬或從模擬中移除時,必須再次使用新的(或已變更的)陣列呼叫此方法,以通知模擬和已綁定的力有關變更;模擬不會對指定的陣列進行防禦性複製。
模擬.alpha(alpha)
原始碼 · alpha 大致類似於 模擬退火 中的溫度。它會隨著模擬「冷卻」而隨著時間遞減。當 alpha 達到 alphaMin 時,模擬會停止;請參閱 模擬.restart。
如果指定了 alpha,則將目前的 alpha 設定為 [0,1] 範圍內的指定數字,並傳回此模擬。如果未指定 alpha,則傳回目前的 alpha 值,預設為 1。
simulation.alphaMin(min)
來源 · 如果指定了 min,則將目前的 alpha 設定為 [0,1] 範圍內的指定數字,並傳回此模擬。如果未指定 min,則傳回目前的 alpha 值,預設為 0.001。當目前的 alpha 小於目前的 alpha 時,模擬的內部計時器會停止。預設的 alpha 衰減率 約為 0.0228,相當於 300 次反覆運算。
simulation.alphaDecay(decay)
來源 · 如果指定了 decay,則將 alpha 衰減率設定為 [0,1] 範圍內的指定數字,並傳回此模擬。如果未指定 decay,則傳回目前的 alpha 衰減率,預設為 0.0228… = 1 - pow(0.001, 1 / 300),其中 0.001 為預設的 alpha。
alpha 衰減率決定了目前的 alpha 如何快速地內插到目標 alpha;由於預設的目標 alpha 為零,因此預設下這會控制模擬冷卻的速度。較高的衰減率會讓模擬更快地穩定,但有卡在局部最小值的風險;較低的值會讓模擬執行時間較長,但通常會收斂到更好的配置。若要讓模擬永遠在目前的 alpha 執行,則將 decay 率設定為零;或者,設定一個大於 alpha 的 目標 alpha。
simulation.alphaTarget(target)
來源 · 如果指定了 target,則將目前的目標 alpha 設定為 [0,1] 範圍內的指定數字,並傳回此模擬。如果未指定 target,則傳回目前的目標 alpha 值,預設為 0。
模擬.velocityDecay(衰減)
原始碼 · 如果指定了 衰減,則將速度衰減因子設定為 [0,1] 範圍內指定的數字,並傳回此模擬。如果未指定 衰減,則傳回目前的衰減因子,預設為 0.4。衰減因子類似於空氣阻力;在 tick 期間應用任何力後,每個節點的速度都會乘以 1 - 衰減。與降低 alpha 衰減率 一樣,較小的速度衰減可能會收斂到更好的解,但有數值不穩定和震盪的風險。
模擬.force(名稱, 力)
原始碼 · 如果指定了 力,則指定 名稱 的 力 並傳回此模擬。如果未指定 力,則傳回具有指定名稱的力,或者如果沒有此力,則傳回未定義。(預設情況下,新的模擬沒有力。)例如,若要建立一個新的模擬來配置圖形,您可以說
const simulation = d3.forceSimulation(nodes)
.force("charge", d3.forceManyBody())
.force("link", d3.forceLink(links))
.force("center", d3.forceCenter());
若要移除具有給定 名稱 的力,請將 null 傳遞為 力。例如,若要移除電荷力
simulation.force("charge", null);
模擬.find(x, y, 半徑)
原始碼 · 傳回最接近位置 ⟨x,y⟩ 的節點,並具有指定的搜尋 半徑。如果未指定 半徑,則預設為無限大。如果搜尋區域內沒有節點,則傳回未定義。
模擬.randomSource(來源)
原始碼)
如果指定了 來源,則設定用於產生亂數的函式;這應該是一個傳回介於 0(含)和 1(不含)之間數字的函式。如果未指定 來源,則傳回此模擬目前的亂數來源,預設為固定種子 線性同餘產生器。另請參閱 亂數.來源。
模擬.on(類型名稱, 監聽器)
原始碼 · 如果指定了 listener,則設定指定 typenames 的事件 listener,並傳回此模擬。如果已為相同類型和名稱註冊事件 listener,則在新增新的 listener 之前會移除現有的 listener。如果 listener 為 null,則移除指定 typenames 的目前事件 listener(如果有的話)。如果未指定 listener,則傳回與指定 typenames 相符的第一個目前已指派 listener(如果有的話)。當觸發指定事件時,每個 listener 都會呼叫,而 this
的內容會是模擬。
typenames 是包含一個或多個 typename 的字串,各 typename 以空白分隔。每個 typename 都是一個 type,後面可以選擇加上一個句點 (.
) 和一個 name,例如 tick.foo
和 tick.bar
;name 允許為同一個 type 註冊多個 listener。type 必須是下列其中一種
tick
- 在模擬內部計時器的每次滴答聲之後。end
- 當模擬的計時器在 alpha < alphaMin 時停止之後。
請注意,當手動呼叫 simulation.tick 時,不會觸發 tick 事件;事件只會由內部計時器觸發,並用於模擬的互動式呈現。若要影響模擬,請註冊 力,而不是在滴答事件 listener 內修改節點的位置或速度。
有關詳細資訊,請參閱 dispatch.on。
自訂力
力 是修改節點位置或速度的函式。它可以模擬物理力,例如電荷或重力,或者它可以解決幾何約束,例如讓節點保持在邊界框內或讓連結的節點保持固定的距離。例如,以下是一個將節點移向原點的力
function force(alpha) {
for (let i = 0, n = nodes.length, node, k = alpha * 0.1; i < n; ++i) {
node = nodes[i];
node.vx -= node.x * k;
node.vy -= node.y * k;
}
}
力通常會讀取節點目前的座標 ⟨x,y⟩,然後改變節點的速度 ⟨vx,vy⟩。力也可以「預先查看」節點預期的下一個座標 ⟨x + vx,y + vy⟩;這對於透過 反覆放鬆 來解決幾何約束是必要的。力也可以直接修改位置,這有時有助於避免為模擬增加能量,例如在視窗中重新置中模擬時。
force(alpha)
套用此力,選擇性地觀察指定的alpha。通常,此力會套用於先前傳遞至 force.initialize 的節點陣列,然而,有些力可能會套用於節點子集,或有不同的行為。例如,forceLink 會套用於每個連結的來源和目標。
force.initialize(nodes)
提供nodes 和random 來源的陣列給此力。當力透過 simulation.force 繫結到模擬時,以及當模擬的節點透過 simulation.nodes 變更時,會呼叫此方法。力可以在初始化期間執行必要的作業,例如評估每個節點的參數,以避免在每次套用力時重複執行作業。