代码之家  ›  专栏  ›  技术社区  ›  Jared Wilber

d3强制使节点在位置更新时移动较慢

  •  1
  • Jared Wilber  · 技术社区  · 6 年前

    我创造了一个 a minimal block here

    如您所见,单击按钮时,节点会快速移动到新位置。我想放慢速度。我使用了 documentation (例如。 alpha , alphaDecay , velocityDecay ),但无济于事。

    重述:

    谢谢!

    1 回复  |  直到 6 年前
        1
  •  8
  •   Andrew Reid    6 年前

    你可能想用高速衰变。值为0.9将使滴答声的速度减慢到0.1,“滴答声期间施加任何力后,每个节点的速度将乘以1-[速度]衰减( docs

    然而,与此相结合,我们需要确保alpha衰减很低:如果alpha衰减太高,模拟将在节点到达其端点之前冷却。我在下面的例子中使用了0.0005,

    最后,为了解决重新居中时模拟的跳跃性,我降低了alpha以减少抖动的出现,当然,移动alpha越低,alphaDecay越低必须支持相同持续时间的模拟冷却期

    • 阿尔帕德凯:0.005,
    • 速度Cay:0.6,
    • 重新启动alpha: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>