TLDR;
Can’t be done natively, use this instead: layeredCanvas
HTML5 Canvas doesn’t implement a layers mechanism. In order to implement this you can do it in 2 different ways:
Multiple canvas elements approach
Think of a layer as an individual canvas and then absolute position one on top of the other. Then to lay it out just wrap on a div with position relative:
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 |
<div style="width: 300px; height: 300px; position: relative"> <canvas id="layer1" width="300" height="300" style="position: absolute;"></canvas> <canvas id="layer2" width="300" height="300" style="position: absolute;"></canvas> <canvas id="layer3" width="300" height="300" style="position: absolute;"></canvas> </div> <script> function layer1() { canvas = document.getElementById( "layer1" ); ctx = canvas.getContext( '2d' ); ctx.fillStyle = "#E5E059"; ctx.fillRect( 50, 50, 150, 150 ); } function layer2() { canvas = document.getElementById( "layer2" ); ctx = canvas.getContext( '2d' ); ctx.beginPath(); ctx.fillStyle = "#88A09E"; ctx.arc( 275, 275, 150, 0, 2 * Math.PI ); ctx.fill(); } function layer3() { canvas = document.getElementById( "layer3" ); ctx = canvas.getContext( '2d' ); ctx.fillStyle = "#C70039"; ctx.beginPath(); ctx.moveTo(100, 100); ctx.lineTo(100, 300); ctx.lineTo(300, 300); ctx.closePath(); ctx.fill(); } layer1(); layer2(); layer3(); </script> |
What’s crappy about this is if you want to save the image you have to do a screenshot and then cut it, or you can only save one canvas element at a time.
Single canvas element approach
Natively, there is no way of doing this, but with a little bit of abstraction, it isn’t a problem. Think of a layer as a function, now you call the functions in order and you are mostly layered:
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 |
<canvas id="layeredCanvas" width="300" height="300"></canvas> <script> function layer1( ctx ) { ctx.fillStyle = "#E5E059"; ctx.fillRect( 50, 50, 150, 150 ); } function layer2( ctx ) { ctx.beginPath(); ctx.fillStyle = "#88A09E"; ctx.arc( 275, 275, 150, 0, 2 * Math.PI ); ctx.fill(); } function layer3( ctx ) { ctx.fillStyle = "#C70039"; ctx.beginPath(); ctx.moveTo(100, 100); ctx.lineTo(100, 300); ctx.lineTo(300, 300); ctx.closePath(); ctx.fill(); } canvas = document.getElementById( "layeredCanvas" ); ctx2d = canvas.getContext( '2d' ); layer1( ctx2d ); layer2( ctx2d ); layer3( ctx2d ); </script> |
This is still a bit crappy … lets make it slight more layer-like. We can make an array of functions and run them in sequence. This is much better because now we can remove (or change the index) an element from the array effectively replicating a layer feel:
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 |
<canvas id="layeredCanvas" width="300" height="300"></canvas> <script> render = function( layers ) { for ( var i = 0; i < layers.length; i++ ) { layers[ i ](); } }; canvas = document.getElementById( "layeredCanvas" ); ctx = canvas.getContext( '2d' ); layers = []; layers.push( function() { ctx.fillStyle = "#E5E059"; ctx.fillRect( 50, 50, 150, 150 ); } ); layers.push( function() { ctx.beginPath(); ctx.fillStyle = "#88A09E"; ctx.arc( 275, 275, 150, 0, 2 * Math.PI ); ctx.fill(); } ); layers.push( function() { ctx.fillStyle = "#C70039"; ctx.beginPath(); ctx.moveTo(100, 100); ctx.lineTo(100, 300); ctx.lineTo(300, 300); ctx.closePath(); ctx.fill(); } ); render( layers ); </script> |
DONE! Not too bad … using this principle I created a more elegant approach that allows you a couple more neat little things like show/hide … try it, fork it, use it: layeredCanvas