Как я могу передавать ТОЛЬКО клики через SVG с указателями-событиями?

У меня есть SVG, перекрывающий div с кнопкой. Я знаю, что могу передавать события мыши через SVG, установив «события-указателя: нет»; для моего 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 мог распознавать, когда мышь находится над ним, но передавать щелчки элементам (div / buttons / ...) под собой. Таким образом, мой 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");
}

Идея заключалась в том, чтобы отключить события указателя, когда я нажимаю кнопку мыши, и снова включить их, когда я отпущу ее.

Кто-нибудь знает решение или обходной путь для этой проблемы? Спасибо!


person ephtron    schedule 02.02.2015    source источник
comment
Любопытно, какова цель этого SVG. Мне кажется, что наложение формы противоречит интуиции.   -  person Paulie_D    schedule 02.02.2015
comment
Цель моего проекта - создать SVG, которые перекрывают некоторые части веб-сайта. Эти SVG должны реагировать на некоторые события зависания. Я понимаю, что это не кажется интуитивным, без знания всей предыстории;)   -  person ephtron    schedule 02.02.2015
comment
Наложения - это наложения ... вы не можете выбрать, будут ли части из них переходить по клику.   -  person Paulie_D    schedule 02.02.2015
comment
То есть для оверлеев нет разницы между наведением и щелчком? Я не хочу иметь специальные части, я хочу, чтобы SVG проходил через клики, при этом распознавая наведение. События указателя, похоже, не различаются между наведением и щелчком ... вы либо получаете то и другое, либо ничего.   -  person ephtron    schedule 02.02.2015
comment
По сути, у вас есть что-то, что покрывает форму. Вы либо все пропускаете, либо ничего. Помимо неудобной реструктуризации HTML, я думаю, вы застряли на этом.   -  person Paulie_D    schedule 02.02.2015
comment
это возможно с elementFromPoint()   -  person ephtron    schedule 02.02.2015


Ответы (4)


Я нашел решение своей проблемы. С помощью функции 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;
}

В конце дня я установил pointer-events: auto для своего SVG и для своего div:

#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

Спасибо за другие подходы!

person ephtron    schedule 02.02.2015

Вот более простое решение: оставьте pointer-events: none; в svg, но добавьте pointer-events: fill к многоугольнику, пути или любой другой кнопке, при этом пустое пространство прозрачно, но кнопку разумно нажимать

https://stackoverflow.com/a/29319009/2594391

person Jesus CMD    schedule 20.07.2016

Вот способ, я привожу вам пример

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

person Jesus CMD    schedule 20.07.2016

Вы можете отключить события указателя в 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>

person mfk    schedule 02.02.2015
comment
Я не думаю, что это позволит щелкнуть элементы ниже дополнительного div и SVG. - person Paulie_D; 02.02.2015
comment
Да, это так, потому что щелчки проходят через прозрачный div, а непрозрачный svg имеет отключенные события указателя - просто запустите фрагмент, чтобы увидеть, что вы можете нажать кнопку под svg. - person mfk; 02.02.2015