d3js v4:如何对节点onclick施加强制并使其看起来像补间?

时间:2016-09-23 21:37:42

标签: javascript d3.js svg d3v4 d3.js-v4

请查看this codepen demo;我要求您单击svg对象以查看实例化的模拟标记,因此会发生转换。我使用一个简单的函数来执行此操作:

function transitionTo() {
  simulation
    .on("tick", ticked);
}

但是,您可以从演示中看到“补间”不存在。要查看我建议的补间示例,请参阅here

我哪里出错了? ticked()函数知道我的节点在哪里吗?我是否需要为模拟而不是节点指定我的位置?

密钥代码(包含在上面的演示链接中):

var data = {
    nodes:d3.range(0, range).map(function(d){ return {label: "l"+d ,r: config.radius,color: d3.scaleOrdinal(d3.schemeCategory10)}})      
}
svg
  .attr("width", config.canvas.width)
  .attr("height", config.canvas.height)
  .attr("id", "canvas")
  .style("border", "1px solid black")
  .attr("onclick", "transitionTo()");
}

var simulation = d3.forceSimulation()
  .force("collide",d3.forceCollide( function(d){return d.r + 1 }).iterations(15) )
  .force("charge", d3.forceManyBody().strength(1))
  .force("center", d3.forceCenter(config.canvas.width / 2, config.canvas.height / 2))
  .force("y", d3.forceY(0))
  .force("x", d3.forceX(0));

var node = svg.append("g")
  .attr("class", "nodes")
  .selectAll("circle")
  .data(data.nodes)
  .enter().append("circle")
  .attr("r", function(d){  return d.r })
  .attr('cx', function(d, i) { return i % 10 * (config.canvas.width - config.margin.x*2) / 10 + config.radius + config.margin.x; })
  .attr('cy', function(d, i) {return (Math.floor(i/10) * (config.canvas.height - config.margin.y*2) / 10) + config.margin.y + config.radius});

var ticked = function() {
  node
    .attr("cx", function(d) { return d.x; })
    .attr("cy", function(d) { return d.y; });
}  

simulation
  .nodes(data.nodes);

function transitionTo() {
  simulation
    .on("tick", ticked);
}

我更喜欢d3 v4的答案,但任何想法都会非常受欢迎!感谢这个d3 noob。

1 个答案:

答案 0 :(得分:0)

我认为您没有看到任何补间的原因是解决方案正在快速收敛 - 即“勾选”函数的第一次迭代计算x和y非常接近最终解决方案。你可以看到模拟结束时点点闪烁,因为它们找到了最终的位置。

是的 - 勾选确实知道节点的位置(通过d.x和d.y),你不必指定它们在模拟中的位置。

要查看节点从初始位置到最终解决方案的动画,一个选项是将模拟设置调整为效率较低的设置。

e.g。我添加了一个velocityDecay并将forceCollide迭代更改为1.

  var simulation = d3.forceSimulation()
    .velocityDecay(0.05)
    .force("collide",d3.forceCollide( function(d){return d.r + 1 }).iterations(1) )
    .force("charge", d3.forceManyBody().strength(1))
    .force("center", d3.forceCenter(config.canvas.width / 2, config.canvas.height / 2))
    .force("y", d3.forceY(0))
    .force("x", d3.forceX(0));

这是updated codepen

使用d3.transition()可能有一个更清洁的解决方案。