Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Collision/overlap detection of circles in a d3 transition

I'm using d3 to animate a route (path) on a map. When the route reaches a point along the route I'd like to popup some information.

Most of my code is based on the following example. http://bl.ocks.org/mbostock/1705868. I'm really just trying to determine if there is a way to detect when the transitioning circle collides or overlaps any of the stationary circles in this example.

like image 997
shadc Avatar asked Dec 05 '25 14:12

shadc


1 Answers

You can detect collision in your tween function. Define a collide function to be called from inside the tween function as follows:

function collide(node){
    var trans = d3.transform(d3.select(node).attr("transform")).translate,
      x1 = trans[0],
      x2 = trans[0] + (+d3.select(node).attr("r")),
      y1 = trans[1],
      y2 = trans[1] + (+d3.select(node).attr("r"));

  var colliding = false;
  points.each(function(d,i){
    var ntrans = d3.transform(d3.select(this).attr("transform")).translate,
      nx1 = ntrans[0],
      nx2 = ntrans[0] + (+d3.select(this).attr("r")),
      ny1 = ntrans[1],
      ny2 = ntrans[1] + (+d3.select(this).attr("r"));


      if(!(x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1))
        colliding=true;
  })

  return colliding;
}

Where points are the stationary points, and node is the transitioning element. What collide does is check whether node overlaps with any of the points (as shown in collision detection example here).

Because we need the node to be passed to the tween function, we replace attrTween used in Mike's example, with tween:

circle.transition()
      .duration(10000)
      .tween("attr", translateAlong(path.node()))
      .each("end", transition);

Finally, the tween function calling our collide:

function translateAlong(path) {
  var l = path.getTotalLength();
  return function(d, i, a) {
    return function(t) {
      var p = path.getPointAtLength(t * l);

      d3.select(this).attr("transform","translate(" + p.x + "," + p.y + ")");

      if(collide(this))
        d3.select(this).style("fill", "red")
       else
        d3.select(this).style("fill", "steelblue")
    };
  };
}

See the full demo here

like image 195
ahmohamed Avatar answered Dec 07 '25 03:12

ahmohamed



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!