Javascript 单击几下后,动画会冻结,为什么?

Javascript 单击几下后,动画会冻结,为什么?,javascript,d3.js,Javascript,D3.js,我有以下代码,我从中获取并修改 这是我的行动 我目前正在开发一个需要这些气泡的用户交互,正好有5个气泡被吸引到屏幕中央。问题是,我知道用户会点击每个气泡多少次。我注意到的一点是,在某个时刻,泡沫不断增长,但它们之间的碰撞将停止工作 在这里,您可以看到修改以下内容的代码: var width = 500, height = 500, padding = 1.5, // separation between same-color circles clusterPadding

我有以下代码,我从中获取并修改

这是我的行动

我目前正在开发一个需要这些气泡的用户交互,正好有5个气泡被吸引到屏幕中央。问题是,我知道用户会点击每个气泡多少次。我注意到的一点是,在某个时刻,泡沫不断增长,但它们之间的碰撞将停止工作

在这里,您可以看到修改以下内容的代码:

var width = 500,
    height = 500,
    padding = 1.5, // separation between same-color circles
    clusterPadding = 4, // separation between different-color circles
    maxRadius = 40; 

var n = 5, // total number of circles
    m = 1; // number of distinct clusters  

var color = d3.scale.category10()
    .domain(d3.range(m));

// The largest node for each cluster.
var clusters = new Array(m);

var nodes = d3.range(n).map(function() {
var i = Math.floor(Math.random() * m),
    //r = Math.sqrt((i + 1) / m * -Math.log(Math.random())) * maxRadius,
    r = maxRadius,
    d = {cluster: i, radius: r};
    if (!clusters[i] || (r > clusters[i].radius)) clusters[i] = d;
      return d;
    });

// Use the pack layout to initialize node positions.
d3.layout.pack()
  .sort(null)
  .size([width, height])
  .children(function(d) { return d.values; })
  .value(function(d) { return d.radius * d.radius; })
  .nodes({values: d3.nest()
  .key(function(d) { return d.cluster; })
  .entries(nodes)});

var force = d3.layout.force()
  .nodes(nodes)
  .size([width, height])
  .gravity(.02)
  .charge(0)
  .on("tick", tick)
  .start();

var svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height);

var node = svg.selectAll("circle")
  .data(nodes)
  .enter().append("circle")
  .style("fill", function(d) { return color(d.cluster); })
  .on("click", function(d) {
    d.radius *= 1.1;
    d3.select(this).attr("r", d.radius);
  })
  .call(force.drag);

node.transition()
  .duration(750)
  .delay(function(d, i) { return i * 5; })
  .attrTween("r", function(d) {
    var i = d3.interpolate(0, d.radius);
      return function(t) { return d.radius = i(t); };
  });

function tick(e) {
  node
    .each(cluster(10 * e.alpha * e.alpha))
    .each(collide(.5))
    .attr("cx", function(d) { return d.x; })
    .attr("cy", function(d) { return d.y; });
}

// Move d to be adjacent to the cluster node.
function cluster(alpha) {
  return function(d) {
  var cluster = clusters[d.cluster];
  if (cluster === d) return;
    var x = d.x - cluster.x,
      y = d.y - cluster.y,
      l = Math.sqrt(x * x + y * y),
      r = d.radius + cluster.radius;
    if (l != r) {
      l = (l - r) / l * alpha;
      d.x -= x *= l;
      d.y -= y *= l;
      cluster.x += x;
      cluster.y += y;
    }
  };
}

// Resolves collisions between d and all other circles.
function collide(alpha) {
  var quadtree = d3.geom.quadtree(nodes);
  return function(d) {
  var r = d.radius + maxRadius + Math.max(padding, clusterPadding),
      nx1 = d.x - r,
      nx2 = d.x + r,
      ny1 = d.y - r,
      ny2 = d.y + r;
      quadtree.visit(function(quad, x1, y1, x2, y2) {
      if (quad.point && (quad.point !== d)) {
        var x = d.x - quad.point.x,
          y = d.y - quad.point.y,
          l = Math.sqrt(x * x + y * y),
          r = d.radius + quad.point.radius + (d.cluster ===    quad.point.cluster ? padding : clusterPadding);
        if (l < r) {
          l = (l - r) / l * alpha;
          d.x -= x *= l;
          d.y -= y *= l;
          quad.point.x += x;
          quad.point.y += y;
        }
      }
      return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
    });
  };
}
var宽度=500,
高度=500,
padding=1.5,//相同颜色圆之间的间隔
clusterPadding=4,//不同颜色圆之间的间隔
最大半径=40;
var n=5,//圆的总数
m=1;//不同簇的数目
var color=d3.scale.category10()
.域(d3.范围(m));
//每个群集的最大节点。
var集群=新阵列(m);
var节点=d3.range(n).map(函数(){
var i=数学地板(数学随机()*m),
//r=Math.sqrt((i+1)/m*-Math.log(Math.random())*maxRadius,
r=最大半径,
d={簇:i,半径:r};
如果(!clusters[i]|(r>clusters[i].radius))clusters[i]=d;
返回d;
});
//使用包布局初始化节点位置。
d3.layout.pack()
.sort(空)
.尺寸([宽度、高度])
.children(函数(d){返回d.values;})
.value(函数(d){返回d.radius*d.radius;})
.nodes({值:d3.nest())
.key(函数(d){返回d.cluster;})
.entries(nodes)});
var-force=d3.layout.force()
.节点(节点)
.尺寸([宽度、高度])
重力(.02)
.收费(0)
.on(“滴答”,滴答)
.start();
var svg=d3.选择(“正文”).追加(“svg”)
.attr(“宽度”,宽度)
.attr(“高度”,高度);
var node=svg.selectAll(“圆”)
.数据(节点)
.enter().append(“圆”)
.style(“fill”,函数(d){返回颜色(d.cluster);})
.打开(“单击”,功能(d){
d、 半径*=1.1;
d3.选择(此).attr(“r”,d.半径);
})
.呼叫(强制拖动);
node.transition()
.持续时间(750)
.delay(函数(d,i){返回i*5;})
.attrTween(“r”,函数(d){
var i=d3.插值(0,d.半径);
返回函数(t){returnd.radius=i(t);};
});
功能勾号(e){
节点
.每个(集群(10*e.alpha*e.alpha))
.每个(碰撞(.5))
.attr(“cx”,函数(d){return d.x;})
.attr(“cy”,函数(d){返回d.y;});
}
//将d移动到与群集节点相邻的位置。
功能簇(alpha){
返回函数(d){
var cluster=簇[d.cluster];
if(cluster==d)返回;
var x=d.x-cluster.x,
y=d.y-cluster.y,
l=数学sqrt(x*x+y*y),
r=d.radius+cluster.radius;
如果(l!=r){
l=(l-r)/l*α;
d、 x-=x*=l;
d、 y-=y*=l;
簇x+=x;
簇y+=y;
}
};
}
//解决d和所有其他圆之间的碰撞。
函数碰撞(alpha){
var四叉树=d3.geom.quadtree(节点);
返回函数(d){
var r=d.radius+maxRadius+Math.max(填充,簇填充),
nx1=d.x-r,
nx2=d.x+r,
ny1=d.y-r,
ny2=d.y+r;
四叉树访问(函数(四叉树,x1,y1,x2,y2){
if(quad.point&&(quad.point!==d)){
var x=d.x-四点x,
y=d.y-四点y,
l=数学sqrt(x*x+y*y),
r=d.radius+quad.point.radius+(d.cluster===quad.point.cluster?填充:clusterPadding);
if(lnx2 | x2ny2 | y2
发生您描述的行为是因为力模拟已结束。因此,最简单的解决方案是在每次单击时重新加热力:

.on("click", function(d) {
    d.radius *= 1.1;
    d3.select(this).attr("r", d.radius);
    force.resume();
})
这里,
force.resume()

将冷却参数alpha设置为0.1。此方法将内部alpha参数设置为0.1,然后重新启动计时器。通常,您不需要直接调用此方法;它由start自动调用。在拖动手势期间,它也会通过拖动自动调用

这是你最新的小提琴: