Composition using Canvas in HTML5
Composing means combining several images into one image. In combination with the alpha property (transparency using either rgba or globalAlpha), it is a very powerful tool for bringing elements from various scenes into a single scene.
We can draw new shapes behind existing shapes and mask off certain areas and clear sections from the canvas using globalCompositeOperation attributes.
In other words we can say that to perform a composite operation with a HTML5 Canvas, we can use the globalCompositeOperation property of the canvas context. This property defines the composite operation between the source and destination states of the canvas. Assuming you are trying to compose two different images, the image you draw first is the "source" and the second image is the "destination". Before drawing the destination, you should use the globalCompositeOperation attribute to specify the type of composing you wish to do.
NOTE: It's important to note that a canvas context can only support one composite operation throughout its life cycle. If we want to use multiple composite operations, as this tutorial does, we need to apply the operations on a hidden canvas and then copy the results onto a visible canvas.
This attribute takes the following twelve values:
source-over: The destination image that goes over the source. The destination will cover parts of the source where they intersect.
source-in: Only those parts of the destination that intersect with the source are visible.
source-out: Only those parts of the destination that fall outside the source are visible.
source-atop: The source and parts of the destination that intersect with the source are visible. Where the destination covers the source, the source is invisible.
destination-over: The source image goes over the destination and covers the intersecting parts of the destination.
destination-in: Only those parts of the source that intersect with the destination are visible.
destination-out: Only those parts of the source that fall outside the destination are visible.
destination-atop: The destination and parts of the source that intersect with the destination are visible. Where the source covers the destination, the destination is invisible.
lighter: The portion where source and destination intersect appear lighter, with the colour of the destination being dominant.
darker: Where both shapes overlap the color is determined by subtracting color values.
copy: Only draws the new shape and removes everything else.
xor: The intersecting pixels of the source and destination are xored.
Example
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>Composition in HTML5</title>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 1px solid #9C9898;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="430"></canvas>
<canvas id="tempCanvas" width="578" height="430" style="display: none;"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var tempCanvas = document.getElementById('tempCanvas');
var tempContext = tempCanvas.getContext('2d');
var squareWidth = 55;
var circleRadius = 35;
var shapeOffset = 50;
var operationOffset = 150;
var arr = [];
arr.push('source-atop');
arr.push('source-in');
arr.push('source-out');
arr.push('source-over');
arr.push('destination-atop');
arr.push('destination-in');
arr.push('destination-out');
arr.push('destination-over');
arr.push('lighter');
arr.push('darker');
arr.push('xor');
arr.push('copy');
// translate context to add 10px padding
context.translate(10, 10);
// draw each of the operations
for (var n = 0; n < arr.length; n++) {
var thisOperation = arr[n];
tempContext.save();
// clear temp context
tempContext.clearRect(0, 0, canvas.width, canvas.height);
// draw rectangle (destination)
tempContext.beginPath();
tempContext.rect(0, 0, squareWidth, squareWidth);
tempContext.fillStyle = 'blue';
tempContext.fill();
// set global composite
tempContext.globalCompositeOperation = thisOperation;
// draw circle (source)
tempContext.beginPath();
tempContext.arc(shapeOffset, shapeOffset, circleRadius, 0, 2 * Math.PI, false);
tempContext.fillStyle = 'red';
tempContext.fill();
tempContext.restore();
// draw text
tempContext.font = '10pt Verdana';
tempContext.fillStyle = 'black';
tempContext.fillText(thisOperation, 0, squareWidth + 45);
// translate visible context so operation is drawn in the right place
if (n > 0) {
if (n % 4 === 0) {
context.translate(operationOffset * -3, operationOffset);
}
else {
context.translate(operationOffset, 0);
}
}
// copy drawing from tempCanvas onto visible canvas
context.drawImage(tempCanvas, 0, 0);
}
</script>
</body>
</html>
Output