Переместить элемент вперед, не нарушая события
Я пытаюсь исправить некоторый код события, над которым работаю. В этом конкретном случае мне нужно иметь возможность подписаться на событие click на svg:circle. Однако существует также необходимость переместить окружность в верхнюю часть z-индекса на mousedown таким образом, чтобы элемент можно было перетащить поверх других элементов.
Способ, которым это делается, состоит в том, чтобы извлечь элемент из DOM и повторно вставить его в нужное место, используя вспомогательную функцию, которую я использую из http://bl.ocks.org/eesur/4e0a69d57d3bfc8a82c2 . Проблема с этим заключается в том, что цепочка событий, похоже, разорвалась, вынимая элемент из dom, предотвращая запуск события click.
Мне интересно, может ли кто-нибудь придумать лучший способ сделать это, который обеспечит click Правильное срабатывание, но все еще позволяет изменять z-индекс где-то в течение жизненного цикла перетаскивания?
Этот небольшой пример показывает, как изменяется z-индекс, но события щелчка не срабатывают приставка. Щелчок по элементу еще раз, как только он находится сверху, делает это правильно.
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> 2 ответов:
Мне было интересно, была ли проблема с
d3, поэтому я написал эквивалент в чистом JS и получил точно такой же результат на Chrome, как и вы сd3. Я смог заставить его работать, заменивclickнаmouseupи сравнив его с элементомmousedown, как в моем комментарии. Вы заявили в своем комментарии, что в вашем случае это решение было невозможно из-за других ограничений проекта. Я подумал, что все равно выложу свое решение, поскольку упоминалось, что поведение отличается в FF и Т.Е..
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>
Мне удалось придумать немного дурацкую идею, которая, кажется, работает, хотя я немного беспокоюсь о производительности, если в DOM есть много элементов.
Идея состоит в том, чтобы вместо перемещения выделения (наmousedown) наверх переместить все остальное (того же типа, в данном случаеsvg:circle) за элемент, на который была наведена мышь.
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); }); };.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>
Comments