Sunday, August 19, 2018

Sending multiple objects forward changes their order (z-index)

The following snippet has a green square above a red square

  1. Select both squares by dragging over them.
  2. Click the bring forward button

After clicking bring forward the squares have switched order. It is my understanding that the items should stay in the same order, but be moved increasingly above other non-selected items as the button is further clicked.

If you deselect, and repeat the experiment you will see that they switch again.

Any ideas?

var canvas = new fabric.Canvas('c', 
{
  preserveObjectStacking : true
});

var rect = new fabric.Rect({
  left: 10, top: 10,
  fill: 'red',
  width: 100, height: 100,
  hasControls: true
});

canvas.add(rect);

var rect2 = new fabric.Rect({
  left: 40, top: 40,
  fill: 'green',
  width: 100, height: 100,
  hasControls: true
});

canvas.add(rect2);

$("#bringForward").click(function()
{
 var items = canvas.getActiveObject() || canvas.getActiveGroup();

 if(items)
  items.bringForward();
});




Solved

This can be considered a bug or not, depending on what do you expect the function to do.

The documentation for the feature says: Moves an object or a selection up in stack of drawn objects And is actually doing so. The object on top cannot go more on top, the one under can and goes.

Still for a dev this can look like a weird behaviour, to me not really. But guess is personal.

Here is your widget with a modified snippet to try a better solution.

var removeFromArray = fabric.util.removeFromArray;

// modified function to avoid snapping
fabric.StaticCanvas.prototype.bringForward = function (object, intersecting) {
      if (!object) {
        return this;
      }
      var activeGroup = this._activeGroup,
          i, obj, idx, newIdx, objs, latestIndex;

      if (object === activeGroup) {
        objs = activeGroup._objects;
        latestIndex = this._objects.length;
        for (i = objs.length; i--;) {
          obj = objs[i];
          idx = this._objects.indexOf(obj);
          if (idx !== this._objects.length - 1 && idx < latestIndex - 1) {
            newIdx = idx + 1;
            latestIndex = newIdx;
            removeFromArray(this._objects, obj);
            this._objects.splice(newIdx, 0, obj);
          } else {
            latestIndex = idx;
          }
        }
      }
      else {
        idx = this._objects.indexOf(object);
        if (idx !== this._objects.length - 1) {
          // if object is not on top of stack (last item in an array)
          newIdx = this._findNewUpperIndex(object, idx, intersecting);
          removeFromArray(this._objects, object);
          this._objects.splice(newIdx, 0, object);
        }
      }
      this.renderAll && this.renderAll();
      return this;
    };


var canvas = new fabric.Canvas('c', 
{
  preserveObjectStacking : true
});

var rect = new fabric.Rect({
  left: 10, top: 10,
  fill: 'red',
  width: 100, height: 100,
  hasControls: true
});

canvas.add(rect);

var rect2 = new fabric.Rect({
  left: 40, top: 40,
  fill: 'green',
  width: 100, height: 100,
  hasControls: true
});

canvas.add(rect2);

var rect3 = new fabric.Rect({
  left: 70, top: 70,
  fill: 'blue',
  width: 100, height: 100,
  hasControls: true
});

canvas.add(rect3);

var rect4 = new fabric.Rect({
  left: 100, top: 100,
  fill: 'orange',
  width: 100, height: 100,
  hasControls: true
});

canvas.add(rect4);

$("#bringForward").click(function()
{
 var items = canvas.getActiveObject() || canvas.getActiveGroup();

 if(items)
  items.bringForward();
});





No comments:

Post a Comment