Search code examples
svgeventsdetectionpointvector-graphics

How to detect if a point is inside complex, irregular vector shape (SVG)?


I'm more or less new to all this. I'm trying to create an app using SVG (as I'd rather have vector shapes that can scale without loss of quality). Using web technologies and would later migrate to react-native.

Is there any way for me to find out if a point (x,y which would also be determined by CSS's left and top properties) is inside a highly complex, irregular, vector shape?

I know my question is full of constraints, which makes it really hard to answer, even pointing to the right documentation would be helpful.

PS: I tried the method elementFromPoint() but it returns the bounding rectangle which the DOM is putting around my SVG. That completely defeats my purpose, I'd want to make sure the point is only detected within the SVG Paths and shape itself. Any help is appreciated, Thanks!


Solution

  • As long as you use inline SVGs, elementFromPoint() should work just fine:

    const shape = document.querySelector('#shape'),
          status = document.querySelector('#inout');
    
    document.body.addEventListener('mousemove', function(e) {
        const x = e.clientX,
              y = e.clientY;
        
        if(document.elementFromPoint(x, y) === shape) {
            status.className = status.textContent = 'inside';
        }
        else {
            status.className = status.textContent = 'outside';
        }
    });
    h2 { margin: 0; }
    
    .inside { color: lime; }
    .outside { color: red; }
    <h2>The cursor is: <span id="inout" class="outside">outside</span></h2>
    
    <svg xmlns="http://www.w3.org/2000/svg" width="250" height="200">
        <path id="shape" d="M150,120  q26,75 -80,50  c-80,-25 -53,-125 -26,-125  c53,-25 107,-25 107,50  q107,-50 53,50 z"
              stroke-width="4" fill="yellow" stroke="limegreen" />
    </svg>

    https://jsfiddle.net/n98m4Lrk/