【问题标题】:how to add nodes and links do d3-force without enter如何在不输入的情况下添加节点和链接做 d3-force
【发布时间】:2020-03-02 20:00:58
【问题描述】:

我正在尝试更新节点和链接,但不想使用 d3 的输入模式。原因是我希望 svelte 框架来执行此操作并处理所有渲染,我只想使用 d3-force 进行计算。

我让初始渲染工作正常,但添加链接和节点有以下问题:

  1. 添加链接使网络增长
  2. 链接似乎对图形布局没有任何影响,即它们似乎没有被添加到 force.simulation
  3. 首先添加节点似乎可以工作,但是在添加链接后添加节点时,它们似乎不会对其他节点施加力。

这是我添加节点和链接的函数:

function addNode(){
    force.forceSimulation(data.nodes.push({"id": "116", "group": 5, "index":data.nodes.length, "x":0, "y":0, "vx":0, "vy":0}))
    data=data
    graph.alpha(1.0).update()
    graph.restart()

}

function addLink(){
    let n=getRandomInt(0, data.nodes.length-1)
    let tn=getRandomInt(0, n)
    let sn=getRandomInt(n, data.nodes.length-1)

    graph.force("link", force.forceLink(data.links.push({'source':data.nodes[sn], 'target':data.nodes[tn],'index':data.links.length, 'value':getRandomInt(1, 7)})))

    data=data

    graph.alpha(1.0).update()
    graph.restart()
}

我找到了this 的答案,但他们使用合并并将其绑定到 DOM 元素。我不明白如何在不涉及 DOM 的情况下做到这一点,只需更新 javascript 中的节点和链接数组以使 d3-force 将其包含在模拟中。

Here我在一个苗条的 REPL 中有当前的模拟,你可以 fork 和编辑它。

【问题讨论】:

    标签: d3.js force-layout svelte


    【解决方案1】:

    幸运的是,将 d3-force 布局与 DOM 分离相当容易:force 布局本身与 DOM 没有交互,它只是基于某些数据属性的物理计算。添加和删​​除数据点(节点/链接)可能有点棘手,但无论 D3 渲染 DOM、其他东西还是您根本不渲染力都是一样的。

    这里是你添加链接和节点的地方:

    function addNode(){
        force.forceSimulation(data.nodes.push({"id": "116", "group": 5, "index":data.nodes.length, "x":0, "y":0, "vx":0, "vy":0}))
        data=data
        graph.alpha(1.0).update()
        graph.restart()
    }
    
    function addLink(){
        let n=getRandomInt(0, data.nodes.length-1)
        let tn=getRandomInt(0, n)
        let sn=getRandomInt(n, data.nodes.length-1)
    
        graph.force("link", force.forceLink(data.links.push({'source':data.nodes[sn], 'target':data.nodes[tn],'index':data.links.length, 'value':getRandomInt(1, 7)})))
    
        data=data
    
        graph.alpha(1.0).update()
        graph.restart()
    }
    

    这里有几个问题:

    1. Array.push() 不返回数组。它修改一个数组,在推送一个项目后返回数组的长度。这意味着您实际上并未将节点添加到强制布局。这将导致问题,因为强制布局需要对象而不是基元来表示节点。相反,只需推送节点/链接,然后将节点/链接数组传递给 .nodes() 或 .links()

    2. force.forceSimulation() 将创建一个新的力布局生成器,这不是您想要的。您想将节点添加到现有节点,因此我们可以改用graph.nodes()

    3. 没有force.update(),这会导致错误,这也是模拟冷却完成后无法重新启动模拟的原因。我们可以去掉这部分。

    让我们看看这两个函数如何纠正这个问题:

    function addNode(){
        data.nodes.push({"id": "116", "group": 5, "index":data.nodes.length, "x":0, "y":0, "vx":0, "vy":0})
        graph.nodes(data.nodes)
        data=data
        graph.alpha(1.0).restart()
    
    }
    
    function addLink(){
        let n=getRandomInt(0, data.nodes.length-1)
        let tn=getRandomInt(0, n)
        let sn=getRandomInt(n, data.nodes.length-1)
    
      data.links.push({'source':data.nodes[sn], 'target':data.nodes[tn],'index':data.links.length, 'value':getRandomInt(1, 7)})
        graph.force("link", force.forceLink(data.links))
        data=data
        graph.alpha(1.0).restart()
    
    }
    

    我不知道你为什么有data=data,没有它我看不出有什么区别,我会悄悄地假设这是框架的一个怪癖


    更新链接的一个小替代方案:

    您可以访问您命名为“链接”的部队并为其分配新链接:

    graph.force("link").links(data.links)
    

    而不是:

    graph.force("link", force.forceLink(data.links))
    

    后者重新创造了一种力量,而前者只是对其进行了修改。

    【讨论】:

    • 完美,非常感谢您对解决方案的理解!
    猜你喜欢
    • 2013-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-17
    • 2018-03-24
    • 2014-11-20
    相关资源
    最近更新 更多