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

Allow a not stateful canvas to fire object:modified at end of transform. #2890

Merged
merged 10 commits into from Apr 13, 2016
84 changes: 54 additions & 30 deletions src/canvas.class.js
Expand Up @@ -479,16 +479,19 @@
* @private
* @param {Number} x pointer's x coordinate
* @param {Number} y pointer's y coordinate
* @return {Boolean} true if the translation occurred
*/
_translateObject: function (x, y) {
var target = this._currentTransform.target;

if (!target.get('lockMovementX')) {
target.set('left', x - this._currentTransform.offsetX);
}
if (!target.get('lockMovementY')) {
target.set('top', y - this._currentTransform.offsetY);
}
var transform = this._currentTransform,
target = transform.target,
newLeft = x - transform.offsetX,
newTop = y - transform.offsetY,
moveX = !target.get('lockMovementX') && target.left !== newLeft,
moveY = !target.get('lockMovementY') && target.top !== newTop;

moveX && target.set('left', newLeft);
moveY && target.set('top', newTop);
return moveX || moveY;
},

/**
Expand Down Expand Up @@ -532,15 +535,16 @@
* @param {Number} x pointer's x coordinate
* @param {Number} y pointer's y coordinate
* @param {String} by Either 'x' or 'y'
* @return {Boolean} true if the skewing occurred
*/
_skewObject: function (x, y, by) {
var t = this._currentTransform,
target = t.target,
target = t.target, skewed = false,
lockSkewingX = target.get('lockSkewingX'),
lockSkewingY = target.get('lockSkewingY');

if ((lockSkewingX && by === 'x') || (lockSkewingY && by === 'y')) {
return;
return false;
}

// Get the constraint point
Expand All @@ -554,15 +558,21 @@

constraintPosition = target.translateToOriginPoint(center, t.originX, t.originY);
// Actually skew the object
this._setObjectSkew(actualMouseByOrigin, t, by, dim);
skewed = this._setObjectSkew(actualMouseByOrigin, t, by, dim);
t.lastX = x;
t.lastY = y;
// Make sure the constraints apply
target.setPositionByOrigin(constraintPosition, t.originX, t.originY);
return skewed;
},

/**
* Set object skew
* @private
* @return {Boolean} true if the skewing occurred
*/
_setObjectSkew: function(localMouse, transform, by, _dim) {
var target = transform.target, newValue,
var target = transform.target, newValue, skewed = false,
skewSign = transform.skewSign, newDim, dimNoSkew,
otherBy, _otherBy, _by, newDimMouse, skewX, skewY;

Expand Down Expand Up @@ -591,12 +601,14 @@
(dimNoSkew[otherBy] / target['scale' + _otherBy]));
newValue = fabric.util.radiansToDegrees(newValue);
}
skewed = target['skew' + _by] !== newValue;
target.set('skew' + _by, newValue);
if (target['skew' + _otherBy] !== 0) {
newDim = target._getTransformedDimensions();
newValue = (_dim[otherBy] / newDim[otherBy]) * target['scale' + _otherBy];
target.set('scale' + _otherBy, newValue);
}
return skewed;
},

/**
Expand All @@ -606,6 +618,7 @@
* @param {Number} y pointer's y coordinate
* @param {String} by Either 'x' or 'y' - specifies dimension constraint by which to scale an object.
* When not provided, an object is scaled by both dimensions equally
* @return {Boolean} true if the scaling occurred
*/
_scaleObject: function (x, y, by) {
var t = this._currentTransform,
Expand All @@ -615,74 +628,83 @@
lockScalingFlip = target.get('lockScalingFlip');

if (lockScalingX && lockScalingY) {
return;
return false;
}

// Get the constraint point
var constraintPosition = target.translateToOriginPoint(target.getCenterPoint(), t.originX, t.originY),
localMouse = target.toLocalPoint(new fabric.Point(x, y), t.originX, t.originY),
dim = target._getTransformedDimensions();
dim = target._getTransformedDimensions(), scaled = false;

this._setLocalMouse(localMouse, t);

// Actually scale the object
this._setObjectScale(localMouse, t, lockScalingX, lockScalingY, by, lockScalingFlip, dim);
scaled = this._setObjectScale(localMouse, t, lockScalingX, lockScalingY, by, lockScalingFlip, dim);

// Make sure the constraints apply
target.setPositionByOrigin(constraintPosition, t.originX, t.originY);
return scaled;
},

/**
* @private
* @return {Boolean} true if the scaling occurred
*/
_setObjectScale: function(localMouse, transform, lockScalingX, lockScalingY, by, lockScalingFlip, _dim) {
var target = transform.target, forbidScalingX = false, forbidScalingY = false;
var target = transform.target, forbidScalingX = false, forbidScalingY = false, scaled = false,
changeX, changeY, scaleX, scaleY;

transform.newScaleX = localMouse.x * target.scaleX / _dim.x;
transform.newScaleY = localMouse.y * target.scaleY / _dim.y;
scaleX = localMouse.x * target.scaleX / _dim.x;
scaleY = localMouse.y * target.scaleY / _dim.y;
changeX = target.scaleX !== scaleX;
changeY = target.scaleY !== scaleY;

if (lockScalingFlip && transform.newScaleX <= 0 && transform.newScaleX < target.scaleX) {
if (lockScalingFlip && scaleX <= 0 && scaleX < target.scaleX) {
forbidScalingX = true;
}

if (lockScalingFlip && transform.newScaleY <= 0 && transform.newScaleY < target.scaleY) {
if (lockScalingFlip && scaleY <= 0 && scaleY < target.scaleY) {
forbidScalingY = true;
}

if (by === 'equally' && !lockScalingX && !lockScalingY) {
forbidScalingX || forbidScalingY || this._scaleObjectEqually(localMouse, target, transform, _dim);
forbidScalingX || forbidScalingY || (scaled = this._scaleObjectEqually(localMouse, target, transform, _dim));
}
else if (!by) {
forbidScalingX || lockScalingX || target.set('scaleX', transform.newScaleX);
forbidScalingY || lockScalingY || target.set('scaleY', transform.newScaleY);
forbidScalingX || lockScalingX || (target.set('scaleX', scaleX) && (scaled = scaled || changeX));
forbidScalingY || lockScalingY || (target.set('scaleY', scaleY) && (scaled = scaled || changeY));
}
else if (by === 'x' && !target.get('lockUniScaling')) {
forbidScalingX || lockScalingX || target.set('scaleX', transform.newScaleX);
forbidScalingX || lockScalingX || (target.set('scaleX', scaleX) && (scaled = scaled || changeX));
}
else if (by === 'y' && !target.get('lockUniScaling')) {
forbidScalingY || lockScalingY || target.set('scaleY', transform.newScaleY);
forbidScalingY || lockScalingY || (target.set('scaleY', scaleY) && (scaled = scaled || changeY));
}

transform.newScaleX = scaleX;
transform.newScaleY = scaleY;
forbidScalingX || forbidScalingY || this._flipObject(transform, by);

return scaled;
},

/**
* @private
* @return {Boolean} true if the scaling occurred
*/
_scaleObjectEqually: function(localMouse, target, transform, _dim) {

var dist = localMouse.y + localMouse.x,
lastDist = _dim.y * transform.original.scaleY / target.scaleY +
_dim.x * transform.original.scaleX / target.scaleX;
_dim.x * transform.original.scaleX / target.scaleX,
scaled;

// We use transform.scaleX/Y instead of target.scaleX/Y
// because the object may have a min scale and we'll loose the proportions
transform.newScaleX = transform.original.scaleX * dist / lastDist;
transform.newScaleY = transform.original.scaleY * dist / lastDist;

scaled = transform.newScaleX !== target.scaleX || transform.newScaleY !== target.scaleY;
target.set('scaleX', transform.newScaleX);
target.set('scaleY', transform.newScaleY);
return scaled;
},

/**
Expand Down Expand Up @@ -767,13 +789,14 @@
* @private
* @param {Number} x pointer's x coordinate
* @param {Number} y pointer's y coordinate
* @return {Boolean} true if the rotation occurred
*/
_rotateObject: function (x, y) {

var t = this._currentTransform;

if (t.target.get('lockRotation')) {
return;
return false;
}

var lastAngle = atan2(t.ey - t.top, t.ex - t.left),
Expand All @@ -786,6 +809,7 @@
}

t.target.angle = angle % 360;
return true;
},

/**
Expand Down
37 changes: 16 additions & 21 deletions src/mixins/canvas_events.mixin.js
Expand Up @@ -303,14 +303,12 @@
}

target.setCoords();
this._restoreOriginXY(target);

// only fire :modified event if target coordinates were changed during mousedown-mouseup
if (this.stateful && target.hasStateChanged()) {
if (transform.actionPerformed || (this.stateful && target.hasStateChanged())) {
this.fire('object:modified', { target: target });
target.fire('modified');
}

this._restoreOriginXY(target);
},

/**
Expand Down Expand Up @@ -568,6 +566,7 @@
}
}
else {

this._transformObject(e);
}

Expand Down Expand Up @@ -599,37 +598,32 @@
var x = pointer.x,
y = pointer.y,
target = transform.target,
action = transform.action;
action = transform.action,
actionPerformed = false;

if (action === 'rotate') {
this._rotateObject(x, y);
this._fire('rotating', target, e);
(actionPerformed = this._rotateObject(x, y)) && this._fire('rotating', target, e);
}
else if (action === 'scale') {
this._onScale(e, transform, x, y);
this._fire('scaling', target, e);
(actionPerformed = this._onScale(e, transform, x, y)) && this._fire('scaling', target, e);
}
else if (action === 'scaleX') {
this._scaleObject(x, y, 'x');
this._fire('scaling', target, e);
(actionPerformed = this._scaleObject(x, y, 'x')) && this._fire('scaling', target, e);
}
else if (action === 'scaleY') {
this._scaleObject(x, y, 'y');
this._fire('scaling', target, e);
(actionPerformed = this._scaleObject(x, y, 'y')) && this._fire('scaling', target, e);
}
else if (action === 'skewX') {
this._skewObject(x, y, 'x');
this._fire('skewing', target, e);
(actionPerformed = this._skewObject(x, y, 'x')) && this._fire('skewing', target, e);
}
else if (action === 'skewY') {
this._skewObject(x, y, 'y');
this._fire('skewing', target, e);
(actionPerformed = this._skewObject(x, y, 'y')) && this._fire('skewing', target, e);
}
else {
this._translateObject(x, y);
this._fire('moving', target, e);
(actionPerformed = this._translateObject(x, y)) && this._fire('moving', target, e);
this.setCursor(this.moveCursor);
}
transform.actionPerformed = actionPerformed;
},

/**
Expand Down Expand Up @@ -660,13 +654,14 @@

/**
* @private
* @return {Boolean} true if the scaling occurred
*/
_onScale: function(e, transform, x, y) {
// rotate object only if shift key is not pressed
// and if it is not a group we are transforming
if ((e.shiftKey || this.uniScaleTransform) && !transform.target.get('lockUniScaling')) {
transform.currentAction = 'scale';
this._scaleObject(x, y);
return this._scaleObject(x, y);
}
else {
// Switch from a normal resize to proportional
Expand All @@ -675,7 +670,7 @@
}

transform.currentAction = 'scaleEqually';
this._scaleObject(x, y, 'equally');
return this._scaleObject(x, y, 'equally');
}
},

Expand Down
3 changes: 2 additions & 1 deletion src/mixins/textbox_behavior.mixin.js
Expand Up @@ -14,10 +14,11 @@
var w = t.width * ((localMouse.x / transform.scaleX) / (t.width + t.strokeWidth));
if (w >= t.getMinWidth()) {
t.set('width', w);
return true;
}
}
else {
setObjectScaleOverridden.call(fabric.Canvas.prototype, localMouse, transform,
return setObjectScaleOverridden.call(fabric.Canvas.prototype, localMouse, transform,
lockScalingX, lockScalingY, by, lockScalingFlip, _dim);
}
};
Expand Down