捕获两个重叠元素上的鼠标悬停事件 [英] Capturing mouseover events on two overlapping elements

查看:33
本文介绍了捕获两个重叠元素上的鼠标悬停事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有一个带有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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆