Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fabric.js - problem with drawing multiple images zindex

I'm using this script:

var canvas = new fabric.Canvas('game_canvas', { selection: false });

fabric.Image.fromURL('images/bg.jpg', function(img) {
  img.set('left', 1024/2).set('top', 600/2).set('zindex', 0);
  canvas.add(img);        
});

fabric.Image.fromURL('images/panel-2-bg-l-r.png', function(img) {
  img.set('left', 262/2).set('top', (390/2)+110).set('zindex', 1);
  canvas.add(img);        
});

fabric.Image.fromURL('images/player-board.png', function(img) {
  img.set('left', 254/2).set('top', (122/2)).set('zindex', 2);
  canvas.add(img);        
});

fabric.Image.fromURL('images/player-board-top-red.png', function(img) {
  img.set('left', 203/2).set('top', (109/2)).set('zindex', 3);
  canvas.add(img).bringToFront(img);          
});

3rd image draw is working properly and showing one on top of the other. But if I add 4th one it's hiding behind 3rd. If I specify zindex of the image it's still under 3rd only.

What is wrong with this? Am I doing something wrong here? Please help.

Thanks
Peter

like image 805
peterkr Avatar asked Aug 04 '11 10:08

peterkr


2 Answers

There are couple of issues here.

1) You can't change zindex of images by setting their zindex property. Fabric images simply don't have such property and changing it doesn't change z index of images on canvas. This makes all those .set('zindex', 0), .set('zindex', 1), etc. pretty much a no-op.

2) bringToFront works as expected here, bringing last image all the way to the top of the drawing stack. But the problem is that "images/player-board-top-red.png" image which you're loading last is not guaranteed to be the last one added. Those 4 requests are asynchronous; they are coming in any order, and so callbacks are executed in any order as well. In my test, for example, the last image comes second, callback executes, image is brought to the front, but is then "overwritten" by following 2 callbacks.

How to make last image render on top? Well, we can simply check that all images are loaded before attempting to bring last one to the top:

var img4;
// ...
function checkAllLoaded() {
  if (canvas.getObjects().length === 4) {
    canvas.bringToFront(img4);
  }
}
// ...
fabric.Image.fromURL('images/1.png', function(img) {
  img.set('left', 0).set('top', 0);
  canvas.add(img);
  checkAllLoaded(img);
});
// load other images, making sure to include `checkAllLoaded` in callback
fabric.Image.fromURL('images/4.png', function(img) {
  img4 = img.set('left', 0).set('top', 0);
  canvas.add(img);
  checkAllLoaded(img);
});

By the way, don't forget that you can pass an object to set method like so:

img.set({ left: ..., top: ... });

And since set is chainable and returns reference to an instance, you can even pass it to add like so:

canvas.add(img.set({ left: ..., top: ... }));

Hope this helps.

like image 78
kangax Avatar answered Nov 05 '22 19:11

kangax


You can use canvas.insertAt(object,index); instead of canvas.add(object) to set object's zIndex as per your choice.

Also you can get any object by using:

canvas_object = canvas.item(index);

If you want to bring that object in front, use:

canvas_object.bringForward() 

//or

canvas_object.bringToFront() 
like image 21
Amit Sharma Avatar answered Nov 05 '22 19:11

Amit Sharma