如何使用pointer-events属性将仅鼠标点击事件传递到SVG?

10

我有一个覆盖在带有按钮的div上的SVG。我知道可以通过为SVG设置"pointer-events: none;"来将鼠标事件传递给下面的元素。然而,当我这样做时,SVG不再识别鼠标事件。

<body>
  <div id="website">
    <form action="input_button.htm">
      <p>
        <textarea cols="20" rows="4" name="text"></textarea>
        <input type="button" name="Text 1" value="show text" 
         onclick="this.form.text.value='Test'">
      </p>
    </form>
  </div>
  <div id="svgRect">
    <svg width="1845" height="140">
      <rect id="r0"></rect>
    </svg>
  </div>
</body>

我希望我的SVG能够识别鼠标何时悬停在它上面,但将点击事件传递给它下面的元素(divs / buttons / ...)。
因此,我的SVG应该只是hover-events的目标,而我的按钮应该是click-events的目标。
我尝试过其他方法,但都没有奏效。- 无法解决问题。
.on("mousedown", function(d,i){
   d3.select("#r0")
     .style("pointer-events", "none");
   d3.select("#website")
     .style("pointer-events", "auto");}
.on("mouseup", function(d,i){
   d3.select("#r0")
     .style("pointer-events", "auto");
   d3.select("#website")
     .style("pointer-events", "none");
}

这个想法是在我按下鼠标按钮时禁用指针事件,释放后再次启用它们。

有人知道这个问题的解决方案或变通方法吗? 谢谢!


1
对于这个SVG的目的我很好奇。在表单上叠加似乎与直觉相反。 - Paulie_D
我的项目旨在创建覆盖网站某些部分的SVG。这些SVG需要对某些悬停事件做出反应。如果不了解整个背景,我理解这似乎不太直观。 - ephtron
覆盖层就是覆盖层……你不能挑选其中的某些部分进行点击。 - Paulie_D
那么对于“覆盖层”,“悬停”和“点击”之间没有区别吗?我不想有特殊的部件,我希望SVG可以通过点击,同时仍然识别悬停。指针事件似乎在悬停和点击之间没有区别...你要么得到两者,要么什么都没有。 - ephtron
从根本上说,你有一些东西覆盖了表单。你要么让所有东西通过,要么什么都不让通过。除了笨拙的HTML重构,我认为你无法改变它。 - Paulie_D
1
可以使用elementFromPoint()实现。 - ephtron
4个回答

7
这里是一个更简单的解决方案: 在 SVG 中保留 pointer-events: none;,但是在多边形、路径或任何你的按钮上添加 pointer-events: fill。这样,空白处是透明的,但按钮可以被点击。 https://dev59.com/533aa4cB1Zd3GeqPhLz4#29319009

好的想法,但似乎没有起作用。 - Stavros

5
我找到了解决方案。可以使用elementFromPoint(x,y);函数遍历所有底层元素。我编写了一个辅助函数,该函数检查第一个选择的元素是否为SVG - 如果是,则将其显示设置为“none”,并选择下一个元素。
function get_element_under_svg(x,y){
    var resulting_element;
    var first_element = document.elementFromPoint(x,y);
    //check if first_element is a svg
    if (first_element.nodeName == "rect") {
      _display = first_element.style.display;    //save display of svg
      first_element.style.display = "none";      // make svg invisible
      resulting_element = document.elementFromPoint(x,y); 
      first_element.style.display = _display;    // reset display
    } else {
      resulting_element = first_element;
    }
    return resulting_element;
  }  
  return lower_element;
}

在一天结束时,我为我的SVG和div设置了“pointer-events:auto”。
#website{
  pointer-event: auto;
}
svg{
  pointer-event: auto;
}

我在我的SVG中添加了以下内容:

.on("click", function(d,i) {
  var element = get_element_under_rect( mouse.x, mouse.y );
  element.click(); // simulate click on the underlying element
}); 

通过这种方法,我的SVG仍然可以接收悬停或点击事件,同时能够将点击传递给底层元素。

此外,请参见https://developer.mozilla.org/en-US/docs/Web/API/document.elementFromPoint

感谢提供其他方法!


1
这里有一种方法,我给你一个例子。

body {
  margin: 0;
}

.wrapper {
  background-color: #e54d42;
  height: 100%;
  width: 100%;
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.link {
  cursor: pointer;
  color: #eee;
  font-family: Helvetica, Verdana;
  font-weight: 100;
  font-size: 40px;
}
.link:hover {
  color: #e59a95;
}

.mask {
  position: absolute;
  top: 0;
  width: 100%;
  right: 0;
}

.mask {
  pointer-events: none;
}

.svg-not-transparent {
  pointer-events: fill;
  cursor: pointer;
}
.svg-not-transparent:hover {
  fill: #333;
}
<div class="wrapper">
  <a class="link">En: I am reacheable even if there is a big SVG omer me <br>But not over the  SVG shape<br>Esp: Puedes darme click aún cuándo hay un SVG sobre mi.<br>Pero no sobre el poligono</a>
  <svg version="1.1" class="mask" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1980 1320" style="enable-background:new 0 0 1980 1320;" xml:space="preserve">
     <polygon class="svg-not-transparent" points="1277.7,0 567.8,1337.5 1980,1337.5 1980,0 "/>
  </svg>
</div>

: http://codepen.io/jesuscmd/pen/EyEyoP

这段文本是关于编程的,其中保留了HTML标签。它包含一个链接,指向codepen网站上的一个页面。

0
你可以在SVG上禁用指针事件,但是添加一个与表单和SVG大小相同的透明父元素div。然后你可以监听透明父元素上的hover事件:

var btn = document.getElementById("btn");
var container = document.getElementById("container");

container.addEventListener("mouseover", function() {
  log("SVG mouse over");
}, true);
container.addEventListener("mouseout", function() {
  log("SVG mouse out");
}, true);

btn.addEventListener("click", function() {
  log("BTN click");
}, false);

var out = document.getElementById("out");

function log(s) {
  out.innerHTML += s + "<br>";
}
#container {
  position: relative;
  width: 300px;
  height: 100px;
}
#svgOverlay {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  pointer-events: none;
}
#out {
  width: 200px;
  height: 300px;
  overflow: auto;
  border: 1px solid gray;
  position: absolute;
  top: 160px;
}
<body>
  <div id="container">
    <div id="website">
      <form action="input_button.htm">
        <textarea cols="20" rows="4" name="text"></textarea>
        <input type="button" name="Text 1" value="show text" onclick="this.form.text.value='Test'" id="btn"></input>
      </form>
    </div>
    <svg id="svgOverlay" width="300" height="100">
      <rect width="100%" stroke="black" height="100%" fill="gray" id="r0" opacity=".5"></rect>
    </svg>
  </div>
  <div id="out"></div>
</body>


我认为这不会允许单击额外的div和SVG下面的元素。 - Paulie_D
是的,它能够正常工作,因为点击会穿过透明的 div,而不透明的 svg 元素则禁用了指针事件 - 只需运行代码段即可看到,在 svg 下方仍然可以点击按钮。 - mfk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接