From 4da39ed39bf321dab8e3a3040c0e6e236e70338e Mon Sep 17 00:00:00 2001 From: kzhdev Date: Fri, 31 Jan 2014 16:15:13 -0600 Subject: [PATCH 1/4] fix #785: cache scaled twice in scaled canvas. --- src/Container.js | 2 +- src/Context.js | 9 +++++++-- src/Node.js | 3 +++ src/Shape.js | 6 +++--- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Container.js b/src/Container.js index 41706070..955b4828 100644 --- a/src/Container.js +++ b/src/Container.js @@ -287,7 +287,7 @@ clipY = this.getClipY(); context.save(); - context._applyTransform(this); + context._applyTransform(this, canvas.isCache); context.beginPath(); context.rect(clipX, clipY, clipWidth, clipHeight); context.clip(); diff --git a/src/Context.js b/src/Context.js index 610b9af5..c79abe92 100644 --- a/src/Context.js +++ b/src/Context.js @@ -223,12 +223,17 @@ this.setAttr('lineJoin', lineJoin); } }, - _applyTransform: function(shape) { + _applyTransform: function(shape, isCacheCanvas) { var transformsEnabled = shape.getTransformsEnabled(), m; if (transformsEnabled === 'all') { - m = shape.getAbsoluteTransform().getMatrix(); + if (isCacheCanvas) { + // don't apply parents' transform on cache canvas + m = shape.getTransform().getMatrix(); + } else { + m = shape.getAbsoluteTransform().getMatrix(); + } this.transform(m[0], m[1], m[2], m[3], m[4], m[5]); } else if (transformsEnabled === 'position') { diff --git a/src/Node.js b/src/Node.js index 66cc9ef9..428265c1 100644 --- a/src/Node.js +++ b/src/Node.js @@ -168,6 +168,9 @@ origY = this.y(), sceneContext; + cachedSceneCanvas.isCache = true; + cachedHitCanvas.isCache = true; + this.clearCache(); this.transformsEnabled('position'); diff --git a/src/Shape.js b/src/Shape.js index dee75db4..9042bc9e 100644 --- a/src/Shape.js +++ b/src/Shape.js @@ -154,7 +154,7 @@ bufferContext.clear(); bufferContext.save(); bufferContext._applyLineJoin(this); - bufferContext._applyTransform(this); + bufferContext._applyTransform(this, canvas.isCache); drawFunc.call(this, bufferContext); bufferContext.restore(); @@ -172,7 +172,7 @@ // if buffer canvas is not needed else { context._applyLineJoin(this); - context._applyTransform(this); + context._applyTransform(this, canvas.isCache); if (hasShadow) { context.save(); @@ -205,7 +205,7 @@ else if (drawFunc) { context.save(); context._applyLineJoin(this); - context._applyTransform(this); + context._applyTransform(this, canvas.isCache); drawFunc.call(this, context); context.restore(); From 543191735a4defe11b60b8549ed48950413bc6c0 Mon Sep 17 00:00:00 2001 From: kzhdev Date: Fri, 31 Jan 2014 20:28:33 -0600 Subject: [PATCH 2/4] fix #785: cache scaled twice in scaled canvas. --- src/Context.js | 3 +-- src/Node.js | 45 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/Context.js b/src/Context.js index c79abe92..7008a4ef 100644 --- a/src/Context.js +++ b/src/Context.js @@ -229,8 +229,7 @@ if (transformsEnabled === 'all') { if (isCacheCanvas) { - // don't apply parents' transform on cache canvas - m = shape.getTransform().getMatrix(); + m = shape.getRelativeTransform().getMatrix(); } else { m = shape.getAbsoluteTransform().getMatrix(); } diff --git a/src/Node.js b/src/Node.js index 428265c1..e31a5163 100644 --- a/src/Node.js +++ b/src/Node.js @@ -2,6 +2,7 @@ // CONSTANTS var ABSOLUTE_OPACITY = 'absoluteOpacity', ABSOLUTE_TRANSFORM = 'absoluteTransform', + RELATIVE_TRANSFORM = 'relativeTransform', BEFORE = 'before', CHANGE = 'Change', CHILDREN = 'children', @@ -50,6 +51,7 @@ this.on(TRANSFORM_CHANGE_STR, function() { this._clearCache(TRANSFORM); that._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM); + that._clearSelfAndDescendantCache(RELATIVE_TRANSFORM); }); this.on('visibleChange.kinetic', function() { that._clearSelfAndDescendantCache(VISIBLE); @@ -103,6 +105,7 @@ clearCache: function() { delete this._cache.canvas; this._filterUpToDate = false; + this.cacheBegin = false; return this; }, /** @@ -168,10 +171,11 @@ origY = this.y(), sceneContext; + this.clearCache(); + cachedSceneCanvas.isCache = true; cachedHitCanvas.isCache = true; - - this.clearCache(); + this.cacheBegin = true; this.transformsEnabled('position'); this.x(x * -1); @@ -404,6 +408,7 @@ // traversal must be cleared when removing a node this._clearSelfAndDescendantCache(STAGE); this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM); + this._clearSelfAndDescendantCache(RELATIVE_TRANSFORM); this._clearSelfAndDescendantCache(VISIBLE); this._clearSelfAndDescendantCache(LISTENING); this._clearSelfAndDescendantCache(ABSOLUTE_OPACITY); @@ -756,6 +761,7 @@ this._clearCache(TRANSFORM); this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM); + this._clearSelfAndDescendantCache(RELATIVE_TRANSFORM); }, _clearTransform: function() { var trans = { @@ -782,6 +788,7 @@ this._clearCache(TRANSFORM); this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM); + this._clearSelfAndDescendantCache(RELATIVE_TRANSFORM); // return original transform return trans; @@ -818,7 +825,7 @@ this.setPosition({x:x, y:y}); return this; }, - _eachAncestorReverse: function(func, includeSelf) { + _eachAncestorReverse: function(func, includeSelf, stopAtCacheBegin) { var family = [], parent = this.getParent(), len, n; @@ -827,7 +834,7 @@ if(includeSelf) { family.unshift(this); } - while(parent) { + while(parent && (!stopAtCacheBegin || !parent.cacheBegin)) { family.unshift(parent); parent = parent.parent; } @@ -1093,6 +1100,36 @@ }, true); return at; }, + + /** + * get relative transform of the node which takes into + * account its ancestor transforms + * @method + * @memberof Kinetic.Node.prototype + * @returns {Kinetic.Transform} + */ + getRelativeTransform: function() { + return this._getCache(RELATIVE_TRANSFORM, this._getRelativeTransform); + }, + _getRelativeTransform: function() { + var at = new Kinetic.Transform(), + transformsEnabled, trans; + + // start with stage and traverse downwards to self + this._eachAncestorReverse(function(node) { + transformsEnabled = node.transformsEnabled(); + trans = node.getTransform(); + + if (transformsEnabled === 'all') { + at.multiply(trans); + } + else if (transformsEnabled === 'position') { + at.translate(node.x(), node.y()); + } + }, true, true); + return at; + }, + /** * get transform of the node * @method From 955cc53fc0f9bf57bb523bdaa4b21c11a24c203a Mon Sep 17 00:00:00 2001 From: kzhdev Date: Mon, 3 Feb 2014 09:05:53 -0600 Subject: [PATCH 3/4] Fix an issue where caching cached children is scaled twice --- src/Node.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Node.js b/src/Node.js index e31a5163..a3dd649f 100644 --- a/src/Node.js +++ b/src/Node.js @@ -212,7 +212,7 @@ }, _drawCachedSceneCanvas: function(context) { context.save(); - context._applyTransform(this); + context._applyTransform(this, context.canvas.isCache); context.drawImage(this._getCachedSceneCanvas()._canvas, 0, 0); context.restore(); }, @@ -258,7 +258,7 @@ hitCanvas = cachedCanvas.hit; context.save(); - context._applyTransform(this); + context._applyTransform(this, context.canvas.isCache); context.drawImage(hitCanvas._canvas, 0, 0); context.restore(); }, From c5fcfea8c389a3df92e2a512a6fe6b23fee0cb7d Mon Sep 17 00:00:00 2001 From: kzhdev Date: Tue, 18 Feb 2014 12:46:40 -0600 Subject: [PATCH 4/4] fix cache opacity --- src/Context.js | 13 +++++++++---- src/Node.js | 20 ++++++++++++++++++++ src/Shape.js | 4 ++-- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/Context.js b/src/Context.js index 7008a4ef..15916b9f 100644 --- a/src/Context.js +++ b/src/Context.js @@ -211,10 +211,15 @@ this.setAttr('lineCap', lineCap); } }, - _applyOpacity: function(shape) { - var absOpacity = shape.getAbsoluteOpacity(); - if(absOpacity !== 1) { - this.setAttr('globalAlpha', absOpacity); + _applyOpacity: function(shape, isCacheCanvas) { + var opacity; + if (isCacheCanvas) { + opacity = shape.getRelativeOpacity(); + } else { + opacity = shape.getAbsoluteOpacity(); + } + if(opacity !== 1) { + this.setAttr('globalAlpha', opacity); } }, _applyLineJoin: function(shape) { diff --git a/src/Node.js b/src/Node.js index a3dd649f..bde27a4e 100644 --- a/src/Node.js +++ b/src/Node.js @@ -1,6 +1,7 @@ (function() { // CONSTANTS var ABSOLUTE_OPACITY = 'absoluteOpacity', + RELATIVE_OPACITY = 'relativeOpacity', ABSOLUTE_TRANSFORM = 'absoluteTransform', RELATIVE_TRANSFORM = 'relativeTransform', BEFORE = 'before', @@ -61,6 +62,7 @@ }); this.on('opacityChange.kinetic', function() { that._clearSelfAndDescendantCache(ABSOLUTE_OPACITY); + that._clearSelfAndDescendantCache(RELATIVE_OPACITY); }); }, _clearCache: function(attr){ @@ -213,6 +215,7 @@ _drawCachedSceneCanvas: function(context) { context.save(); context._applyTransform(this, context.canvas.isCache); + context._applyOpacity(this, context.canvas.isCache); context.drawImage(this._getCachedSceneCanvas()._canvas, 0, 0); context.restore(); }, @@ -412,6 +415,7 @@ this._clearSelfAndDescendantCache(VISIBLE); this._clearSelfAndDescendantCache(LISTENING); this._clearSelfAndDescendantCache(ABSOLUTE_OPACITY); + this._clearSelfAndDescendantCache(RELATIVE_OPACITY); return this; }, @@ -947,6 +951,22 @@ } return absOpacity; }, + /** + * get relative opacity + * @method + * @memberof Kinetic.Node.prototype + * @returns {Number} + */ + getRelativeOpacity: function() { + return this._getCache(RELATIVE_OPACITY, this._getRelativeOpacity); + }, + _getRelativeOpacity: function() { + var opacity = 1; + this._eachAncestorReverse(function(node) { + opacity *= node.getOpacity(); + }, true, true); + return opacity; + }, /** * move node to another container * @method diff --git a/src/Shape.js b/src/Shape.js index 9042bc9e..e7f90ec1 100644 --- a/src/Shape.js +++ b/src/Shape.js @@ -166,7 +166,7 @@ context.restore(); } - context._applyOpacity(this); + context._applyOpacity(this, canvas.isCache); context.drawImage(bufferCanvas._canvas, 0, 0); } // if buffer canvas is not needed @@ -181,7 +181,7 @@ context.restore(); } - context._applyOpacity(this); + context._applyOpacity(this, canvas.isCache); drawFunc.call(this, context); } context.restore();