diff --git a/src/static_canvas.class.js b/src/static_canvas.class.js index 41dc20d0495..7970959259d 100644 --- a/src/static_canvas.class.js +++ b/src/static_canvas.class.js @@ -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; }, @@ -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; }, diff --git a/test/unit/canvas.js b/test/unit/canvas.js index dc83ce5365f..c2d5f4cac45 100644 --- a/test/unit/canvas.js +++ b/test/unit/canvas.js @@ -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');