簡體   English   中英

在 React 應用程序中更新 d3 的力導向圖,同時保留舊節點位置

[英]Update d3's force-directed graph in a React app while preserving old nodes positions

我正在使用 d3 的forceSimulation來計算給定力的每個節點的 (x,y) 坐標(從沒有節點或鏈接開始):

const simulation = d3.forceSimulation()
      .force('charge', d3.forceManyBody().strength(-1000))
      .force('link', d3.forceLink().id(d => d?.id).distance(200))
      .force('collide', d3.forceCollide().radius(150))
      .stop()
      .tick(300)

然后聽simulation的 'tick' 事件來更新圖形(使用 react-flow-renderer setNodessetSetEdges見文檔):

simulation.on('tick', () => {
    setEdges([...simulation.force('link').links()].map(setEdge));
    setNodes([...simulation.nodes()].map(setNode));
})

React 部分應該在將實際nodesedges應用於simulation simulation

useEffect(() => {
    simulation.nodes(nodes);
    simulation.force('link').links(edges);
    simulation.alpha(0.1).restart();

    return () => simulation.stop();
}, [nodes, edges])

現在, nodesedges可能會更新,因為有可能擴展節點的關系。 問題是 - 每次我們擴展節點關系時,我們都會得到一個新的節點和邊數組,每個包含舊值和新值:

虛擬示例:

old nodes: [{ id: 1 }]

new nodes: [{ id: 1 }, { id: 2}, { id: 3}]

“模擬”以新值重新啟動並從頭開始重新計算圖形,因此新圖形與舊圖形完全不同。 是否有一個選項可以使圖形保留舊節點的(x,y)坐標並簡單地將新節點“添加”到現有圖形中?

如果有人遇到這種問題:

在更新節點的數組之前記錄以前的節點:

const prev = usePrev(new Map(nodes.map((node) => [node.id, node])));

然后,在將新節點傳遞給模擬之前,制作一個新副本,合並以前存在的元素,如下所示:

useEffect(() => {
    nodes = nodes.map((node) => Object.assign(node, prev?.get(node.id)));

    simulation.nodes(nodes);
    (...) // rest of the code

這樣,當模擬從新節點開始時,其中一些可能已經設置了 (x,y) 坐標。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM