11

I tried to make this happen with canvas' globalCompositeOperation, but had no luck so I'm asking here. There are similar questions here, but I did not find my case among them.

I have layers in my canvas area as so (drawing order from bottom to top):

  • The canvas base is filled with pure white (#fff, with fillRect)
  • First image house is a picture of a house. The background is transparent. (see below)
  • Second image roofOverlay is an overlay "masking" image that has the roof area coloured red (can be anything, but red for clarity, see below)

Both images take up the whole canvas and are lined up perfectly on top of each other, so that the red roof area matches the house.

I then have a repeating background repeatPattern pattern what I want to use ONLY inside the red areas: to fill the red area with repeatPattern. (can be anything, but assume hexagons or whatever)

In pseudocode, this would ideally be something in the lines of:

roofOverlay.maskBackground(repeatPattern)

(On a sidenote, I would also like to be able to mess with the background pattern HSL-values, but I think that's quite straightforward once I get the pattern to even display)

Expected result:

The expected result would be a house which roof is textured with the repeatPattern image.

Note: I'm aware of clipping paths with masks, but I cannot use them here. The example is simplified and drawing all the paths for multiple different houses would be way too much work. I only have the overlayed png-files for the roof.

Images for reference

House house


House roof overlay roofOverlay

0

1 Answer 1

19

Here’s how to composite your “roof pattern” on top of your “house” using “roofOverlay”

enter image description here

This is a multi-part process:

  1. Draw the house on canvas#1.
  2. Draw the red roofOverlay on canvas#2.
  3. Set canvas#2’s context.globalCompositeOperation = 'source-in'
  4. Draw your desired pattern on canvas#2
  5. Compositing will cause your desired pattern to replace the red overlay—only in the red overlay area.

Here is a Fiddle that loads grass on your roof: http://jsfiddle.net/m1erickson/SWP6v/

And here is code that uses a lattice pattern fill on your roof:

Note: I'm assuming that you want the house and roof on separate canvases so you can flip through a variety of roof choices. If you need everything on 1 canvas, you can just draw the roof canvas onto the house canvas.

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
    #container{position:relative;}
    #house{position:absolute; top:0; left:0;}
    #canvas{position:absolute; top:0; left:0;}
</style>

<script>
$(function(){

    var house=document.getElementById("house");
    var ctxHouse=house.getContext("2d");
    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");

    var red=new Image();
    red.onload=function(){
       canvas.width=red.width;
       canvas.height=red.height;

       var houseImage=new Image();
       houseImage.onload=function(){
           house.width=houseImage.width;
           house.height=houseImage.height;
           ctxHouse.drawImage(houseImage,0,0);
       }
       houseImage.src="https://dl.dropbox.com/u/1122582/stackoverflow/house.png";

       ctx.drawImage(red,0,0);

        var imageObj = new Image();
        imageObj.onload = function() {
          var pattern = ctx.createPattern(imageObj, 'repeat');
          ctx.globalCompositeOperation = 'source-in';
          ctx.rect(0, 0, canvas.width, canvas.height);
          ctx.fillStyle = pattern;
          ctx.fill();
        };
        imageObj.src = "http://dl.dropbox.com/u/139992952/stackoverflow/lattice.jpg";
    }
    red.src="https://dl.dropbox.com/u/1122582/stackoverflow/roof-overlay.png";

}); // end $(function(){});
</script>

</head>

<body>
<div id="container">
        <canvas id="house" width=300 height=300></canvas>
        <canvas id="canvas" width=300 height=300></canvas>
</div>
</body>
</html>
2
  • This answer confused me, but it helped by pointing me in the right direction, which was to google ctx.globalCompositeOperation Commented Jan 9, 2014 at 22:24
  • The fiddle seems no result to show now. Dropbox images are all 404 Commented Mar 21, 2014 at 20:33

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