将元素移到前面而不会破坏事件

时间:2016-09-12 08:38:17

标签: javascript d3.js svg

我正在尝试修复一些我正在处理的事件代码。在这种特殊情况下,我需要能够在click上订阅svg:circle个活动。但是,还需要将圆圈移动到mousedown上的z-index顶部,以便可以将元素拖到其他元素的顶部。

这样做的方法是将元素从DOM中取出,然后使用我在http://bl.ocks.org/eesur/4e0a69d57d3bfc8a82c2中使用的辅助函数将其重新插入到正确的位置。这样做的问题在于事件链似乎已经破坏了将元素从dom中移除,从而阻止click事件触发。

我想知道是否有人能够提出更好的方法来确保click正确触发但仍允许在拖动生命周期中某处更改z-index?

这个小例子展示了z-index如何变化,但点击事件不会在控制台中触发。一旦它在顶部再次单击该元素,则会正确触发该点击。



d3.selectAll("circle")
  .on("mousedown", function() {
    d3.select(this).moveToFront();
  })
  .on("click", function() {
    var fill = d3.select(this).style("fill");
    console.log("You clicked on : " + fill);
  });

d3.selection.prototype.moveToFront = function() {
  return this.each(function() {
    this.parentNode.appendChild(this);
  });
};

.red {
  fill: red;
}
.blue {
  fill: blue;
}
.green {
  fill: green;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.13/d3.min.js"></script>
<svg width="600" height="600">
  <circle class="red" cx="50" cy="50" r="50" />
  <circle class="blue" cx="100" cy="100" r="50" />
  <circle class="green" cx="150" cy="150" r="50" />
</svg>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:1)

我设法提出了一个稍微古怪的想法,这看起来很有效,但如果DOM内有很多元素,我会对性能有点担心。

这个想法本质上是,而不是将选择(在mousedown上)移动到顶部,而不是移动鼠标元素后面的所有其他东西(相同类型,在这种情况下为svg:circle)堕落。

&#13;
&#13;
d3.selectAll("circle")
  .on("mousedown", function() { 
    var that = this;
    d3.select(this.parentNode)
      .selectAll("circle")
      .filter(function() { return this !== that; })
      .moveBehind(that);
  })
  .on("click", function() {
    var fill = d3.select(this).style("fill");
    console.log("You clicked on : " + fill);
  });

d3.selection.prototype.moveToFront = function() {
  return this.each(function() {
    this.parentNode.appendChild(this);
  });
};

d3.selection.prototype.moveBehind = function(element) { 
  return this.each(function() { 
     this.parentNode.insertBefore(this, element);   
  });
};
&#13;
.red {
  fill: red;
}
.blue {
  fill: blue;
}
.green {
  fill: green;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.13/d3.min.js"></script>
<svg width="600" height="600">
  <circle class="red" cx="50" cy="50" r="50" />
  <circle class="blue" cx="100" cy="100" r="50" />
  <circle class="green" cx="150" cy="150" r="50" />
</svg>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

我想知道问题是否与d3有关,所以我在纯JS中编写了等效文件,并且在Chrome上的结果与d3完全相同。我能够通过将click替换为mouseup并将其与mousedown元素进行比较来使其工作,就像在我的评论中一样。您在评论中表示,由于其他项目限制,此解决方案在您的情况下是不可能的。我认为无论如何我都会发布我的解决方案,因为有人提到FF和IE的行为不同。

const circles = Array.from(document.getElementsByTagName('circle'));
let mousedown;
for (let circle of circles) {
  circle.addEventListener('mousedown', (e) => {
    mousedown = e.target;
    e.target.parentNode.appendChild(e.target);
  }, false);
  circle.addEventListener('mouseup', (e) => {
    if (mousedown === e.target) {
      console.log('You clicked on : ' + window.getComputedStyle(e.target).fill);
    }
    mousedown = null;
  }, false);
}
.red {
  fill: red;
}
.blue {
  fill: blue;
}
.green {
  fill: green;
}
<svg width="600" height="600">
  <circle class="red" cx="50" cy="50" r="50" />
  <circle class="blue" cx="100" cy="100" r="50" />
  <circle class="green" cx="150" cy="150" r="50" />
</svg>