捕获两个重叠元素上的鼠标悬停事件 [英] Capturing mouseover events on two overlapping elements
本文介绍了捕获两个重叠元素上的鼠标悬停事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
所以我有一个带有rect
覆盖的d3图表,用于保存mouseover
事件上的十字准线元素。在覆盖下,我有其他RECT显示数据,这些数据也具有mouseover
事件处理程序,但是覆盖阻止了mouseover
事件形成下面的子RECT上的触发器。
let chartWindow = svg
.append("g");
/* this holds axis groups, and cadlestick group*/
let candleStickWindow = chartWindow.append("g")
//this event never fires
.on('mousemove', ()=>console.log('mouse move'));
let candlesCrosshairWindow = chartWindow
.append("rect")
.attr("class", "overlay")
.attr("height", innerHeight)
.attr("width", innerWidth)
.on("mouseover", function() {
crosshair.style("display", null);
})
.on("mouseout", function() {
crosshair.style("display", "none");
removeAllAxisAnnotations();
})
.on("mousemove", mousemove);
CrosshairWindow
具有CSS属性pointer-events: all
。如果我删除它,我会让我的事件在candleStickWindow
上激发,而不是在CrosshairWindow
上激发。如何将鼠标事件同时放到这两个元素上?
谢谢您的帮助!
更新 我将十字准线矩形元素更改为位于底部,它有点起作用了,烛台栏鼠标悬停事件起作用了,但它会阻止十字准线起作用。
推荐答案
脑海中出现的一种解决方案可能使用event bubbling,但是,只有当事件可以沿着相同的DOM子树泡沫上行时才有效。如果在DOM结构中,十字准线矩形和其他元素不共享您可以合理地附加到的公共祖先,则需要重新考虑您的DOM或求助于其他解决方案。对于此答案,我将介绍一种更普遍适用的替代方法。
您可以将全尺寸rect
放在SVG的最底部,并将其pointer-events
设置为all
。这样,您可以轻松地将mousemove
处理程序附加到它,以控制十字准线在整个视口中的移动。但是,正如您已经注意到的那样,如果上面有元素附加了该特定事件类型的侦听器,则此操作不起作用。因为在这种情况下,一旦事件到达其目标,就无法将其进一步传播到用于处理十字光标组件的底层矩形。不过,解决方法很简单,因为您可以克隆事件并将新事件直接分派到您的矩形。
克隆事件是通过使用MouseEvent()
构造函数从d3.event
引用传入事件详细信息来完成的:
new MouseEvent(d3.event.type, d3.event)
然后可以使用SVGRectElement
实现的EventTarget
接口的.dispatchEvent()
方法将新创建的事件对象分派到十字准线rect
元素:
.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>
这篇关于捕获两个重叠元素上的鼠标悬停事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文