HTML5 Canvas set z-index

Is it possible to set the z-index of a drawn object in HTML5 canvas?

I am trying to get it so one object can be infront of a the "player" and another object is behind the "player"

Answers:

Answer

Yes..kind of yes. You can use compositing 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>

Answer

Just draw the things behind it first, then the thing, then the other objects.

To do hit testing you may need to iterate backwards over your display list, testing each object. This will work if you know the object boundaries really well.

Or you may want to try some standard graphics tricks like drawing the same objects to another in-memory canvas with unique colours for every object drawn: to hit test this just check the pixel colour on the in-memory canvas. Neat ;-)

Answer

Or you could simply use an array containing your objects to be drawn then sort this array using the zIndex property of each child. Then you jist iterate that array and draw.

var canvas = document.querySelector('#game-canvas');
var ctx = canvas.getContext('2d');

// Define our shape "class".
var Shape = function (x, y, z, width, height) {
  this.x = x;
  this.y = y;
  this.zIndex = z;
  this.width = width;
  this.height = height;
};
// Define the shape draw function.
Shape.prototype.draw = function () {
  ctx.fillStyle = 'lime';
  ctx.fillRect(this.x, this.y, this.width, this.height);
};

// let's store the objects to be drawn.
var objects = [
  new Shape(10, 10, 0, 30, 30), // should be drawn first.
  new Shape(50, 10, 2, 30, 30), // should be drawn third.
  new Shape(90, 10, 1, 30, 30)  // should be drawn second.
];

// For performance reasons, we will first map to a temp array, sort and map the temp array to the objects array.
var map = objects.map(function (el, index) {
  return { index : index, value : el.zIndex };
});

// Now we need to sort the array by z index.
map.sort(function (a, b) {
  return a. value - b.value;
});

// We finaly rebuilt our sorted objects array.
var objectsSorted = map.map(function (el) {
  return objects[el.index];
});

// Now that objects are sorted, we can iterate to draw them.
for (var i = 0; i < objectsSorted.length; i++) {
  objectsSorted[i].draw();
}

// Enjoy !

Note that I didnt tested that code and wrote it on my cellphone, so there might be typos, but that should permits to understand the principle, i hope.

Answer

A solution that I've found works for me (and gets rid of flickering, hurrah!) is to use two canvases. (or more)

I will assume you are making a game of some kind (since you mention a player) and use that as an example.

You can take a page from the way windows works and put a canvas first as a background with another canvas over it as your player canvas. You can mark the player canvas as 'dirty' or changed whenever it has been altered and only redraw the changed layer when needed. This means that you only update the second canvas when your player moves or takes an action.

This method can be taken even farther and you can add a third canvas for a HUD with gameplay stats on it that is only changed when the player's stats change.

The html might look something like this:

<canvas id="background-canvas" height="500" width="1000" style="border:1px solid #000000;"></canvas>
<canvas id="player-canvas" height="500" width="1000" style="border:1px solid #000000;"></canvas>
<canvas id="hud-canvas" height="500" width="1000" style="border:1px solid #000000;"></canvas>
Answer

Sorry, but nope, the canvas element will have its z-index and anything drawn on it will be on that layer.

If you are referring to different things on the canvas then yes, anything that is drawn is drawn on top of whatever was there before.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.