To perform a composite operation with 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.
destination is defined as the canvas state preceding a composite operation.
source is defined as the canvas state following a composite operation.
We can perform one of 11 composite operations including
source-atop,
source-in,
source-out,
source-over,
destination-atop,
destination-in,
destination-out,
destination-over,
lighter,
xor, and
copy. Unless otherwise specified, the default composite operation is
source-over.
1
| context.globalCompositeOperation=[value]; |
HTML5 Canvas Global Composite Operations Example
Open in new window
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
| window.onload = function(){
var squareWidth = 55;
var circleRadius = 35;
var rectCircleDistX = 50;
var rectCircleDistY = 50;
var operationArray = new Array();
operationArray.push("source-atop"); // 0
operationArray.push("source-in"); // 1
operationArray.push("source-out"); // 2
operationArray.push("source-over"); // 3
operationArray.push("destination-atop"); // 4
operationArray.push("destination-in"); // 5
operationArray.push("destination-out"); // 6
operationArray.push("destination-over"); // 7
operationArray.push("lighter"); // 8
operationArray.push("xor"); // 9
operationArray.push("copy"); // 10
// draw each of the eleven operations
for (var n = 0; n < operationArray.length; n++) {
var thisOperation = operationArray[n];
var canvas = document.getElementById(thisOperation);
var context = canvas.getContext("2d");
var rectX = 10;
// draw rectangle
context.beginPath();
context.rect(rectX, 0, squareWidth, squareWidth);
context.fillStyle = "blue";
context.fill();
context.globalCompositeOperation = thisOperation;
// draw circle
context.beginPath();
context.arc(rectX + rectCircleDistX, rectCircleDistY, circleRadius, 0, 2 * Math.PI, false);
context.fillStyle = "red";
context.fill();
}
}; |
I think the result of “destination-in” should be a quarter-pie shape…
Which browser are you using? Currently, only Firefox 4 Beta supports all 11 composite operations. Chrome and Safari fall short.
I see. They are rendered dynamically – I was using chrome 10 on mac.
I was able to get “destination-in” work correctly in chrome/safari by drawing into a temp canvas first, and use the temp canvas as the source.
Rock on! Give us a link so we can see what you did!
hey erick great website i was wondering when i use the global alpha , its making my two canvas or elements transparent, i have an image and also a square , i want the square to be the only transparent, can you explain me how to achieve this? thanks i really appreciate it i am totally new at this!
forgot to mention that i have tried to mixed with the globalCompositeOperation but still both items gets transparent .. thanks again
Sure, it would look something like this:
context.drawImage(imageObj,x,y);
// set transparency of rectangle to 50%
context.globalAlpha=0.5;
context.fillRect(x,y,width,height);
Ok so I’m trying to do some combination of a few things.
I need to have a linear gradient circle, with the center cut out, on top of an image that is clipped in a circle.
I got the circle image clipped, I’m just struggling with getting the gradient ring on top to work. I can’t decide if using destination-out or just using .clip() is better. I’ve tried both and can’t get it to work right.
Any suggestions?
@Jared – heya! I feel your pain. Unfortunately none of the browsers have really implemented composite operations correctly, and you’re only able to do one composite operation for the entire canvas! (that’s why this tutorial makes use of 11 different canvases) When they are working correctly in the future, however, you’re right, you’d want to use a destination-out operation to cut out a circle.
For the time being, the only solution that I know of at the moment is to create a secondary buffer canvas, use the destination-out operation to cut a circle out of another circle and then copy the result onto the canvas you’re drawing on. When I get a chance, I’ll create a tutorial that covers this technique since it’s definitely something that a lot of us have struggled with.
Which program do you use for this?
@JimHendriks not sure I follow. If you’re referring to this website, I’m using WordPress
@Eric Sorry for being unclear, I would like to know what program you use for making your HTML5 creations. In what program are you typing the code?
@JimiHendriks nothing special, I usually use Eclipse or Aptana so I can get code coloring, code formatting, and Javascript validation. Sometimes I use notepad++ :)
Thanks for your reply. I am using Aptana too and wanted to know if this is a common program developers use.
One more question, not sure if it belongs in this tutorial, but any change of an upcoming tutorial on how to make an old school Snake game? That would be fantastic!
@Jim Aptana is nice.
I don’t have plans at the moment to create any small games because I’ve been so busy with KineticJS. Maybe you could create one and post it here? :)
Eric! Great site!!! You seem to be missing one “darker”
(The Mozilla dev site here: [https://developer.mozilla.org/en/Canvas_tutorial/Compositing] says it’s Unimplemented. (If that’s even a word!)
@Joel yes, although you’d intuitively think that there should be a darker composite operation since there’s a lighter composite, it’s actually not in the HTML5 spec:
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html
I do believe that some browsers have added / dropped support for it, but since it’s not in the spec, I haven’t added it to this tutorial :)
Great tutorial. I’m trying to erase an image by “xor”ing it with itself, which almost works, but it leaves an outline of the image. Any idea why?
Thanks.
@Michael what do you mean by “outline”? Do you mean that a 1px perimeter of the image is still visible?
Could you show us a jsfiddle demo?
Yes, that’s precisely it. Basically an Asteroids-style game. When the ship gets destroyed, I’m having the pixels blow apart, but I want to do it without redraw/clearRect flickering. So I’m xor-ing every old image of the ship against itself, then drawing the new (exploding) image.
I’ll look into jsfiddle, but for now, can you tell me if there’s anything basically wrong with these few lines of code?:
//xor-out the old, less exploded image of the ship
hiddenContext.putImageData(oldImageData,this.x,this.y);
visibleContext.globalCompositeOperation = “xor”;
visibleContext.drawImage(hiddenCanvas,0,0);
visibleContext.globalCompositeOperation = “source-over”;
//save the new image data for the next loop
oldImageData = newImageData;
//draw the new, slightly more ‘exploded’ image of the ship
hiddenContext.putImageData(newImageData,this.x,this.y);
visibleContext.drawImage(wCanvas,0,0);
Does Kinetic JS have this property?
@Andy not yet, and I’m not sure if it will. Composite operations are used to create very specific shapes and effects. I think it makes more sense for them to be used with custom shapes. More on that here:
http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-shape-tutorial/
Thoughts?