0

JSFiddle: http://jsfiddle.net/6WMXh/170/

I have a canvas with a snowy effect overlaying the web page, and I want to delegate clicks through the canvas to the element beneath which was meant to be clicked.

This script works for other objects, but fails on the image map (with AREA tags) in certain browsers.

Works: IE10, Chrome;
Fails: FF, Safari.

    // delegate click through canvas to page
    canvas.addEventListener('click', function(event) {
        event = event || window.event;
        canvas.style.zIndex = "0";
        target = document.elementFromPoint(event.clientX, event.clientY);
        if (target.click) {
            target.click();
        } else {
            target.onclick();
        }
        canvas.style.zIndex = "1000000";
    }, false);

Please see the JSFiddle for a demonstration of the problem. When you click on the map which is not overlapped by the Canvas the AREA element's onclick function fires. However, when you click on the part of the Map covered by the Canvas it does not fire the onclick function in the specified browsers. Try the JSFiddle with IE10/Chrome: there isn't a problem, try it with FireFox/Safari to see the problem.

What's going wrong?

3

3 Answers 3

2

You could have canvas to stop listening to mouse events using CSS pointer-events:none;

// CSS

#canvasObj {
    pointer-events: none;
}
1
  • Seriously, that's all I had to do?? :'(
    – Ozzy
    Commented Dec 19, 2013 at 11:10
0

You are only triggering the actual click or onclick handlers, not any that are added by a listener, to do so you need to trigger the event using dispatchEvent.

Further, the event properties that handle cursor position do not always match properly from one browser to another, so you might wish to use a library such as jQuery that normalises their values.

6
  • That sounds good, but not sure if I'm doing it right? var clickEvent = new MouseEvent('click', { 'view': window, 'bubbles': true, 'cancelable': true }); and then using target.dispatchEvent(clickEvent); but there is no difference to the problem.
    – Ozzy
    Commented Dec 18, 2013 at 21:32
  • Oh there is a difference, the MouseEvent declaration is causing an error in IE: Object doesn't support this action.
    – Ozzy
    Commented Dec 18, 2013 at 21:37
  • @Ozzy you are having the event transferred, so you dont need to create a new event object, you already have the one you got from the click on the canvas, just transfer it into the target using dispatchEvent
    – Entoarox
    Commented Dec 18, 2013 at 22:06
  • Could you post an example please? Because everything I tried gives me another error. Using the 'event' object that is passed causes an InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable. Also, dispatchEvent doesn't work in IE.
    – Ozzy
    Commented Dec 18, 2013 at 22:26
  • @Ozzy you need to copy the event object before passing it on, As to IE, I dont understand how you can have a canvas but not dispatchEvent, unless you are polyfilling the canvas??
    – Entoarox
    Commented Dec 19, 2013 at 2:02
0

Okay, so I got it working in a really horrible, manual way.

First I realised that the target element is finding the <img> rather than the map > <area> element. So I have to do this manually. I look at the <img usemap=""> attribute, locate the <map> by id, then I have to calculate from the clicked position using event.clientX and event.clientY which child <area> of the map was intended to be clicked.

It's even more horrible in my case because I have used an <area shape="poly"...> element so to get around it I simply defaulted to the polygon-shaped area if the others weren't correct.

    // delegate click through canvas to page
    var bindEvent = function(element, type, handler)
    {
           if(element.addEventListener) {
              element.addEventListener(type, handler, false);
           } else {
              element.attachEvent('on'+type, handler);
           }
    };
    bindEvent(canvas, 'click', function(event) {
        event = event || window.event;
        canvas.style.zIndex = "0";
        target = document.elementFromPoint(event.clientX, event.clientY);
        if (target.useMap) {
            var evt = document.createEvent("MouseEvents");
            evt.initMouseEvent("click", true, true, window, 1, 0, 0, 0, 0,
                false, false, false, false, 0, null);
            var mapid = target.useMap.replace("#","");
            var map = document.getElementById(mapid);
            var x = event.clientX - target.offsetParent.offsetLeft;
            var y = event.clientY - target.offsetParent.offsetTop;
            console.log("("+x+","+y+")");
            var areas = map.getElementsByTagName("area");
            var clickarea = areas[0];
            for (var i=0; i<areas.length; i++) {
                var area = areas[i];
                var coords = area.coords.split(",");
                if (area.shape == "rect"
                    && x > parseInt(coords[0])
                    && x < parseInt(coords[2])
                    && y > parseInt(coords[1])
                    && y < parseInt(coords[3])) {
                    console.log(x+">"+coords[0]
                        +" && "+x+"<"+coords[2]);
                    console.log(y+">"+coords[1]
                        +" && "+y+"<"+coords[3]);
                    clickarea = area;
                    break;
                }
            }
            clickarea.dispatchEvent(evt);
        } else if (target.click) {
            target.click();
        } else {
            target.onclick();
        }
        canvas.style.zIndex = "1000000";
    }, false);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.