如何在不输入的情况下添加节点和链接做d3-force
how to add nodes and links do d3-force without enter
我正在尝试更新节点和 links 但不想使用 d3 的输入模式。原因是我希望 svelte 框架代替它执行此操作并处理所有渲染,我只想使用 d3-force 进行计算。
我的初始渲染工作得很好,但是添加 links 和节点有以下问题:
- 添加 links 使网络增长
- links 似乎对图形布局没有任何影响,即它们似乎没有添加到 force.simulation
- 第一次添加节点似乎可行,但是在添加 link 之后添加节点时,它们似乎不会对其他节点产生影响。
这是我添加节点和 links 的函数:
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()
}
我找到了 答案,但他们使用合并并将其绑定到 DOM 元素。我不明白如何在不涉及 DOM 的情况下执行此操作,只需更新节点数组和 javascript 中的 links 以使 d3-force 将其包含在模拟中。
Here 我在 svelte REPL 中有当前的模拟,你可以 fork 并编辑它。
幸运的是,从 DOM 中分离 d3-force 布局相当容易:力布局本身与 DOM 没有交互,它只是基于某些数据属性的物理计算。虽然添加和删除数据点 (nodes/links) 可能有点棘手,但无论 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()
}
这里有几个问题:
Array.push() 不是 return 数组。它就地修改一个数组,return在推送一个项目后调整数组的长度。这意味着您实际上并没有将节点添加到强制布局。这将导致问题,因为力布局需要对象而不是基元来表示节点。相反,只需推送 node/link,然后将 node/link 数组传递给 .nodes() 或 .links()
force.forceSimulation() 将创建一个新的力布局生成器,这不是您想要的。你想在现有节点上添加节点,所以我们可以使用 graph.nodes()
代替。
没有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
,没有它我看不出有什么不同,我会悄悄地假设这是框架的一个怪癖
更新链接的小替代方案:
您可以访问您命名为 'link' 的部队并为其分配新链接:
graph.force("link").links(data.links)
而不是:
graph.force("link", force.forceLink(data.links))
后者重新创建一个力,而第一个只是修改它。
我正在尝试更新节点和 links 但不想使用 d3 的输入模式。原因是我希望 svelte 框架代替它执行此操作并处理所有渲染,我只想使用 d3-force 进行计算。
我的初始渲染工作得很好,但是添加 links 和节点有以下问题:
- 添加 links 使网络增长
- links 似乎对图形布局没有任何影响,即它们似乎没有添加到 force.simulation
- 第一次添加节点似乎可行,但是在添加 link 之后添加节点时,它们似乎不会对其他节点产生影响。
这是我添加节点和 links 的函数:
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()
}
我找到了
Here 我在 svelte REPL 中有当前的模拟,你可以 fork 并编辑它。
幸运的是,从 DOM 中分离 d3-force 布局相当容易:力布局本身与 DOM 没有交互,它只是基于某些数据属性的物理计算。虽然添加和删除数据点 (nodes/links) 可能有点棘手,但无论 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()
}
这里有几个问题:
Array.push() 不是 return 数组。它就地修改一个数组,return在推送一个项目后调整数组的长度。这意味着您实际上并没有将节点添加到强制布局。这将导致问题,因为力布局需要对象而不是基元来表示节点。相反,只需推送 node/link,然后将 node/link 数组传递给 .nodes() 或 .links()
force.forceSimulation() 将创建一个新的力布局生成器,这不是您想要的。你想在现有节点上添加节点,所以我们可以使用
graph.nodes()
代替。没有
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
,没有它我看不出有什么不同,我会悄悄地假设这是框架的一个怪癖
更新链接的小替代方案:
您可以访问您命名为 'link' 的部队并为其分配新链接:
graph.force("link").links(data.links)
而不是:
graph.force("link", force.forceLink(data.links))
后者重新创建一个力,而第一个只是修改它。