How can I simulate z-index in canvas

13,776

Solution 1

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.

Solution 2

As dystroy has said, z-index is, at its simplest, just an index to tell you in what order to draw things on the canvas, so that they overlap properly.

If you mean to do more than this, say to replicate the existing workings of a browser, then you would have more work to do. The order in which objects are drawn in a browser is a complicated calculation that is driven by:

  1. The DOM tree
  2. Elements' position attributes
  3. Elements' z-index attributes

The canonical source to this is the Elaborate description of Stacking Contexts, part of the CSS specification.

Share:
13,776
JalalJaberi
Author by

JalalJaberi

As I see my technical aspect of life: He is a software engineer He Loves the technical dept. but he hates the technical debt He is a C++ evangelist He has a master degree (CS from Amirkabir university of Tehran) He has experienced broad type of IT projects, from simple web api's to real-time AR, computer vision, developing games, and so on He is actively searching for delighting jobs in some fields game industry subcategories in AI (CV, ML, ...) IOT

Updated on June 09, 2022

Comments

  • JalalJaberi
    JalalJaberi almost 2 years

    I have asked a question before: How can I control z-index of canvas objects? and we reached to a solution that may not be a good one for complicated situations.

    I found that canvas doesn't have a z-index system, but a simple ordered drawing one. Now there is a new question: how can I simulate z-index system to make this problem fixed in complicated situations?

    The good answer can solve a big problem.

  • JalalJaberi
    JalalJaberi over 11 years
    Thanks, but have you seen that question? I know that it is possible now, but in a manner that make code dirty. I am searching for a clean way.
  • JalalJaberi
    JalalJaberi over 11 years
    Thanks, if it is possible with DOM I am very pleased to being familiar with. That's nice.
  • Ian Clelland
    Ian Clelland over 11 years
    Sorry, I don't mean to say that you can control your canvas output in any way with the DOM -- I mean that the browser's use of z-index for regular html elements is more complicated than you might think. If you want to replicate HTML-like stacking in canvas, though, that's your best reference.
  • JalalJaberi
    JalalJaberi over 11 years
    Got it. I will try to do such a business.
  • Denys Séguret
    Denys Séguret over 11 years
    @JalalJaberi Is it clearer with the example ? I give a z-index to all my squares.
  • Cerbrus
    Cerbrus over 11 years
    @JalalJaberi: this is as clean as you'll get it when using the canvas. You will have to sort the elements you're going to draw. This requires no less than the code dystroy answered with.
  • JalalJaberi
    JalalJaberi over 11 years
    Yes, there is no problem with shapes, but when images enter the scene there is some latency to load. Because of this latency we will be forced to draw anything in image onload event. Is that true?
  • JalalJaberi
    JalalJaberi over 11 years
    Or wait all images to load. That makes life hard.
  • Denys Séguret
    Denys Séguret over 11 years
    @JalalJaberi This is a different question, and the answer should depend on the context, but basically "not always". If you draw periodically, you could just test if the image is yet loaded at each draw. When I use many images, I also make sure I use a sprite system (i.e. I embed them all in a bigger image so that there is only one request).
  • JalalJaberi
    JalalJaberi over 11 years
    Thank you, I did understand :)