Skip to content

Commit

Permalink
Use sendToBack, bringToFront, bringForward, sendBackwards for multipl…
Browse files Browse the repository at this point in the history
…e selections (#2908)

Use sendToBack, bringToFront, bringForward, sendBackwards for activeGroups.
Visually there is no effect if preserveObjectStacking is set to false.
  • Loading branch information
asturur committed Apr 28, 2016
1 parent c335cb5 commit 940db38
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 26 deletions.
120 changes: 94 additions & 26 deletions src/static_canvas.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -1347,47 +1347,97 @@
/* _TO_SVG_END_ */

/**
* Moves an object to the bottom of the stack of drawn objects
* Moves an object or the objects of a multiple selection
* to the bottom of the stack of drawn objects
* @param {fabric.Object} object Object to send to back
* @return {fabric.Canvas} thisArg
* @chainable
*/
sendToBack: function (object) {
removeFromArray(this._objects, object);
this._objects.unshift(object);
if (!object) {
return this;
}
var activeGroup = this.getActiveGroup ? this.getActiveGroup() : null,
i, obj, objs;
if (object === activeGroup) {
objs = activeGroup._objects;
for (i = objs.length; i--;) {
obj = objs[i];
removeFromArray(this._objects, obj);
this._objects.unshift(obj);
}
}
else {
removeFromArray(this._objects, object);
this._objects.unshift(object);
}
return this.renderAll && this.renderAll();
},

/**
* Moves an object to the top of the stack of drawn objects
* Moves an object or the objects of a multiple selection
* to the top of the stack of drawn objects
* @param {fabric.Object} object Object to send
* @return {fabric.Canvas} thisArg
* @chainable
*/
bringToFront: function (object) {
removeFromArray(this._objects, object);
this._objects.push(object);
if (!object) {
return this;
}
var activeGroup = this.getActiveGroup ? this.getActiveGroup() : null,
i, obj, objs;
if (object === activeGroup) {
objs = activeGroup._objects;
for (i = 0; i < objs.length; i++) {
obj = objs[i];
removeFromArray(this._objects, obj);
this._objects.push(obj);
}
}
else {
removeFromArray(this._objects, object);
this._objects.push(object);
}
return this.renderAll && this.renderAll();
},

/**
* Moves an object down in stack of drawn objects
* Moves an object or a selection down in stack of drawn objects
* @param {fabric.Object} object Object to send
* @param {Boolean} [intersecting] If `true`, send object behind next lower intersecting object
* @return {fabric.Canvas} thisArg
* @chainable
*/
sendBackwards: function (object, intersecting) {
var idx = this._objects.indexOf(object);

// if object is not on the bottom of stack
if (idx !== 0) {
var newIdx = this._findNewLowerIndex(object, idx, intersecting);

removeFromArray(this._objects, object);
this._objects.splice(newIdx, 0, object);
this.renderAll && this.renderAll();
if (!object) {
return this;
}
var activeGroup = this.getActiveGroup ? this.getActiveGroup() : null,
i, obj, idx, newIdx, objs;

if (object === activeGroup) {
objs = activeGroup._objects;
for (i = 0; i < objs.length; i++) {
obj = objs[i];
idx = this._objects.indexOf(obj);
if (idx !== 0) {
newIdx = idx - 1;
removeFromArray(this._objects, obj);
this._objects.splice(newIdx, 0, obj);
}
}
}
else {
idx = this._objects.indexOf(object);
if (idx !== 0) {
// if object is not on the bottom of stack
newIdx = this._findNewLowerIndex(object, idx, intersecting);
removeFromArray(this._objects, object);
this._objects.splice(newIdx, 0, object);
}
}
this.renderAll && this.renderAll();
return this;
},

Expand Down Expand Up @@ -1421,23 +1471,41 @@
},

/**
* Moves an object up in stack of drawn objects
* Moves an object or a selection up in stack of drawn objects
* @param {fabric.Object} object Object to send
* @param {Boolean} [intersecting] If `true`, send object in front of next upper intersecting object
* @return {fabric.Canvas} thisArg
* @chainable
*/
bringForward: function (object, intersecting) {
var idx = this._objects.indexOf(object);

// if object is not on top of stack (last item in an array)
if (idx !== this._objects.length - 1) {
var newIdx = this._findNewUpperIndex(object, idx, intersecting);

removeFromArray(this._objects, object);
this._objects.splice(newIdx, 0, object);
this.renderAll && this.renderAll();
if (!object) {
return this;
}
var activeGroup = this.getActiveGroup ? this.getActiveGroup() : null,
i, obj, idx, newIdx, objs;

if (object === activeGroup) {
objs = activeGroup._objects;
for (i = objs.length; i--;) {
obj = objs[i];
idx = this._objects.indexOf(obj);
if (idx !== this._objects.length - 1) {
newIdx = idx + 1;
removeFromArray(this._objects, obj);
this._objects.splice(newIdx, 0, obj);
}
}
}
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;
},

Expand Down
78 changes: 78 additions & 0 deletions test/unit/canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,84 @@
//TODO: make it work with perPixelTargetFind
});

test('activeGroup sendToBack', function() {

var rect1 = makeRect(),
rect2 = makeRect(),
rect3 = makeRect(),
rect4 = makeRect();

canvas.add(rect1, rect2, rect3, rect4);

var group = new fabric.Group([ rect3, rect4 ]);
canvas.setActiveGroup(group);
equal(canvas._objects[0], rect1, 'rect1 should be last');
equal(canvas._objects[1], rect2, 'rect2 should be second');
canvas.sendToBack(group);
equal(canvas._objects[0], rect3, 'rect3 should be the new last');
equal(canvas._objects[1], rect4, 'rect3 should be the new second');
equal(canvas._objects[2], rect1, 'rect1 should be the third object');
equal(canvas._objects[3], rect2, 'rect2 should be on top now');
});

test('activeGroup bringToFront', function() {

var rect1 = makeRect(),
rect2 = makeRect(),
rect3 = makeRect(),
rect4 = makeRect();

canvas.add(rect1, rect2, rect3, rect4);

var group = new fabric.Group([ rect1, rect2 ]);
canvas.setActiveGroup(group);
equal(canvas._objects[0], rect1, 'rect1 should be last');
equal(canvas._objects[1], rect2, 'rect2 should be second');
canvas.bringToFront(group);
equal(canvas._objects[0], rect3, 'rect3 should be the new last');
equal(canvas._objects[1], rect4, 'rect3 should be the new second');
equal(canvas._objects[2], rect1, 'rect1 should be the third object');
equal(canvas._objects[3], rect2, 'rect2 should be on top now');
});

test('activeGroup bringForward', function() {

var rect1 = makeRect(),
rect2 = makeRect(),
rect3 = makeRect(),
rect4 = makeRect();

canvas.add(rect1, rect2, rect3, rect4);

var group = new fabric.Group([ rect1, rect2 ]);
canvas.setActiveGroup(group);
equal(canvas._objects[0], rect1, 'rect1 should be last');
equal(canvas._objects[1], rect2, 'rect2 should be second');
canvas.bringForward(group);
equal(canvas._objects[0], rect3, 'rect3 should be the new last');
equal(canvas._objects[1], rect1, 'rect1 should be the new second');
equal(canvas._objects[2], rect2, 'rect2 should be the third object');
equal(canvas._objects[3], rect4, 'rect4 did not move');
});

test('activeGroup sendBackwards', function() {
var rect1 = makeRect(),
rect2 = makeRect(),
rect3 = makeRect(),
rect4 = makeRect();

canvas.add(rect1, rect2, rect3, rect4);

var group = new fabric.Group([ rect3, rect4 ]);
canvas.setActiveGroup(group);
equal(canvas._objects[0], rect1, 'rect1 should be last');
equal(canvas._objects[1], rect2, 'rect2 should be second');
canvas.sendBackwards(group);
equal(canvas._objects[0], rect1, 'rect1 is still last');
equal(canvas._objects[1], rect3, 'rect3 should be shifted down by 1');
equal(canvas._objects[2], rect4, 'rect4 should be shifted down by 1');
equal(canvas._objects[3], rect2, 'rect2 is the new top');
});

test('toDataURL', function() {
ok(typeof canvas.toDataURL == 'function');
Expand Down

0 comments on commit 940db38

Please sign in to comment.