diff --git a/src/canvas.class.js b/src/canvas.class.js index 33bec8a8..322d2111 100644 --- a/src/canvas.class.js +++ b/src/canvas.class.js @@ -118,13 +118,23 @@ /** * Indicates which key enable multiple click selection - * values: altKey, shiftKey, ctrlKey + * values: altKey, shiftKey, ctrlKey, cmdKey * @since 1.6.2 * @type String * @default */ selectionKey: 'shiftKey', + /** + * Indicates which key enable alternative selection + * in case of target overlapping with active object + * values: altKey, shiftKey, ctrlKey, cmdKey + * @since 1.6.5 + * @type null|String + * @default + */ + altSelectionKey: null, + /** * Color of selection * @type String @@ -398,7 +408,6 @@ vptPointer = this.restorePointerVpt(pointer), p = fabric.util.transformPoint(vptPointer, invertedM); return fabric.util.transformPoint(p, vpt); - //return { x: p.x * vpt[0], y: p.y * vpt[3] }; }, /** @@ -1006,7 +1015,8 @@ var ignoreZoom = true, pointer = this.getPointer(e, ignoreZoom), activeGroup = this.getActiveGroup(), - activeObject = this.getActiveObject(); + activeObject = this.getActiveObject(), + activeTarget; // first check current group (if one exists) // active group does not check sub targets like normal groups. @@ -1014,14 +1024,25 @@ if (activeGroup && !skipGroup && this._checkTarget(pointer, activeGroup)) { return activeGroup; } - - if (activeObject && this._checkTarget(pointer, activeObject)) { + // if we hit the corner of an activeObject, let's return that. + if (activeObject && activeObject._findTargetCorner(pointer)) { return activeObject; } + if (activeObject && this._checkTarget(pointer, activeObject)) { + if (!this.preserveObjectStacking) { + return activeObject; + } + else { + activeTarget = activeObject; + } + } this.targets = []; var target = this._searchPossibleTargets(this._objects, pointer); + if (e[this.altSelectionKey] && target && activeTarget && target !== activeTarget) { + target = activeTarget; + } this._fireOverOutEvents(target, e); return target; }, diff --git a/src/mixins/object_geometry.mixin.js b/src/mixins/object_geometry.mixin.js index 8e194349..2f0a757b 100644 --- a/src/mixins/object_geometry.mixin.js +++ b/src/mixins/object_geometry.mixin.js @@ -355,6 +355,10 @@ return this; }, + /* + * calculate rotation matrix of an object + * @return {Array} rotation matrix for the object + */ _calcRotateMatrix: function() { if (this.angle) { var theta = degreesToRadians(this.angle), cos = Math.cos(theta), sin = Math.sin(theta); diff --git a/test/unit/canvas.js b/test/unit/canvas.js index ce3cdd92..f4aeb514 100644 --- a/test/unit/canvas.js +++ b/test/unit/canvas.js @@ -346,17 +346,23 @@ test('findTarget preserveObjectStacking true', function() { ok(typeof canvas.findTarget == 'function'); canvas.preserveObjectStacking = true; - var rect = makeRect({ left: 0, top: 0 }), - rectOver = makeRect({ left: 0, top: 0 }), + var rect = makeRect({ left: 0, top: 0, width: 30, height: 30 }), + rectOver = makeRect({ left: 0, top: 0, width: 30, height: 30 }), target, - pointer = { clientX: 5, clientY: 5 }; + pointer = { clientX: 15, clientY: 15, 'shiftKey': true }, + pointer2 = { clientX: 4, clientY: 4 }; canvas.add(rect); canvas.add(rectOver); target = canvas.findTarget(pointer); equal(target, rectOver, 'Should return the rectOver, rect is not considered'); canvas.setActiveObject(rect); target = canvas.findTarget(pointer); - equal(target, rect, 'Should return the rect, because it is active'); + equal(target, rectOver, 'Should still return rectOver because is above active object'); + target = canvas.findTarget(pointer2); + equal(target, rect, 'Should rect because a corner of the activeObject has been hit'); + canvas.altSelectionKey = 'shiftKey'; + target = canvas.findTarget(pointer); + equal(target, rect, 'Should rect because active and altSelectionKey is pressed'); canvas.preserveObjectStacking = false; });