如何通过带有指针事件的 SVG 仅传递点击?
How can I pass ONLY clicks through a SVG with pointer-events?
我有一个 SVG 覆盖 div 和一个按钮。我知道我可以通过为我的 SVG 设置 "pointer-events: none;" 来通过 SVG 传递鼠标事件。但是,当我这样做时,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/按钮/...)。
所以我的 SVG 应该只是悬停事件的目标,而我的按钮应该是点击事件的目标。
在其他一些方法中,我是这样尝试的:- 没有任何效果。
.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");
}
我的想法是在我按下鼠标按钮时禁用指针事件,并在我释放鼠标按钮时再次启用它们。
有谁知道这个问题的解决方案或变通方法吗?
谢谢!
您可以禁用 SVG 上的指针事件,但添加另一个大小相同的 div,它是 SVG 和表单的透明父级。然后您可以在透明父级上收听悬停事件:
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>
我找到了解决问题的办法。可以使用 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
感谢其他方法!
这是一个更简单的解决方案:
将 pointer-events: none;
保留在 svg 中,但将 pointer-events: fill
添加到多边形、路径或任何你的按钮,有了这个,空的 space 是透明的,但按钮可以点击
这里有个方法,我举个例子
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>
我有一个 SVG 覆盖 div 和一个按钮。我知道我可以通过为我的 SVG 设置 "pointer-events: none;" 来通过 SVG 传递鼠标事件。但是,当我这样做时,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/按钮/...)。 所以我的 SVG 应该只是悬停事件的目标,而我的按钮应该是点击事件的目标。
在其他一些方法中,我是这样尝试的:- 没有任何效果。
.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");
}
我的想法是在我按下鼠标按钮时禁用指针事件,并在我释放鼠标按钮时再次启用它们。
有谁知道这个问题的解决方案或变通方法吗? 谢谢!
您可以禁用 SVG 上的指针事件,但添加另一个大小相同的 div,它是 SVG 和表单的透明父级。然后您可以在透明父级上收听悬停事件:
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>
我找到了解决问题的办法。可以使用 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
感谢其他方法!
这是一个更简单的解决方案:
将 pointer-events: none;
保留在 svg 中,但将 pointer-events: fill
添加到多边形、路径或任何你的按钮,有了这个,空的 space 是透明的,但按钮可以点击
这里有个方法,我举个例子
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>