Одно решение, которое приходит на ум, может использовать всплывающее сообщение , которое, однако, работает, только если события могут всплыть вдоль одного и того же поддерева DOM. Если в вашей структуре DOM прямоугольник перекрестия и другие элементы не имеют общего предка, к которому вы могли бы разумно присоединить такого слушателя, вам нужно либо переосмыслить свой DOM, либо прибегнуть к какому-либо другому решению. Для этого ответа я выложу альтернативный подход, который более применим.
Вы можете разместить свой полноразмерный rect
в самом низу вашего SVG и установить для pointer-events
значение all
. ,Таким образом, вы можете легко прикрепить обработчик mousemove
к нему, чтобы контролировать движения перекрестия, охватывающие весь видовой экран. Однако, как вы уже заметили, это не работает, если есть элементы выше, к которым прикреплены прослушиватели для этого конкретного типа события. Потому что в этом случае, как только событие достигнет своей цели, нет способа распространить его дальше к нижележащему прямоугольнику для обработки компонента перекрестия. Обойти это легко, поскольку вы можете клонировать событие и отправить его прямо в прямоугольник.
Клонирование события выполняется с помощью конструктора MouseEvent()
в сведениях о событии из ссылки d3.event
:
new MouseEvent(d3.event.type, d3.event)
Затем вы можете отправить вновь созданный объект события в элемент перекрестия rect
, используя метод .dispatchEvent()
интерфейс EventTarget
, который реализован с помощью SVGRectElement
:
.dispatchEvent(new MouseEvent(d3.event.type, d3.event));
Из-за отсутствия полного примера в вашем вопросе я сам создал рабочую демонстрациюиллюстрирующий подход. Вы можете перетащить синий кружок, который является развернутой версией компонента перекрестия. Обратите внимание, как круг можно плавно перемещать, даже если он находится под оранжевыми прямоугольниками. Чтобы продемонстрировать обработчики событий, прикрепленные к этим маленьким прямоугольникам, они будут переходить в зеленый и обратно в оранжевый при вводе или оставлении их с помощью указателя мыши.
const width = 500;
const height = 500;
const radius = 10;
const orange = d3.hsl("orange");
const steelblue = d3.hsl("steelblue");
const limegreen = d3.hsl("limegreen");
const svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
const target = svg.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.attr("fill", "none")
.attr("pointer-events", "all")
.on("mousemove", () => {
circle.attr("cx", d3.event.clientX - radius);
circle.attr("cy", d3.event.clientY - radius);
});
const circle = svg.append("circle")
.attr("r", radius)
.attr("fill", steelblue)
.attr("pointer-events", "none");
const rect = svg.selectAll(null)
.data(d3.range(3).map(d => [Math.random() * width, Math.random() * height]))
.enter().append("rect")
.attr("x", d => d[0])
.attr("y", d => d[1])
.attr("width", 50)
.attr("height", 50)
.attr("fill", orange)
.attr("opacity", 0.5)
.on("mouseover", function() {
d3.select(this).transition().attr("fill", limegreen);
})
.on("mousemove", function() {
target.node().dispatchEvent(new MouseEvent(d3.event.type, d3.event));
})
.on("mouseout", function() {
d3.select(this).transition().attr("fill", orange);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>