Управление z-индексом в Fabric.js

В Fabricjs я хочу создать сцену, в которой объект под мышью поднимается в верхнюю часть сцены по z-индексу, а затем, как только мышь покидает этот объект, он возвращается к z-индексу, откуда он пришел. Нельзя установить object.zindex (что было бы неплохо). Вместо этого я использую объект-заполнитель, который помещается в список объектов в старую позицию, а затем старый объект помещается обратно в позицию, где он был в списке, с помощью canvas.insertAt. Однако это не работает.

См. http://jsfiddle.net/rFSEV/ для статуса этого.

var canvasS = new fabric.Canvas('canvasS', { renderOnAddition: false, hoverCursor: 'pointer', selection: false });
var bars = {}; //storage for bars (bar number indexed by group object)
var selectedBar = null; //selected bar (group object)
var placeholder = new fabric.Text("XXXXX", { fontSize: 12 });

//pass null or a bar
function selectBar(bar) {
    if (selectedBar) {
        //remove the old topmost bar and put it back in the right zindex
        //PROBLEM: It doesn't go back; it stays at the same zindex
        selectedBar.remove();
        canvasS.insertAt(selectedBar, selectedBar.XZIndex, true);
        selectedBar = null;
        }
    if (bar) {
        //put a placeholder object ("XXX" for now) in the position
        //where the bar was, and put the bar in the top position
        //so it shows topmost
        selectedBar = bar;
        canvasS.insertAt(placeholder, selectedBar.XZIndex, true);
        canvasS.add(bar);
        canvasS.renderAll();
        }
    }

canvasS.on({
     'mouse:move': function(e) {
        //hook up dynamic zorder
        if (!e.target) return;
        if (bars[e.target])
            selectBar(e.target);
        else
            selectBar(null);
        },
    });

var objcount = canvasS.getObjects().length;

//create bars
for (var i = 0; i < 20; ++i) {
    var rect = new fabric.Rect({
      left: 0,
      top: 0,
      rx: 3,
      ry: 3,
      stroke: 'red',
      width: 200,
      height: 25
    });
    rect.setGradientFill({
      x1: 0,
      y1: 0,
      x2: 0,
      y2: rect.height,
      colorStops: {
        0: '#080',
        1: '#fff'
      }
    });    
    var text = new fabric.Text("Bar number " + (i+1), {
        fontSize: 12
    });
    var group = new fabric.Group([ rect, text ], {
      left: i + 101,
      top: i * 4 + 26
    });
    group.hasControls = group.hasBorders = false;

    //our properties (not part of fabric)
    group.XBar = rect;
    group.XZIndex = objcount++;

    canvasS.add(group);
    bars[group] = i;
    }
canvasS.renderAll();

person Ian    schedule 03.01.2013    source источник
comment
В Fabric есть 4 метода для управления z-index: BringForward (на 1 уровень вверх), BringToFront (полностью вверх), sendBackwards (на 1 уровень вниз) и sendToBack (полностью вниз). Все они могут быть вызваны непосредственно на объекте или на холсте (переходя через нужный объект).   -  person kangax    schedule 04.01.2013
comment
Это хорошая информация, но вы говорите, что insertAt не влияет на z-index? (Какова цель insertAt тогда?). Кроме того, если эти 4 метода являются единственным вариантом, нам пришлось бы вызывать sendBackwards N раз: скажем, чтобы переместить его с z-index 105 на 55, нам пришлось бы вызывать его 50 раз в цикле, что, по-видимому, перерисовывало бы каждый время. Это безумно сложно.   -  person Ian    schedule 05.01.2013
comment
insertAt тоже должно работать. Это предназначено именно для вставки объекта в правильное место. Однако он используется для добавления новых объектов на холст. Чтобы изменить z-индекс существующих объектов, вы можете либо использовать эти 4 метода, либо напрямую изменить массив canvas._objects. z-index просто совпадает с индексом объектов в этом массиве (сначала отображается 0, затем 1, затем 2 и т. д.)   -  person kangax    schedule 06.01.2013


Ответы (5)


Начиная с версии Fabric.js 1.1.4 доступен новый метод манипулирования zIndex:

canvas.moveTo(object, index);
object.moveTo(index);

Я думаю, что это полезно для вашего варианта использования. Я обновил ваш jsfiddle — надеюсь, это то, что вам нужно:
jsfiddle

person Kienz    schedule 29.04.2013
comment
Также см. github.com/kangax/fabric.js/issues/135 для получение текущего zIndex. - person Aram Kocharyan; 09.10.2014
comment
Также: bringToFront, sendToBack, bringForward, sendBackwards - person Tor Klingberg; 30.09.2015
comment
Не работает корректно с объектами Canvas Group() - person Rboreal_Frippery; 25.10.2019

Также убедитесь, что вы изменили z-index ПОСЛЕ добавления объекта на холст.

Таким образом, код будет выглядеть так:

canvas.add(object);
canvas.moveTo(object, index);

В противном случае Fabricjs не заботятся о установленных вами z-индексах.

person Frantisek    schedule 29.10.2014

После того, как я добавил объект линии, я заставил линию появиться под объектом, используя:

canvas.add(line);
canvas.sendToBack(line);

Другие варианты

  • холст.sendBackwards
  • холст.sendToBack
  • холст.bringForward
  • холст.bringToFront

см.: https://github.com/fabricjs/fabric.js/issues/135< /а>

person Ravi Ram    schedule 30.05.2019

Вы можете изменить свой метод _chooseObjectsToRender, чтобы в его конце было следующее изменение, и вы сможете добиться zIndexing в стиле css.

objsToRender = objsToRender.sort(function(a, b) {
  var sortValue = 0, az = a.zIndex || 0, bz = b.zIndex || 0;

  if (az < bz) {
    sortValue = -1;
  }
  else if (az > bz) {
    sortValue = 1;
  }

  return sortValue;
});

https://github.com/fabricjs/fabric.js/pull/5088/files

person maxhud    schedule 05.07.2018

Вы можете использовать эти две функции для получения z-индекса объекта структуры и изменения z-индекса объекта, поскольку не существует специального метода для изменения z-индекса по индексу объекта:

fabric.Object.prototype.getZIndex = function() {
    return this.canvas.getObjects().indexOf(this);
}

fabric.Canvas.prototype.moveToLayer = function(object,position) {
    while(object.getZIndex() > position) {
        this.sendBackwards(object);
    }
}
person Ashitaka    schedule 14.05.2020