Переместить элемент вперед, не нарушая события



Я пытаюсь исправить некоторый код события, над которым работаю. В этом конкретном случае мне нужно иметь возможность подписаться на событие 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>
574   2  

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

    Ничего не найдено.