Html5 canvas hittest arbitrary shape

前端 未结 2 739
北荒
北荒 2021-01-22 12:21

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 quest

相关标签:
2条回答
  • 2021-01-22 12:32

    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 image
    var 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 canvas
        var 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 position
            var 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 anonymous
    logoImg.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.

    0 讨论(0)
  • 2021-01-22 12:42

    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/

    0 讨论(0)
提交回复
热议问题