Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I simulate z-index in canvas

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.

like image 702
JalalJaberi Avatar asked Jan 11 '13 07:01

JalalJaberi


2 Answers

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.

like image 51
Denys Séguret Avatar answered Nov 13 '22 04:11

Denys Séguret


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.

like image 37
Ian Clelland Avatar answered Nov 13 '22 04:11

Ian Clelland