2

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();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.6/fabric.min.js"></script>
<button id="bringForward">Bring Forward</button>

<canvas id="c" width="640" height="480"></canvas>
Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
  • You're going to have to work it out for yourself (i.e. which individual ones are selected and which aren't, and then move them keeping track of the selected ones order). – Tim Harker Feb 17 '17 at 03:27
  • I'm happy to mock something up if you'd like... you'll need to start here, `canvas.on('object:selected', onObjectSelected);`, by creating a selected event so you know the selected objects... then bring forward, `canvas.bringForward(canvasSelectedItem, true);` send backward... etc. – Tim Harker Feb 17 '17 at 03:42
  • @TimHarker This is more an illustration of a bug to the developers. I've also posted this question on their git page with a link to this question. Happy for you to attempt to answer the question though! – Lee Taylor Feb 17 '17 at 03:46
  • Sure. They have a ton... unfortunately. But they also have a ton of great code that I've managed to work with. I'm putting this website together, [http://xpressclocks.azurewebsites.net/create](http://xpressclocks.azurewebsites.net/create). If you add multiple shapes and/or text and then right click you'll see a context menu for bring forward etc. Haven't implemented multiple select due to its complexities. I'll try to mock something up in the next day or two... – Tim Harker Feb 17 '17 at 03:51
  • @TimHarker Yes, I'm working my way through a sandbox as we speak. Finding bugs as I go. Your site is coming together nicely. I did spot an odd bug when you have multiple text items and you then undo. It sometimes gives you 2 text items that are identical. Not sure if you're aware... – Lee Taylor Feb 17 '17 at 04:01
  • Thanks. Yep. Undo needs work... I'm aware... Just need to get it live and try to make some money first though, been going at it a while (in the evenings). I noticed some of your other fabricjs stackoverflow posts along the same lines. – Tim Harker Feb 17 '17 at 04:06
  • 1
    I've implemented an undo/redo facility using https://github.com/benjamine/jsondiffpatch Takes a lot of the pain out of it! Happy to give you a heads up if you like. – Lee Taylor Feb 17 '17 at 04:08
  • 1
    I took a quick look... interesting!!! Mine come from here, [http://stackoverflow.com/questions/19043219/undo-redo-feature-in-fabric-js](http://stackoverflow.com/questions/19043219/undo-redo-feature-in-fabric-js). – Tim Harker Feb 17 '17 at 04:21
  • I mean, having 2 objects both on top of canvas, select them and ask to send them on top is weird. I guess is an unwanted behaviour, simply you should not do the action if the objects are the topmost. – AndreaBogazzi Feb 17 '17 at 19:57
  • @AndreaBogazzi But the trick is to know whether you have a selection that will cause this problem... – Lee Taylor Feb 18 '17 at 20:23

1 Answers1

5

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();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.6/fabric.min.js"></script>
<button id="bringForward">Bring Forward</button>

<canvas id="c" width="640" height="480"></canvas>
AndreaBogazzi
  • 14,323
  • 3
  • 38
  • 63