Html5 Canvas Set Z-Index

HTML5 Canvas set z-index

Yes..kind of yes. You can use globalCompositeOperation to "draw behind" existing pixels.

ctx.globalCompositeOperation='destination-over';

Here's an example and a Demo:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");

var cx=100;

drawCircle()
cx+=20;

ctx.globalCompositeOperation='destination-over';

$("#test").click(function(){
drawCircle();
cx+=20;
});

function drawCircle(){
ctx.beginPath();
ctx.arc(cx,150,20,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle=randomColor();
ctx.fill();
}

function randomColor(){
return('#'+Math.floor(Math.random()*16777215).toString(16));
}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id="test">Draw new circle behind.</button><br>
<canvas id="canvas" width=300 height=300></canvas>

How can I control z-index of canvas objects?

You are most likely waiting for images to load before drawing them.

Additionally, you are probably drawing lines as soon as you can.

You need to wait for all images to load, then draw everything in the order you want (from farthest z-order to closest). Do not draw anything until all images have been loaded, or your z-order will not be correct.

If you want to show items on the screen before all images are loaded, you must redraw everything on each image load, not just draw that one image.

Here's an example, where I draw 3 objects: A circle, an image, and a window. I draw them immediately, whether the image is loaded or not, but I draw all of them again once the image is loaded to ensure that the image is correctly in between the other two objects:

http://jsfiddle.net/U5bXf/32/

The shorthand relevant code (in case jsfiddle goes down) is:

var img = new Image()
img.onload = function() {
draw()
};
img.src = "http://placekitten.com/100/140";

draw();

function draw() {
// object one

// Now we'll draw the image in between, if its loaded
ctx.drawImage(img, 100, 30);

// object two
}

Code below this line is a response to the comments

You've since posted code, but you'll notice that the only thing you are drawing in the onload function is the image.

The onload function usually happens after the other drawing commands (unless the page is already loaded, then it could be either). You need to move all drawing code into the onload function or else make your own drawing function that loads everything. For example:

<img id="black_checkers_piece" src="egsdk/BlackCheckersPiece.png" style="display: none;">
<canvas id="c1" style="border:1px solid #998800"></canvas>
<script type="text/javascript">
var canvasID = document.getElementById('c1');
var ctx = canvasID.getContext('2d');
var img = new Image();
img.src = document.getElementById('black_checkers_piece').src;
img.onload = function(){
// assuming we want the image drawn before the line:
ctx.drawImage(img, 10, 10, 32, 32);

ctx.beginPath();
ctx.strokeStyle = 'red';
ctx.moveTo(0, 0);
ctx.lineTo(50, 50);
ctx.stroke();
}

How can I simulate z-index in canvas

It's not that canvas doesn't have a z-index, it's that canvas doesn't keep objects drawn contrary to the HTML page. It just draws on the pixel matrix.

There are basically two types of drawing models :

  • object ones (usually vector) : objects are kept and managed by the engine. They can usually be removed or changed. They have a z-index
  • bitmap ones : there are no objects. You just change a pixel matrix

The Canvas model is a bitmap one. To have objects drawn over other ones, you must draw them after. This means you must manage what you draw.

The canvas model is very fast, but if you want a drawing system managing your objects, maybe you need SVG instead.


If you want to use a canvas, then the best is to keep what you draw as objects.
Here's an example I just made : I keep a square list and every second I randomize their zindex and redraw them :

var c = document.getElementById('c').getContext('2d');
function Square(x, y, s, color) {
this.x = x; this.y = y; this.s = s; this.color = color;
this.zindex=0;
}
Square.prototype.draw = function(c) {
c.fillStyle = this.color;
c.fillRect(this.x, this.y, this.s, this.s);
}
var squares = [
new Square(10, 10, 50, 'blue'), new Square(40, 10, 40, 'red'), new Square(30, 50, 30, 'green'),
new Square(60, 30, 40, '#111'), new Square(0, 30, 20, '#444'), new Square(70, 00, 40, '#999')
];

function draw() {
c.fillStyle = "white";
c.fillRect(0, 0, 1000, 500);
for (var i=0; i<squares.length; i++) squares[i].draw(c);
}
setInterval(function(){
// give all squares a random z-index
squares.forEach(function(v){v.zindex=Math.random()});
// sort the list accordingly to zindex
squares.sort(function(a,b){return a.zindex-b.zindex});
draw();
}, 1000);

Demonstration

The idea is that the square array is sorted accordingly to zindex. This could be easily extended to other types of objects.

HTML5 Canvas Change Image Z-Index

One way to make multiple layers is by using multiple canvases and stacking them over each other with CSS positioning.

When you want to use only one canvas, you can start your drawing loop with erasing your whole canvas and then redrawing the whole scene from back to front. When you use requestAnimationFrame, you shouldn't even have any flickering, because the rendering engine of the web browser will take care of that.

Another option could be to use globalCompositeOperation. It allows you to mask what you draw with what is already drawn. When you use the mode destination-over, you will only draw on pixels where nothing else is drawn.

Issue with Layering Canvases using z-index

First time answering on SO, but I believe I have the answer to your question.

I redid the HTML and JavaScript to be as simplistic as possible, since your question seems to be at the root of it all, asking for help on changing canvas layering, so I did it as simply as I could think of, here is the code, followed by a link to the codepen:

<!DOCTYPE html>

<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Canvas Layering</title>
</head>

<body>
<div style="position: relative;">
<canvas id="layer1" width="100" height="100"
style="position: absolute; left: 0; top: 0; z-index: 0; background-image: url(https://static.pexels.com/photos/158780/leaf-nature-green-spring-158780.jpeg);" onclick="ChangePicture(1)"></canvas>
<canvas id="layer2" width="100" height="100"
style="position: absolute; left: 0; top: 0; z-index: 1; background-image: url(https://static.pexels.com/photos/54320/rose-roses-flowers-red-54320.jpeg);" onclick="ChangePicture(2)"></canvas>
<canvas id="layer3" width="100" height="100"
style="position: absolute; left: 0; top: 0; z-index: 2; background-image: url(https://static.pexels.com/photos/5412/water-blue-ocean.jpg);" onclick="ChangePicture(3)"></canvas>
</div>
</body>

<script>

function ChangePicture(layerNumber) {
if (layerNumber === 1) {
document.getElementById("layer1").style.zIndex = "0";
document.getElementById("layer2").style.zIndex = "2";
document.getElementById("layer3").style.zIndex = "1";
} else if (layerNumber === 2) {
document.getElementById("layer1").style.zIndex = "1";
document.getElementById("layer2").style.zIndex = "0";
document.getElementById("layer3").style.zIndex = "2";
} else if (layerNumber === 3) {
document.getElementById("layer1").style.zIndex = "2";
document.getElementById("layer2").style.zIndex = "1";
document.getElementById("layer3").style.zIndex = "0";
} else {
console.log("Failed.");
}
}

</script>

</html>

https://codepen.io/levi_blodgett/pen/KQyWoR

If you want to change what picture starts as the default, simply change the z-index for the styling inside the html.

About CSS z-index value to a canvas

z-index Sets the stacking order of positioned elements, So it works only for positioned elements.

For Fix:

Insert position: absolute; to highscore

Demo

HTML5 Canvas & z-index issue in Google Chrome

I tested the same fiddle in Chrome 27/winXP and it behaves exactly as you describe; It looks like a bug in chrome or webkit for windows, I tested early with chrome 23/linux and it worked OK.

I found a workarround jsfiddle by warping both, the h1 and the canvas with a fixed div:

<div id='fixedContainter'>
<h1>Test Title</h1>
<canvas id="backgroundCanvas" width="956" height="256"></canvas>
</div>

The div should also have z-index:-10 if your intent is to make it a background.

CSS:

#fixedContainter{position: fixed; z-index: -10; }
h1{position: fixed;}
body{height: 2000px; }
canvas{ position: fixed; z-index: -10; }

Canvas and z-index

You need to have a look at absolute positing of elements and z-index

If you position the img absolutely, set the z-index, and then remove the margin-top from the canvas element, this should work.



Related Topics



Leave a reply



Submit