Collision/overlap detection of circles in a d3 transition

霸气de小男生 提交于 2019-12-05 02:07:36

问题


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.


回答1:


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




回答2:


The easiest way is to just check how "close" the transitioning circle is to the other points.

var pop = d3.select("body").append("div")
    .style("position","absolute")
    .style("top",0)
    .style("left",0)
    .style("display", "none")
    .style("background", "yellow")
    .style("border", "1px solid black");

// Returns an attrTween for translating along the specified path element.
function translateAlong(path) {
  var l = path.getTotalLength();
  var epsilon = 5;
  return function(d, i, a) {
    return function(t) {
      var p = path.getPointAtLength(t * l);
      points.forEach(function(d,i){
        if ((Math.abs(d[0] - p.x) < epsilon) && 
            (Math.abs(d[1] - p.y) < epsilon)){
          pop.style("left",d[0]+"px")
            .style("top",d[1]+20+"px")
            .style("display","block")
            .html(d);
          return false;
        }
      })
      return "translate(" + p.x + "," + p.y + ")";
    };
  };
}

The faster the circle moves the greater your epsilon will need to be.

Example here.



来源:https://stackoverflow.com/questions/28647623/collision-overlap-detection-of-circles-in-a-d3-transition

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!