d3-force 使节点在位置更新时移动得更慢
d3-force Make nodes move slower on position update
我正在使用 d3 的强制布局,并希望在事件触发时移动节点。
我创建了一个显示所需功能的 a minimal block here。
如您所见,单击按钮时,节点会快速移动到新位置。我想放慢速度。我玩过 documentation 中指定的(我认为是)相关属性的组合(例如 alpha
、alphaDecay
、velocityDecay
),但无济于事。
回顾一下:如何让节点在位置更新时移动得更慢?
谢谢!
您可能想要使用高速衰减。值为 0.9 会将刻度减慢到其速度的 0.1,"after the application of any forces during a tick, each node’s velocity is multiplied by 1 - [velocity]decay.(docs)"。这肯定会减慢运动速度。在大多数情况下,0.9 的值可能有点矫枉过正。
然而,与此相结合,我们需要确保 alpha 衰减较低:如果 alpha 衰减过高,模拟将在节点到达其端点之前冷却。我在下面的这个例子中使用了 0.0005,
最后,为了解决重新定心时模拟的跳跃性,我降低了alpha以减少抖动的出现,当然你移动alpha越低,alphaDecay必须越低以支持a同期模拟冷静期
以下使用:
- alhpaDecay:0.005,
- 速度衰减:0.6,
- 重启阿尔法:0.1
const width = 500
const height = 500
const svg = d3.select("svg")
const trtCenter = width / 5
const cntrlCenter = width / 1.5
let sampleData = d3.range(24).map((d,i) => ({r: 40 - i * 0.5}))
// define force
let force = d3.forceSimulation()
.force('charge', d3.forceManyBody().strength(1))
force.force('x', d3.forceX().strength(.3).x( width / 2))
force.force('y', d3.forceY().strength(.3).y(height / 3.5))
.force('collision', d3.forceCollide(d => 12))
.nodes(sampleData)
.on('tick', changeNetwork)
let dots = svg.selectAll('.dot')
.data(sampleData)
.enter()
.append('g')
.attr('class', 'dot')
.attr('group', (d,i) => i % 2 == 0 ? 'trt' : 'ctrl')
.append('circle')
.attr('r', 10)
.attr('fill', (d,i) => i % 2 == 0 ? 'pink' : 'olive')
.attr('stroke', 'black')
.attr('stroke-width', .4)
function nodeTreatmentPos(d) {
return d.index % 2 == 0 ? trtCenter : cntrlCenter;
}
function changeNetwork() {
d3.selectAll('g.dot')
.attr('transform', d=> `translate(${d.x}, ${d.y})`)
}
//
function moveNodes() {
force.force('center', null)
.force('collision', d3.forceCollide(d => 12))
.alphaDecay(.0005)
.velocityDecay(0.6)
force.force('x', d3.forceX().strength(1).x(nodeTreatmentPos))
force.force('y', d3.forceY().strength(1).y(height / 3.5))
force.alpha(.1).restart();
}
// force for center
function moveCenter() {
force//.force('center', null)
.force('collision', d3.forceCollide(d => 12))
.alphaDecay(.0005)
.velocityDecay(0.6)
force.force('x', d3.forceX().strength(1).x( width / 2))
force.force('y', d3.forceY().strength(1).y(height / 3.5))
force.alpha(.1).restart();
}
// resolve locations of node on cliks
let toCenter = true;
d3.select('#clickMe')
.on('click', function() {
toCenter === true ? moveNodes() : moveCenter()
toCenter = !toCenter
})
<script src='https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js'></script>
<button id="clickMe" type="button">Move Nodes</button>
<svg id="svg" width="1200" height="500"></svg>
我正在使用 d3 的强制布局,并希望在事件触发时移动节点。
我创建了一个显示所需功能的 a minimal block here。
如您所见,单击按钮时,节点会快速移动到新位置。我想放慢速度。我玩过 documentation 中指定的(我认为是)相关属性的组合(例如 alpha
、alphaDecay
、velocityDecay
),但无济于事。
回顾一下:如何让节点在位置更新时移动得更慢?
谢谢!
您可能想要使用高速衰减。值为 0.9 会将刻度减慢到其速度的 0.1,"after the application of any forces during a tick, each node’s velocity is multiplied by 1 - [velocity]decay.(docs)"。这肯定会减慢运动速度。在大多数情况下,0.9 的值可能有点矫枉过正。
然而,与此相结合,我们需要确保 alpha 衰减较低:如果 alpha 衰减过高,模拟将在节点到达其端点之前冷却。我在下面的这个例子中使用了 0.0005,
最后,为了解决重新定心时模拟的跳跃性,我降低了alpha以减少抖动的出现,当然你移动alpha越低,alphaDecay必须越低以支持a同期模拟冷静期
以下使用:
- alhpaDecay:0.005,
- 速度衰减:0.6,
- 重启阿尔法:0.1
const width = 500
const height = 500
const svg = d3.select("svg")
const trtCenter = width / 5
const cntrlCenter = width / 1.5
let sampleData = d3.range(24).map((d,i) => ({r: 40 - i * 0.5}))
// define force
let force = d3.forceSimulation()
.force('charge', d3.forceManyBody().strength(1))
force.force('x', d3.forceX().strength(.3).x( width / 2))
force.force('y', d3.forceY().strength(.3).y(height / 3.5))
.force('collision', d3.forceCollide(d => 12))
.nodes(sampleData)
.on('tick', changeNetwork)
let dots = svg.selectAll('.dot')
.data(sampleData)
.enter()
.append('g')
.attr('class', 'dot')
.attr('group', (d,i) => i % 2 == 0 ? 'trt' : 'ctrl')
.append('circle')
.attr('r', 10)
.attr('fill', (d,i) => i % 2 == 0 ? 'pink' : 'olive')
.attr('stroke', 'black')
.attr('stroke-width', .4)
function nodeTreatmentPos(d) {
return d.index % 2 == 0 ? trtCenter : cntrlCenter;
}
function changeNetwork() {
d3.selectAll('g.dot')
.attr('transform', d=> `translate(${d.x}, ${d.y})`)
}
//
function moveNodes() {
force.force('center', null)
.force('collision', d3.forceCollide(d => 12))
.alphaDecay(.0005)
.velocityDecay(0.6)
force.force('x', d3.forceX().strength(1).x(nodeTreatmentPos))
force.force('y', d3.forceY().strength(1).y(height / 3.5))
force.alpha(.1).restart();
}
// force for center
function moveCenter() {
force//.force('center', null)
.force('collision', d3.forceCollide(d => 12))
.alphaDecay(.0005)
.velocityDecay(0.6)
force.force('x', d3.forceX().strength(1).x( width / 2))
force.force('y', d3.forceY().strength(1).y(height / 3.5))
force.alpha(.1).restart();
}
// resolve locations of node on cliks
let toCenter = true;
d3.select('#clickMe')
.on('click', function() {
toCenter === true ? moveNodes() : moveCenter()
toCenter = !toCenter
})
<script src='https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js'></script>
<button id="clickMe" type="button">Move Nodes</button>
<svg id="svg" width="1200" height="500"></svg>