捕获两个重叠元素上的鼠标悬停事件

Bar*_*ard 5 svg mouseevent d3.js

所以我有一个带有rect覆盖层的 d3 图表,用于mouseover保存事件上的十字准线元素。在覆盖层下,我有其他显示数据的矩形,这些数据mouseover也具有事件处理程序,但是覆盖层正在阻止mouseover下面的子矩形上的触发器事件。

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);
Run Code Online (Sandbox Code Playgroud)

具有CrosshairWindowCSS 属性pointer-events: all。如果我删除它,我的事件会在 上触发,candleStickWindow但不会在CrosshairWindow. 如何将鼠标事件获取到这两个元素上?

谢谢你的帮助!

更新 我将十字线矩形元素更改为位于底部,它有点起作用,烛台鼠标悬停事件起作用,但它阻止了十字线工作。

在此输入图像描述

alt*_*lus 3

我想到的一种解决方案可能是使用事件冒泡,但是,只有事件可以沿着同一 DOM 子树冒泡时才有效。如果在您的 DOM 结构中,十字准线矩形和其他元素不共享可以合理附加此类侦听器的共同祖先,则您需要重新考虑您的 DOM 或诉诸其他解决方案。对于这个答案,我将提出一种更普遍适用的替代方法。

您可以将全尺寸放置rect在 SVG 的最底部并将其pointer-events设置为all. 这样您就可以轻松地将mousemove处理程序附加到其上,以控制十字准线在整个视口中的移动。然而,正如您自己所注意到的,如果上面的元素附加了针对特定事件类型的侦听器,则此方法不起作用。因为在这种情况下,一旦事件到达其目标,就无法将其进一步传播到底层矩形来处理十字准线组件。不过,解决方法很简单,因为您可以克隆事件并将新事件直接分派到您的矩形。

克隆事件是通过使用MouseEvent()构造函数从引用中传入事件详细信息来完成的d3.event

new MouseEvent(d3.event.type, d3.event)
Run Code Online (Sandbox Code Playgroud)

rect然后,您可以使用实现的接口.dispatchEvent()方法将新创建的事件对象分派到十字准线元素:EventTargetSVGRectElement

.dispatchEvent(new MouseEvent(d3.event.type, d3.event));
Run Code Online (Sandbox Code Playgroud)

由于您的问题中缺乏完整的示例,我自己设置了一个工作演示来说明该方法。您可以围绕蓝色圆圈进行拖动,这是十字准线组件的精简版本。请注意,即使在橙色矩形下方,圆也可以无缝移动。为了演示附加到这些小矩形的事件处理程序,当使用鼠标指针进入或离开它们时,它们将转换为绿色并返回橙色。

new MouseEvent(d3.event.type, d3.event)
Run Code Online (Sandbox Code Playgroud)
.dispatchEvent(new MouseEvent(d3.event.type, d3.event));
Run Code Online (Sandbox Code Playgroud)