d3中的过渡碰撞检测

时间:2018-01-12 02:07:26

标签: javascript d3.js

根据此示例http://bl.ocks.org/ahmohamed/c1804b03b71d8a17bd37

我想在发生碰撞时更改圆圈和静态点的颜色,所以我将同一个类添加到它们中

var points =  svg.selectAll(".point")
    .data(points)
  .enter().append("circle").attr('class', 'dot')
    .attr("r", 20)
    .attr("transform", function(d) { return "translate(" + d + ")"; });

var circle = svg.append("circle").attr('class', 'dot')
    .attr("r", 10)
    .attr("transform", "translate(" + points[0] + ")");

并在碰撞功能中,我更改为此

d3.selectAll('.dot').each(function(d,i){

而不是

points.each(function(d,i){

但在此之后圆圈不会将颜色恢复正常,它会粘在红色上。

这是我的JSFiddle: https://jsfiddle.net/psh2cphm/

请帮忙!感谢

2 个答案:

答案 0 :(得分:2)

更简单的选择就是保持对碰撞圆的引用:

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

然后:

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

以下是具有该更改的代码:

<!DOCTYPE html>
<meta charset="utf-8">

<body>
  <style>
    path {
      fill: none;
      stroke: #000;
      stroke-width: 3px;
    }
    
    circle {
      fill: steelblue;
      stroke: #fff;
      stroke-width: 3px;
    }

  </style>
  <script src="https://d3js.org/d3.v3.min.js"></script>
  <script>
    var points = [
      [480, 200],
      [580, 400],
      [680, 100],
      [780, 300],
      [180, 300],
      [280, 100],
      [380, 400]
    ];

    var collidingPoint;

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

    var path = svg.append("path")
      .data([points])
      .attr("d", d3.svg.line()
        .tension(0) // Catmull–Rom
        .interpolate("cardinal-closed"));

    var points = svg.selectAll(".point")
      .data(points)
      .enter().append("circle").attr('class', 'dot')
      .attr("r", 20)
      .attr("transform", function(d) {
        return "translate(" + d + ")";
      });

    var circle = svg.append("circle").attr('class', 'dot')
      .attr("r", 10)
      .attr("transform", "translate(" + points[0] + ")");

    transition();

    function transition() {
      circle.transition()
        .duration(30000)
        .tween("attr", translateAlong(path.node()))
        .each("end", transition);
    }

    // Returns an attrTween for translating along the specified path element.
    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")
            d3.select(collidingPoint).style("fill", "red")
          } else {
            d3.select(this).style("fill", "steelblue")
            d3.select(collidingPoint).style("fill", "steelblue")
          }
        };
      };
    }

    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"));
    });

    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)) {
          collidingPoint = this;
          colliding = true;
        }
      })

      return colliding;
    }

  </script>

答案 1 :(得分:-1)

对我而言,如果您错误上课,则添加.dot 要圈选在线路径上运行的内容,请更改该类,以便不在d3.sellectAll(".dot")

上包含动态圈

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<style>

path {
  fill: none;
  stroke: #000;
  stroke-width: 3px;
}

circle {
  fill: steelblue;
  stroke: #fff;
  stroke-width: 3px;
}

</style>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>

var points = [
  [480, 200],
  [580, 400],
  [680, 100],
  [780, 300],
  [180, 300],
  [280, 100],
  [380, 400]
];

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

var path = svg.append("path")
    .data([points])
    .attr("d", d3.svg.line()
    .tension(0) // Catmull–Rom
    .interpolate("cardinal-closed"));

var points =  svg.selectAll(".point")
    .data(points)
  .enter().append("circle").attr('class', 'dot')
    .attr("r", 20)
    .attr("transform", function(d) { return "translate(" + d + ")"; });

var circle = svg.append("circle").attr('class', 'dota')
    .attr("r", 10)
    .attr("transform", "translate(" + points[0] + ")");

transition();

function transition() {
  circle.transition()
      .duration(30000)
      .tween("attr", translateAlong(path.node()))
      .each("end", transition);
}

// Returns an attrTween for translating along the specified path element.
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")
    };
  };
}

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"));
  		console.log(nx1,nx2, ny1, ny2)
});

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;
  d3.selectAll('.dot').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"));
    	

    	var yy = ny1-y1 
			var xx = nx1-x1
		Math.abs(yy)
		Math.abs(xx)
    
  if(Math.abs(xx)<30&&Math.abs(yy)<30 ){
    colliding=true;
  }
      
  })
  
  return colliding;
}
</script>