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 t
You can do that using another canvas as mask :
// This is the canvas where you want to draw
var canvas = document.getElementById('your-canvas');
var ctx = canvas.getContext('2d');
// I'll use a skyblue background that covers everything
// Just to demonstrate
ctx.fillStyle = "skyblue";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Create a canvas that we will use as a mask
var maskCanvas = document.createElement('canvas');
// Ensure same dimensions
maskCanvas.width = canvas.width;
maskCanvas.height = canvas.height;
var maskCtx = maskCanvas.getContext('2d');
// This color is the one of the filled shape
maskCtx.fillStyle = "black";
// Fill the mask
maskCtx.fillRect(0, 0, maskCanvas.width, maskCanvas.height);
// Set xor operation
maskCtx.globalCompositeOperation = 'xor';
// Draw the shape you want to take out
maskCtx.arc(30, 30, 10, 0, 2 * Math.PI);
maskCtx.fill();
// Draw mask on the image, and done !
ctx.drawImage(maskCanvas, 0, 0);
<canvas id="your-canvas">
Demo here.
The way this would typically be done is with a "clipping region", where you make an area mask for which the drawing operations apply. HTML5 canvas has the ability to make a clipping mask that is the circle itself...
http://www.html5canvastutorials.com/tutorials/html5-canvas-clipping-region-tutorial/
...but it lacks the subtract() operation that's in Google Gears Canvas, which I spotted and they claimed is "from HTML5"...but apparently it is not.
Someone answered how to invert a clip() here, but it involves an off-screen canvas:
Canvas 'Clip' reverse action?
Hopefully someone else will have a better suggestion. :-/
Using the XOR function on a canvas mask only works with opaque fills (i.e. not compatible with globalAlpha). One way around this is to use the .clip() function and filling the clipped region with what you had in the background. Then, you can overlay the clipped region on top of the original canvas, on which you performed whatever fill you needed to.
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.