diff --git a/src/mixins/canvas_events.mixin.js b/src/mixins/canvas_events.mixin.js index 466ea6e1..3896bf32 100644 --- a/src/mixins/canvas_events.mixin.js +++ b/src/mixins/canvas_events.mixin.js @@ -1,4 +1,4 @@ -(function() { +(function(){ var cursorOffset = { mt: 0, // n @@ -54,6 +54,7 @@ Event.add(this.upperCanvasEl, 'drag', this._onDrag); Event.add(this.upperCanvasEl, 'orientation', this._onOrientationChange); Event.add(this.upperCanvasEl, 'shake', this._onShake); + Event.add(this.upperCanvasEl, 'longpress', this._onLongPress); } }, @@ -68,6 +69,7 @@ this._onGesture = this._onGesture.bind(this); this._onDrag = this._onDrag.bind(this); this._onShake = this._onShake.bind(this); + this._onLongPress = this._onLongPress.bind(this); this._onOrientationChange = this._onOrientationChange.bind(this); this._onMouseWheel = this._onMouseWheel.bind(this); }, @@ -90,6 +92,7 @@ Event.remove(this.upperCanvasEl, 'drag', this._onDrag); Event.remove(this.upperCanvasEl, 'orientation', this._onOrientationChange); Event.remove(this.upperCanvasEl, 'shake', this._onShake); + Event.remove(this.upperCanvasEl, 'longpress', this._onLongPress); } }, @@ -125,8 +128,8 @@ * @param {Event} [e] Event object fired on Event.js orientation change * @param {Event} [self] Inner Event object */ - _onOrientationChange: function(e, self) { - this.__onOrientationChange && this.__onOrientationChange(e, self); + _onOrientationChange: function(e,self) { + this.__onOrientationChange && this.__onOrientationChange(e,self); }, /** @@ -135,7 +138,16 @@ * @param {Event} [self] Inner Event object */ _onShake: function(e, self) { - this.__onShake && this.__onShake(e, self); + this.__onShake && this.__onShake(e,self); + }, + + /** + * @private + * @param {Event} [e] Event object fired on Event.js shake + * @param {Event} [self] Inner Event object + */ + _onLongPress: function(e, self) { + this.__onLongPress && this.__onLongPress(e,self); }, /** @@ -516,6 +528,10 @@ this._onMouseMoveInDrawingMode(e); return; } + + if (typeof e.touches !== 'undefined' && e.touches.length > 1) { + return; + } var groupSelector = this._groupSelector; diff --git a/src/mixins/canvas_gestures.mixin.js b/src/mixins/canvas_gestures.mixin.js index ea56e733..408549ed 100644 --- a/src/mixins/canvas_gestures.mixin.js +++ b/src/mixins/canvas_gestures.mixin.js @@ -1,16 +1,24 @@ +/** + * Adds support for multi-touch gestures using the Event.js library. + * Fires the following custom events: + * - touch:gesture + * - touch:drag + * - touch:orientation + * - touch:shake + * - touch:longpress + */ (function() { var degreesToRadians = fabric.util.degreesToRadians, - radiansToDegrees = fabric.util.radiansToDegrees; + radiansToDegrees = fabric.util.radiansToDegrees; fabric.util.object.extend(fabric.Canvas.prototype, /** @lends fabric.Canvas.prototype */ { - /** * Method that defines actions when an Event.js gesture is detected on an object. Currently only supports * 2 finger gestures. * - * @param {Event} e Event object by Event.js - * @param {Event} self Event proxy object by Event.js + * @param e Event object by Event.js + * @param self Event proxy object by Event.js */ __onTransformGesture: function(e, self) { @@ -20,63 +28,99 @@ var target = this.findTarget(e); if ('undefined' !== typeof target) { - this.onBeforeScaleRotate(target); - this._rotateObjectByAngle(self.rotation); - this._scaleObjectBy(self.scale); + this.__gesturesParams = { + 'e': e, + 'self': self, + 'target': target + }; + + this.__gesturesRenderer(); } - this.fire('touch:gesture', { target: target, e: e, self: self }); + this.fire('touch:gesture', {target: target, e: e, self: self}); }, + __gesturesParams: null, + __gesturesRenderer: function() { + if (this.__gesturesParams === null || this._currentTransform === null) { + return; + } + + var self = this.__gesturesParams.self; + + var t = this._currentTransform; + t.action = 'scale'; + t.originX = t.originY = 'center'; + this._setOriginToCenter(t.target); + + this._scaleObjectBy(self.scale); + + if (self.rotation !== 0) { + t.action = 'rotate'; + this._rotateObjectByAngle(self.rotation); + } + + this.renderAll(); + t.action = 'drag'; + }, /** * Method that defines actions when an Event.js drag is detected. * - * @param {Event} e Event object by Event.js - * @param {Event} self Event proxy object by Event.js + * @param e Event object by Event.js + * @param self Event proxy object by Event.js */ __onDrag: function(e, self) { - this.fire('touch:drag', { e: e, self: self }); + this.fire('touch:drag', {e: e, self: self}); }, - /** * Method that defines actions when an Event.js orientation event is detected. * - * @param {Event} e Event object by Event.js - * @param {Event} self Event proxy object by Event.js + * @param e Event object by Event.js + * @param self Event proxy object by Event.js */ __onOrientationChange: function(e, self) { - this.fire('touch:orientation', { e: e, self: self }); + this.fire('touch:orientation', {e: e, self: self}); }, - /** * Method that defines actions when an Event.js shake event is detected. * - * @param {Event} e Event object by Event.js - * @param {Event} self Event proxy object by Event.js + * @param e Event object by Event.js + * @param self Event proxy object by Event.js */ __onShake: function(e, self) { - this.fire('touch:shake', { e: e, self: self }); + this.fire('touch:shake', {e: e, self: self}); + }, + /** + * Method that defines actions when an Event.js longpress event is detected. + * + * @param e Event object by Event.js + * @param self Event proxy object by Event.js + */ + __onLongPress: function(e, self) { + this.fire('touch:longpress', {e: e, self: self}); }, - /** * Scales an object by a factor - * @param {Number} s The scale factor to apply to the current scale level - * @param {String} by Either 'x' or 'y' - specifies dimension constraint by which to scale an object. + * @param s {Number} The scale factor to apply to the current scale level + * @param by {String} Either 'x' or 'y' - specifies dimension constraint by which to scale an object. * When not provided, an object is scaled by both dimensions equally */ _scaleObjectBy: function(s, by) { var t = this._currentTransform, - target = t.target, - lockScalingX = target.get('lockScalingX'), - lockScalingY = target.get('lockScalingY'); + target = t.target, + lockScalingX = target.get('lockScalingX'), + lockScalingY = target.get('lockScalingY'); - if (lockScalingX && lockScalingY) { + if (lockScalingX && lockScalingY) return; - } target._scaling = true; + var constraintPosition = target.translateToOriginPoint(target.getCenterPoint(), t.originX, t.originY); + if (!by) { + t.newScaleX = t.scaleX * s; + t.newScaleY = t.scaleY * s; if (!lockScalingX) { target.set('scaleX', t.scaleX * s); } @@ -84,25 +128,19 @@ target.set('scaleY', t.scaleY * s); } } - else if (by === 'x' && !target.get('lockUniScaling')) { - lockScalingX || target.set('scaleX', t.scaleX * s); - } - else if (by === 'y' && !target.get('lockUniScaling')) { - lockScalingY || target.set('scaleY', t.scaleY * s); - } - }, + target.setPositionByOrigin(constraintPosition, t.originX, t.originY); + }, /** * Rotates object by an angle - * @param {Number} curAngle The angle of rotation in degrees + * @param curAngle {Number} the angle of rotation in degrees */ _rotateObjectByAngle: function(curAngle) { var t = this._currentTransform; - if (t.target.get('lockRotation')) { + if (t.target.get('lockRotation')) return; - } t.target.angle = radiansToDegrees(degreesToRadians(curAngle) + t.theta); } }); -})(); +})(); \ No newline at end of file