d3js v4:我如何应用力到节点的点击,使它看起来像一个渐变

d3js v4: How can I apply force to nodes onclick and make it look like a tween?

本文关键字:渐变 看起来 一个 节点 v4 何应用 d3js 应用      更新时间:2023-09-26

请看一下这个相互依存的演示;我会要求您单击svg对象,以查看实例化的模拟刻度,因此会发生转换。我使用了一个简单的函数:

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

但是,您可以从演示中看到"tween"是不存在的。要查看我建议的渐变示例,请参阅此处!

我哪里做错了?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新手。

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

所以yes - ticks不知道节点在哪里(通过d.x和d.y),你不应该指定他们的位置到模拟。

要看到你的节点从初始位置动画到最终解决方案,一个选择是调整你的模拟设置到一些效率较低的东西。

。我添加了一个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));

这是一个更新的代码依赖

可能有一个更干净的解决方案,使用d3.transition()。