Question

I have multiple SVG elements that are in separate groups. They overlap each other. Example:

<svg id="board" width="100%" height="80%">
   <g id="terrain" class="layer">
     <path d="M-32,-32L32,-32 32,32 -32,32Z" transform="translate(0, 0)" class="mote terrain hill"></path>
   </g>
   <g id="guy" class="layer">
     <path d="M-21...Z" transform="translate(192, 448)" class="mote guy"></path>
   </g>
</svg>

When an x, y position that matches both is clicked, I want to know all that both were clicked. If I bind each to the 'click' event, only the event handlers for one on top gets called. Which is reasonable, although not what I want here.

I'm thinking of creating a topmost layer and having that catch all clicks, then figure out which elements in the other layers should be notified. That's a lot of tracking that I'd like to avoid, if possible. Are there simpler approaches to this?

Was it helpful?

Solution

From The SVG spec

"By default, pointer-events must not be dispatched on the clipped (non-visible) regions of a shape. For example, a circle with a radius of 10 which is clipped to a circle with a radius of 5 will not receive 'click' events outside the smaller radius. Later versions of SVG may define new properties to enable fine-grained control over the interactions between hit testing and clipping."

However, there is a way of getting a list of svg shapes that intersect at a particular point. The "getIntersectionList" function returns a list of items.

I've created one of those jsfiddle things jsfiddle.net/uKVVg/1/ Click on the intersection of the circles to get a list of ID's. Manually send events to that list.

Javascript follows:

function s$(a) {
    return document.getElementById(a);
}

var list 

function hoverElement(evt) {
    var root = s$("canvas");

    var disp = s$("pointer");
    disp.setAttribute("x",evt.clientX);
    disp.setAttribute("y",evt.clientY);

    rpos = root.createSVGRect();
    rpos.x = evt.clientX;
    rpos.y = evt.clientY;
    rpos.width = rpos.height = 1;
    list = root.getIntersectionList(rpos, null);
    s = "clicked: "
    $.each(list,function(item,val){
        if (val.id != "pointer") {
            s = s + (val.id) + " ";
        }
    })
    alert(s);
}

var root = s$("canvas");
root.addEventListener("click", hoverElement, false);

There's some javascript that could probably be tidied up, but hopefully it answers your question.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top