D3js拖放对象并检测它被丢弃的位置。

时间:2017-10-08 16:32:14

标签: javascript d3.js svg

我正在使用d3js拖放svg。有两个问题,我认为它们彼此相关。

  1. 当圆圈掉落时,它必须检测到它被放入矩形中。我看过的一些例子使用了鼠标的x和y坐标,但我并不完全理解它。

  2. 另一个问题是圆圈出现在矩形后面。有没有办法在圆圈移动时将它带到前面而不改变创建圆和矩形的顺序,即(首先创建圆,然后创建矩形)。

  3. 
    
    var width = window.innerWidth,
      height = window.innerHeight;
    
    var drag = d3.behavior.drag()
      .on("dragstart", dragstarted)
      .on("drag", dragged)
      .on("dragend", dragended);
    
    //create circle and space evenly
    var svg = d3.select("body")
      .append("svg")
      .attr("width", width)
      .attr("height", height);
    
    var circle = d3.select("svg")
      .append("circle")
      .attr("cx", 50)
      .attr("cy", 30)
      .attr("r", 15)
      .attr("transform", "translate(0,0)")
      .style("stroke", "black")
      .call(drag);
    
    
    function dragstarted(d) {
      d3.event.sourceEvent.stopPropagation();
    }
    
    function dragged(d) {
      d3.select(this).attr("transform", "translate(" + [d3.event.x, d3.event.y] + ")");
    }
    
    function dragended(d) {
      d3.event.sourceEvent.stopPropagation();
    
      // here would be some way to detect if the circle is dropped inside the rect. 
      
    }
    
    var ellipse = svg.append("rect")
          .attr("x", 150)
          .attr("y", 50)
          .attr("width", 50)
          .attr("height", 140)
          .attr("fill", "green");
    
    <script src="https://d3js.org/d3.v3.min.js"></script>
    &#13;
    &#13;
    &#13;

    感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

更新后仍然包含边界客户端矩形,但迭代存在的任意数量的矩形。 New Fiddle here.

这是我解决问题的方法。我使用了一个很棒的“moveToBack”辅助函数seen here来将矩形移到后面而不改变它出现的顺序。

为了获得圆形和矩形的位置,我大量使用了vanilla js getBoundingClientRect()方法。您可以在this JS Fiddle中一起看到所有这些内容。

var width = window.innerWidth,
  height = window.innerHeight;

var drag = d3.behavior.drag()
  .on("dragstart", dragstarted)
  .on("drag", dragged)
  .on("dragend", dragended);

//create circle and space evenly
var svg = d3.select("body")
  .append("svg")
  .attr("width", width)
  .attr("height", height);

var circle = d3.select("svg")
  .append("circle")
  .attr("r", 15)
  .attr("transform", "translate(50,30)")
  .style("stroke", "black")
  .attr("id", "circle")
  .call(drag);


d3.selection.prototype.moveToBack = function() {  
  return this.each(function() { 
    var firstChild = this.parentNode.firstChild; 
    if (firstChild) { 
      this.parentNode.insertBefore(this, firstChild); 
    } 
  });
};

var rect = svg.append("rect")
      .attr("x", 150)
      .attr("y", 50)
      .attr("width", 50)
      .attr("height", 140)
      .attr("fill", "green")
      .attr("id", "rect")
      .moveToBack();

var rect2 = svg.append("rect")
      .attr("x", 350)
      .attr("y", 50)
      .attr("width", 50)
      .attr("height", 140)
      .attr("fill", "green")
      .attr("id", "rect")
      .moveToBack();

function dragstarted(d) {
  d3.event.sourceEvent.stopPropagation();
}

function dragged(d) {
  d3.select(this).attr("transform", "translate(" + d3.event.x + "," + d3.event.y + ")");
}

function dragended(d) {
  // Define boundary
  var rects = document.querySelectorAll("rect");
  for (var i = 0; i < rects.length; i++) {
    var rectDimensions = rects[i].getBoundingClientRect();
    var xmin = rectDimensions.x;
    var ymin = rectDimensions.y;
    var xmax = rectDimensions.x + rectDimensions.width;
    var ymax = rectDimensions.y + rectDimensions.height;
    // Get circle position
    var circlePos = document.getElementById("circle").getBoundingClientRect();
    var x1 = circlePos.x;
    var y1 = circlePos.y;
    var x2 = circlePos.x + circlePos.width;
    var y2 = circlePos.y + circlePos.height;
    if(x2 >= xmin && x1 <= xmax && y2 >= ymin && y1 <= ymax) {
      rects[i].setAttribute("fill", "red");
    } else {
      rects[i].setAttribute("fill", "green");
    }  
  }
  d3.event.sourceEvent.stopPropagation();
}