javascriptcanvasglobalcompositeoperation

Masking multiple shapes using globalCompositeOperation in canvas


I am attempting to draw multiple rectangles and then mask those using globalCompositeOperation 'source-in' which works great, but the issue is that when i fill my rectangles they disappear... If I only have one fill() call they all draw properly but only respect the last fill style applied.

code in question -

ctx.drawImage(self.glass.mask, 256, 375);
ctx.globalCompositeOperation = 'source-in';

ctx.rect(256, 635, 256, 75);
ctx.fillStyle = "#c65127";

ctx.rect(256, 605, 256, 25);
ctx.fillStyle = "#f5f4f0";

ctx.rect(256, 565, 256, 35);
ctx.fillStyle = "#c65127";

ctx.fill();

The code above works properly. But if I do this, and remove the mask -

ctx.beginPath();
ctx.rect(0, 256, 256, 75);
ctx.fillStyle = "#c65127";
ctx.fill();

ctx.beginPath();
ctx.rect(0, 226, 256, 25);
ctx.fillStyle = "#f5f4f0";
ctx.fill();

ctx.beginPath();
ctx.rect(0, 186, 256, 35);
ctx.fillStyle = "#222";
ctx.fill();

I have each rectangle and they respect their fill styles. Problem is when I enable the mask they are no longer visible.

Is there a limitation to the number of elements you can have under globalCompositeOperation 'source-in' or am I just missing something simple?

here are some fiddles -

http://jsfiddle.net/ENtXs/ - working as expected but not respecting the fill styles.

http://jsfiddle.net/ENtXs/1/ - Removing mask to show all elements

http://jsfiddle.net/ENtXs/2/ - Adding beginPath() and fill() elements respect fill styles. ( no masking)

http://jsfiddle.net/ENtXs/3/ - Adding the mask back ( nothing shows up anymore )

http://jsfiddle.net/ENtXs/4/ - Only having one rectangle with the same code as #3 works properly.


Solution

  • SOLVED

    I believe the issue is with globalCompositeOperation 'source-in'. What I wound up doing was creating a buffer canvas which I draw my shapes on, then taking that image data and drawing it into my primary canvas and apply the GCO to that.

    here's a working fiddle - http://jsfiddle.net/ENtXs/5/

    code in question:

    // Canvas and Buffers
    var canvas = document.getElementById('canvas');
    var buffer = document.getElementById('buffer');
    var ctx = canvas.getContext('2d');
    var buffer_ctx = buffer.getContext('2d');
    
    // sizing
    canvas.height = window.innerHeight;
    canvas.width = window.innerWidth;
    
    buffer.height = window.innerHeight;
    buffer.width = window.innerWidth;
    
    // mask image
    var mask = new Image();
    mask.onload = function () {
        drawBuffer();
    }
    
    mask.src = 'http://drewdahlman.com/experiments/masking/highball_mask.png';
    
    function drawBuffer() {
        buffer_ctx.beginPath();
        buffer_ctx.rect(0, 256, 256, 75);
        buffer_ctx.fillStyle = "#c65127";
        buffer_ctx.fill();
    
        buffer_ctx.beginPath();
        buffer_ctx.rect(0, 226, 256, 25);
        buffer_ctx.fillStyle = "#f5f4f0";
        buffer_ctx.fill();
    
        buffer_ctx.beginPath();
        buffer_ctx.rect(0, 186, 256, 35);
        buffer_ctx.fillStyle = "#222";
        buffer_ctx.fill();
    
        var image = buffer.toDataURL("image/png");
        var img = new Image();
        img.onload = function(){
            buffer_ctx.clearRect(0,0,buffer.width,buffer.height);
            ctx.drawImage(mask,0,0);
            ctx.globalCompositeOperation = 'source-in';
            ctx.drawImage(img,0,0);
        }
        img.src = image;
    }