Skip to content Skip to sidebar Skip to footer

Html5 Canvas Hittest Arbitrary Shape

I'm trying to develop program which can render images and text in canvas. I tried to handle click on image in canvas, but it work for rectable images. My question: Did you know so

Solution 1:

Solution using pure JavaScript + canvas

For cases where the hit target is mixed with the background you can do two things:

  1. Create a separate canvas which is stacked on top of the main canvas, draw the target object on that and do the testing of that canvas.
  2. Create an off-screen canvas which contains the target object isolated and test on that

In this example I will use an off-screen canvas.

What we do is to basically replicate the image by creating an off-screen canvas the size of the image and draw in the image when loaded. This will protect the background and keep it transparent no matter what is on the main canvas:

Modified fiddle here

/// create an off-screen canvas to hold imagevar ocanvas = document.createElement('canvas');
var octx = ocanvas.getContext('2d');

logoImg.onload=function(){
    
    /// set off-screen canvas to same size as image
    ocanvas.width = this.width;
    ocanvas.height = this.height;
    octx.drawImage(this, 0, 0);

    ... rest of code

Then using your existing code but with an adjustment for mouse position we can use the hitted variable you use to first check if we are inside the target object.

$(canvas).on('mousemove', function(e) {
    
    /// correct mouse position so it becomes relative to canvasvar r = canvas.getBoundingClientRect(),
        x = e.clientX - r.left,
        y = e.clientY - r.top;
    
     var hitted = x >= position.x && x <= position.x + logoImg.width &&
                  y >= position.y && y <= position.y + logoImg.height;

Now that we know we are inside the rectangle we can extract a pixel from the off-screen canvas by compensating for the object position:

if (hitted === true) {
        /// extract a single pixel at the adjusted positionvar pixel = octx.getImageData(x - position.x, y - position.y, 1, 1).data;

        /// set hitted again based on alpha value is 0 or not
        hitted = pixel[3] > 0;
    }

    ...

As you can see in the modified fiddle we only change the class you use to red when we are on an actual pixel in the target no matter what the background of it is (when drawn separately).

Finally a couple of words on CORS: In this case, as you use DropBox, you can request CORS usage of the image simply by activating the crossOrigin property on the image object before you set the source:

logoImg.crossOrigin = '';   /// this is the same as setting anonymouslogoImg.src="http://dl.dropbox.com/..."; 

As DropBox (and image sharing sites such as ImgUr.com) support CORS usage they will allow the request and we can therefor extract pixels from the image.

If the servers didn't allow it however we wouldn't be able to do this. To be sure CORS is ok you should host the image in the same domain as the page when you release it.

Solution 2:

I recommend using EaselJS which has a hitTest method similar to how it works in Actionscript:

myDisplayObject.hitTest(localX, localY);

Here you can find some demos that show the technique: http://shallaazm.com/createjs/easeljs/tutorials/HitTest/

Post a Comment for "Html5 Canvas Hittest Arbitrary Shape"