diff --git a/dist/all.js b/dist/all.js index 539374cd..22c182c4 100644 --- a/dist/all.js +++ b/dist/all.js @@ -3574,10 +3574,6 @@ fabric.util.animate = animate; this.setOverlayImage(options.overlayImage); } - if (options.afterRender) { - this.afterRender = options.afterRender; - } - this._createCanvasBackground(); this._createCanvasContainer(); this._initEvents(); @@ -3671,19 +3667,6 @@ fabric.util.animate = animate; /* NOOP */ }, - /** - * Callback; invoked every time active object is moved - * @method onObjectMove - * @param {fabric.Object} object that's being moved - */ - onObjectMove: null, - - /** - * Callback; invoked when a mouseup event occurs, and at the end of all other transformations - * @method onMouseUp - */ - onMouseUp: null, - /** * Calculates canvas element offset relative to the document * This method is also attached as "resize" event handler of window @@ -4019,9 +4002,7 @@ fabric.util.animate = animate; _this._setCursorFromEvent(e, target); }, 50); - if (this.onMouseUp) { - this.onMouseUp(); - } + fireEvent('mouse:up'); }, _shouldClearSelection: function (e) { @@ -4349,9 +4330,10 @@ fabric.util.animate = animate; } else { this._translateObject(x, y); - if (this.onObjectMove) { - this.onObjectMove(this._currentTransform.target); - } + + fireEvent('object:moved', { + target: this._currentTransform.target + }); } this.renderAll(); } @@ -4659,9 +4641,7 @@ fabric.util.animate = animate; var elapsedTime = new Date() - startTime; this.onFpsUpdate(~~(1000 / elapsedTime)); - if (this.afterRender) { - this.afterRender(); - } + fireEvent('after:render'); return this; }, @@ -4689,9 +4669,7 @@ fabric.util.animate = animate; activeGroup.render(this.contextTop); } - if (this.afterRender) { - this.afterRender(); - } + fireEvent('after:render'); return this; }, diff --git a/src/element.class.js b/src/element.class.js index ab2c4564..c4f6e07b 100644 --- a/src/element.class.js +++ b/src/element.class.js @@ -126,10 +126,6 @@ this.setOverlayImage(options.overlayImage); } - if (options.afterRender) { - this.afterRender = options.afterRender; - } - this._createCanvasBackground(); this._createCanvasContainer(); this._initEvents(); @@ -223,19 +219,6 @@ /* NOOP */ }, - /** - * Callback; invoked every time active object is moved - * @method onObjectMove - * @param {fabric.Object} object that's being moved - */ - onObjectMove: null, - - /** - * Callback; invoked when a mouseup event occurs, and at the end of all other transformations - * @method onMouseUp - */ - onMouseUp: null, - /** * Calculates canvas element offset relative to the document * This method is also attached as "resize" event handler of window @@ -579,9 +562,7 @@ _this._setCursorFromEvent(e, target); }, 50); - if (this.onMouseUp) { - this.onMouseUp(); - } + fireEvent('mouse:up'); }, _shouldClearSelection: function (e) { @@ -935,9 +916,10 @@ } else { this._translateObject(x, y); - if (this.onObjectMove) { - this.onObjectMove(this._currentTransform.target); - } + + fireEvent('object:moved', { + target: this._currentTransform.target + }); } // only commit here. when we are actually moving the pictures this.renderAll(); @@ -1253,9 +1235,7 @@ var elapsedTime = new Date() - startTime; this.onFpsUpdate(~~(1000 / elapsedTime)); - if (this.afterRender) { - this.afterRender(); - } + fireEvent('after:render'); return this; }, @@ -1286,9 +1266,7 @@ activeGroup.render(this.contextTop); } - if (this.afterRender) { - this.afterRender(); - } + fireEvent('after:render'); return this; }, diff --git a/test/demo/aligning_guidelines.js b/test/demo/aligning_guidelines.js index 27a9c471..1f03b4e9 100644 --- a/test/demo/aligning_guidelines.js +++ b/test/demo/aligning_guidelines.js @@ -1,3 +1,8 @@ +/** + * Should objects by aligned by a bounding box? + * [Bug] Scaled objects sometimes can not be aligned by edges + * + */ function initAligningGuidelines(canvas) { var ctx = canvas.getContext(), @@ -35,6 +40,8 @@ function initAligningGuidelines(canvas) { } function isInRange(value1, value2) { + value1 = Math.round(value1); + value2 = Math.round(value2); for (var i = value1 - aligningLineMargin, len = value1 + aligningLineMargin; i <= len; i++) { if (i === value2) { return true; @@ -43,15 +50,21 @@ function initAligningGuidelines(canvas) { return false; } - canvas.onObjectMove = function(activeObject) { + var verticalLines = [ ], + horizontalLines = [ ]; + + fabric.util.observeEvent('object:moved', function(e) { - var canvasObjects = canvas.getObjects(), + var activeObject = e.memo.target, + canvasObjects = canvas.getObjects(), activeObjectLeft = activeObject.get('left'), activeObjectTop = activeObject.get('top'), - activeObjectHeight = activeObject.get('height'), - activeObjectWidth = activeObject.get('width'), - verticalLines = [ ], - horizontalLines = [ ]; + activeObjectHeight = activeObject.getHeight(), + activeObjectWidth = activeObject.getWidth(), + noneInTheRange = true; + + // It should be trivial to DRY this up by encapsulating (repeating) creation of x1, x2, y1, and y2 into functions, + // but we're not doing it here for perf. reasons -- as this a function that's invoked on every mouse move for (var i = canvasObjects.length; i--; ) { @@ -62,8 +75,10 @@ function initAligningGuidelines(canvas) { objectHeight = canvasObjects[i].getHeight(), objectWidth = canvasObjects[i].getWidth(); + // snap by the horizontal center line if (isInRange(objectLeft, activeObjectLeft)) { - verticalLines.push({ + noneInTheRange = false; + verticalLines.push({ x: objectLeft, y1: (objectTop < activeObjectTop) ? (objectTop - objectHeight / 2 - aligningLineOffset) @@ -75,7 +90,39 @@ function initAligningGuidelines(canvas) { activeObject.set('left', objectLeft); } + // snap by the left edge + if (isInRange(objectLeft - objectWidth / 2, activeObjectLeft - activeObjectWidth / 2)) { + noneInTheRange = false; + verticalLines.push({ + x: objectLeft - objectWidth / 2, + y1: (objectTop < activeObjectTop) + ? (objectTop - objectHeight / 2 - aligningLineOffset) + : (objectTop + objectHeight / 2 + aligningLineOffset), + y2: (activeObjectTop > objectTop) + ? (activeObjectTop + activeObjectHeight / 2 + aligningLineOffset) + : (activeObjectTop - activeObjectHeight / 2 - aligningLineOffset) + }); + activeObject.set('left', objectLeft - objectWidth / 2 + activeObjectWidth / 2); + } + + // snap by the right edge + if (isInRange(objectLeft + objectWidth / 2, activeObjectLeft + activeObjectWidth / 2)) { + noneInTheRange = false; + verticalLines.push({ + x: objectLeft + objectWidth / 2, + y1: (objectTop < activeObjectTop) + ? (objectTop - objectHeight / 2 - aligningLineOffset) + : (objectTop + objectHeight / 2 + aligningLineOffset), + y2: (activeObjectTop > objectTop) + ? (activeObjectTop + activeObjectHeight / 2 + aligningLineOffset) + : (activeObjectTop - activeObjectHeight / 2 - aligningLineOffset) + }); + activeObject.set('left', objectLeft + objectWidth / 2 - activeObjectWidth / 2); + } + + // snap by the vertical center line if (isInRange(objectTop, activeObjectTop)) { + noneInTheRange = false; horizontalLines.push({ y: objectTop, x1: (objectLeft < activeObjectLeft) @@ -87,17 +134,54 @@ function initAligningGuidelines(canvas) { }); activeObject.set('top', objectTop); } + + // snap by the top edge + if (isInRange(objectTop - objectHeight / 2, activeObjectTop - activeObjectHeight / 2)) { + noneInTheRange = false; + horizontalLines.push({ + y: objectTop - objectHeight / 2, + x1: (objectLeft < activeObjectLeft) + ? (objectLeft - objectWidth / 2 - aligningLineOffset) + : (objectLeft + objectWidth / 2 + aligningLineOffset), + x2: (activeObjectLeft > objectLeft) + ? (activeObjectLeft + activeObjectWidth / 2 + aligningLineOffset) + : (activeObjectLeft - activeObjectWidth / 2 - aligningLineOffset) + }); + activeObject.set('top', objectTop - objectHeight / 2 + activeObjectHeight / 2); + } + + // snap by the bottom edge + if (isInRange(objectTop + objectHeight / 2, activeObjectTop + activeObjectHeight / 2)) { + noneInTheRange = false; + horizontalLines.push({ + y: objectTop + objectHeight / 2, + x1: (objectLeft < activeObjectLeft) + ? (objectLeft - objectWidth / 2 - aligningLineOffset) + : (objectLeft + objectWidth / 2 + aligningLineOffset), + x2: (activeObjectLeft > objectLeft) + ? (activeObjectLeft + activeObjectWidth / 2 + aligningLineOffset) + : (activeObjectLeft - activeObjectWidth / 2 - aligningLineOffset) + }); + activeObject.set('top', objectTop + objectHeight / 2 - activeObjectHeight / 2); + } } - canvas.afterRender = function() { - for (var i = verticalLines.length; i--; ) { - drawVerticalLine(verticalLines[i]); - } - for (var i = horizontalLines.length; i--; ) { - drawHorizontalLine(horizontalLines[i]); - } - }; - }; + if (noneInTheRange) { + verticalLines.length = horizontalLines.length = 0; + } + }); + fabric.util.observeEvent('after:render', function() { + for (var i = verticalLines.length; i--; ) { + drawVerticalLine(verticalLines[i]); + } + for (var i = horizontalLines.length; i--; ) { + drawHorizontalLine(horizontalLines[i]); + } + }); + fabric.util.observeEvent('mouse:up', function() { + verticalLines.length = horizontalLines.length = 0; + canvas.renderAll(); + }); } \ No newline at end of file diff --git a/test/demo/centering_guidelines.js b/test/demo/centering_guidelines.js index 3e550b5f..b77cb079 100644 --- a/test/demo/centering_guidelines.js +++ b/test/demo/centering_guidelines.js @@ -43,32 +43,37 @@ function initCenteringGuidelines(canvas) { ctx.restore(); } - canvas.onObjectMove = function(object) { - var isInVerticalCenter = object.get('left') in canvasWidthCenterMap, - isInHorizontalCenter = object.get('top') in canvasHeightCenterMap; + var observeEvent = fabric.util.observeEvent, + afterRenderActions = [ ], + isInVerticalCenter, + isInHorizontalCenter; + + observeEvent('object:moved', function(e) { + object = e.memo.target; - if (isInVerticalCenter || isInHorizontalCenter) { - canvas.afterRender = function() { - if (isInHorizontalCenter) { - showHorizontalCenterLine(); - } - if (isInVerticalCenter) { - showVerticalCenterLine(); - } - }; - if (isInHorizontalCenter) { - object.set('top', canvasHeightCenter); - } - if (isInVerticalCenter) { - object.set('left', canvasWidthCenter); - } + isInVerticalCenter = object.get('left') in canvasWidthCenterMap, + isInHorizontalCenter = object.get('top') in canvasHeightCenterMap; + + if (isInHorizontalCenter) { + object.set('top', canvasHeightCenter); } - else { - canvas.afterRender = null; + if (isInVerticalCenter) { + object.set('left', canvasWidthCenter); } - }; - canvas.onMouseUp = function() { - canvas.afterRender = null; + }); + + observeEvent('after:render', function() { + if (isInVerticalCenter) { + showVerticalCenterLine(); + } + if (isInHorizontalCenter) { + showHorizontalCenterLine(); + } + }); + + observeEvent('mouse:up', function() { + // clear these values, to stop drawing guidelines once mouse is up + isInVerticalCenter = isInHorizontalCenter = null; canvas.renderAll(); - }; + }); } \ No newline at end of file diff --git a/test/demo/demo.js b/test/demo/demo.js index 9c2cac2e..0d34c4f4 100644 --- a/test/demo/demo.js +++ b/test/demo/demo.js @@ -332,9 +332,6 @@ }, 100); initCenteringGuidelines(canvas); - - if (document.location.search.indexOf('align') > -1) { - initAligningGuidelines(canvas); - } + initAligningGuidelines(canvas); })(this); \ No newline at end of file