How to fill the 'opposite' shape on canvas?

pimvdb picture pimvdb · Jun 7, 2011 · Viewed 18k times · Source

Say I have a circle (an arc) on HTML5 canvas. I can just fill it like this:

ctx.arc(100, 100, 50, 0, 2 * Math.PI);
ctx.fill();

It works a treat. However, how can one fill the opposite area? Now it's white with a black circle, but I'd like it to be along the lines of the following image (on which white is the background color and black is the filling color):

opposite area

I know I could just use a black background and paint a white circle, but the background can be anything (all kinds of things have been drawn there before, so just swapping colors is not possible).

Another thing is that not the complete canvas should be filled, but rather a square with an circle canceled out.

I was thinking of a globalCompositeOperation but it does not seem to fit my needs as none of them act according to what I need.

So, how can I accomplish filling the 'opposite' area like in the example image?

Answer

Bobtato picture Bobtato · Aug 2, 2012

Draw the black shape in the OP-- that is, draw a rectangle with a circle cut out of the middle.

First call beginPath(); then draw the circle clockwise; then draw the rectangle counter-clockwise (or vice versa); and finally fill().

var ctx = $('#cv').get(0).getContext('2d');

ctx.fillStyle = "grey";
ctx.beginPath();
ctx.arc(200, 200, 100, 0, 2 * Math.PI);
ctx.rect(400, 0, -400, 400);
ctx.fill();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas width="400" height="400" id="cv"></canvas>

It might not be obvious from most of the documentation out there but you can combine multiple subpaths in a single fill(), stroke() or clip() operation. To make a hole in a shape, you just draw the shape of the hole in the opposite direction. The beginPath() method resets the current path. For fill() and clip(), Canvas uses the non-zero winding number rule-- if you read up on that it should become clearer.