Skip to content

Commit

Permalink
Allow a not stateful canvas to fire object:modified at end of transfo…
Browse files Browse the repository at this point in the history
…rm. (#2890)

stateful false can fire events now
Also events fire just when the object is really rotated, scaled, skewed or dragged.
  • Loading branch information
asturur committed Apr 13, 2016
1 parent de4826f commit 37b2099
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 52 deletions.
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

0 comments on commit 37b2099

Please sign in to comment.