KasparKayne KasparKayne - 1 year ago 70
CSS Question

How can I pass ONLY clicks through a SVG with pointer-events?

I have a SVG overlaying a div with a button. I know that i can pass mouse-events through the SVG by setting "pointer-events: none;" for my SVG. However when I do this the SVG wont recognize mouse-events anymore.

<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"
<div id="svgRect">
<svg width="1845" height="140">
<rect id="r0"></rect>

I want my SVG to be able to recognize when the mouse is over it but pass clicks to elements (divs/ buttons / ...) underneath itself.
So my SVG should only be the target of hover-events and my button should be the target of click-events.

Among some other approaches I tried it like this: - Nothing worked.

.on("mousedown", function(d,i){
.style("pointer-events", "none");
.style("pointer-events", "auto");}
.on("mouseup", function(d,i){
.style("pointer-events", "auto");
.style("pointer-events", "none");

The idea was to disable pointer-events when I press the mouse-button and enable them again when I release it.

Does anyone know a solution or work-arround for this problem?

Answer Source

I found a solution to my problem. It is possible to traverse through all underlying elements with the elementFromPoint(x,y); function. I wrote a helper-function that checks if the first selected element is a SVG - if it is one its' display is set to "none" and the next element is selected.

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;

At the end of the day I set pointer-events: auto for my SVG and for my div:

  pointer-event: auto;
  pointer-event: auto;

And to my svg I added the following:

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

With this approach my SVG is still capable to receive hover- or click-events, while it is able to pass clicks to underlying elements. See also https://developer.mozilla.org/en-US/docs/Web/API/document.elementFromPoint

Thanks for the other approaches!