Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use sendToBack, bringToFront for multiple selections #2908

Merged
merged 15 commits into from
Apr 28, 2016
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