absolute transforms are now cached

This commit is contained in:
Eric Rowell
2013-08-10 00:58:53 -07:00
parent a0a2d9a676
commit d902e6dca0
4 changed files with 109 additions and 48 deletions

View File

@@ -218,6 +218,10 @@
}
},
_applyAncestorTransforms: function(node) {
var m = node.getAbsoluteTransform().getMatrix();
this.context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
/*
var context = this.context,
t, m;
@@ -226,6 +230,7 @@
m = t.getMatrix();
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
}, true);
*/
},
_clip: function(container) {
var context = this.getContext();

View File

@@ -1,6 +1,7 @@
(function() {
// CONSTANTS
var ADD = 'add',
var ABSOLUTE_TRANSFORM = 'absoluteTransform',
ADD = 'add',
B = 'b',
BEFORE = 'before',
BLACK = 'black',
@@ -34,20 +35,29 @@
UPPER_Y = 'Y',
VISIBLE = 'visible',
X = 'x',
Y = 'y',
Y = 'y';
CACHE_MAP = {
x: TRANSFORM,
y: TRANSFORM,
rotation: TRANSFORM,
rotationDeg: TRANSFORM,
scaleX: TRANSFORM,
scaleY: TRANSFORM,
skewX: TRANSFORM,
skewY: TRANSFORM,
function _clearTransformCacheEachChild(node) {
_clearTransformCache.call(node);
}
function _clearTransformCache() {
this._clearCache(TRANSFORM);
this._clearCache(ABSOLUTE_TRANSFORM);
visible: VISIBLE
};
if (this.children) {
this.getChildren().each(_clearTransformCacheEachChild);
}
}
function _clearVisibleCacheEachChild(node) {
_clearVisibleCache.call(node);
}
function _clearVisibleCache() {
this._clearCache(VISIBLE);
if (this.children) {
this.getChildren().each(_clearVisibleCacheEachChild);
}
}
Kinetic.Util.addMethods(Kinetic.Node, {
_init: function(config) {
@@ -58,10 +68,7 @@
this.setAttrs(config);
},
_clearCache: function(attr){
var cacheAttr = CACHE_MAP[attr];
if (cacheAttr) {
delete this.cache[cacheAttr];
}
delete this.cache[attr];
},
_getCache: function(attr, privateGetter){
var cache = this.cache[attr];
@@ -234,6 +241,26 @@
return this.attrs[attr];
}
},
/**
* get ancestors
* @method
* @memberof Kinetic.Node.prototype
* @example
* shape.getAncestors().each(function(node) {
* console.log(node.getId());
* })
*/
getAncestors: function() {
var parent = this.getParent(),
ancestors = new Kinetic.Collection();
while (parent) {
ancestors.push(parent);
parent = parent.getParent();
}
return ancestors;
},
/**
* set attr
* @method
@@ -758,6 +785,9 @@
* @memberof Kinetic.Node.prototype
*/
getAbsoluteTransform: function() {
return this._getCache(ABSOLUTE_TRANSFORM, this._getAbsoluteTransform);
},
_getAbsoluteTransform: function() {
// absolute transform
var am = new Kinetic.Transform(),
m;
@@ -1153,28 +1183,28 @@
});
// getter setter adders
Kinetic.Node.addGetterSetter = function(constructor, attr, def) {
Kinetic.Node.addGetterSetter = function(constructor, attr, def, before) {
this.addGetter(constructor, attr, def);
this.addSetter(constructor, attr);
this.addSetter(constructor, attr, before);
};
Kinetic.Node.addPointGetterSetter = function(constructor, attr, def) {
this.addPointGetter(constructor, attr);
this.addPointSetter(constructor, attr);
Kinetic.Node.addPointGetterSetter = function(constructor, attr, def, before) {
this.addPointGetter(constructor, attr, def);
this.addPointSetter(constructor, attr, before);
// add invdividual component getters and setters
this.addGetter(constructor, attr + UPPER_X, def);
this.addGetter(constructor, attr + UPPER_Y, def);
this.addSetter(constructor, attr + UPPER_X);
this.addSetter(constructor, attr + UPPER_Y);
this.addSetter(constructor, attr + UPPER_X, before);
this.addSetter(constructor, attr + UPPER_Y, before);
};
Kinetic.Node.addPointsGetterSetter = function(constructor, attr) {
this.addPointsGetter(constructor, attr);
this.addPointsSetter(constructor, attr);
this.addPointAdder(constructor, attr);
};
Kinetic.Node.addRotationGetterSetter = function(constructor, attr, def) {
Kinetic.Node.addRotationGetterSetter = function(constructor, attr, def, before) {
this.addRotationGetter(constructor, attr, def);
this.addRotationSetter(constructor, attr);
this.addRotationSetter(constructor, attr, before);
};
Kinetic.Node.addColorGetterSetter = function(constructor, attr) {
this.addGetter(constructor, attr);
@@ -1289,16 +1319,17 @@
this._setAttr('points', points);
};
};
Kinetic.Node.addSetter = function(constructor, attr) {
var that = this,
method = SET + Kinetic.Util._capitalize(attr);
Kinetic.Node.addSetter = function(constructor, attr, before) {
var method = SET + Kinetic.Util._capitalize(attr);
constructor.prototype[method] = function(val) {
this._clearCache(attr);
if (before) {
before.call(this);
}
this._setAttr(attr, val);
};
};
Kinetic.Node.addPointSetter = function(constructor, attr) {
Kinetic.Node.addPointSetter = function(constructor, attr, before) {
var that = this,
baseMethod = SET + Kinetic.Util._capitalize(attr);
@@ -1313,6 +1344,9 @@
y = pos.y;
this._fireBeforeChangeEvent(attr, oldVal, pos);
if (before) {
before.call(this);
}
if (x !== undefined) {
this[baseMethod + UPPER_X](x);
}
@@ -1323,18 +1357,22 @@
}
};
};
Kinetic.Node.addRotationSetter = function(constructor, attr) {
Kinetic.Node.addRotationSetter = function(constructor, attr, before) {
var that = this,
method = SET + Kinetic.Util._capitalize(attr);
// radians
constructor.prototype[method] = function(val) {
this._clearCache(attr);
if (before) {
before.call(this);
}
this._setAttr(attr, val);
};
// degrees
constructor.prototype[method + DEG] = function(deg) {
this._clearCache(attr);
if (before) {
before.call(this);
}
this._setAttr(attr, Kinetic.Util._degToRad(deg));
};
};
@@ -1394,7 +1432,7 @@
};
// add getters setters
Kinetic.Node.addGetterSetter(Kinetic.Node, 'x', 0);
Kinetic.Node.addGetterSetter(Kinetic.Node, 'x', 0, _clearTransformCache);
/**
* set x position
@@ -1411,7 +1449,7 @@
* @memberof Kinetic.Node.prototype
*/
Kinetic.Node.addGetterSetter(Kinetic.Node, 'y', 0);
Kinetic.Node.addGetterSetter(Kinetic.Node, 'y', 0, _clearTransformCache);
/**
* set y position
@@ -1465,7 +1503,7 @@
* @memberof Kinetic.Node.prototype
*/
Kinetic.Node.addRotationGetterSetter(Kinetic.Node, 'rotation', 0);
Kinetic.Node.addRotationGetterSetter(Kinetic.Node, 'rotation', 0, _clearTransformCache);
/**
* set rotation in radians
@@ -1497,7 +1535,7 @@
* @memberof Kinetic.Node.prototype
*/
Kinetic.Node.addPointGetterSetter(Kinetic.Node, 'scale', 1);
Kinetic.Node.addPointGetterSetter(Kinetic.Node, 'scale', 1, _clearTransformCache);
/**
* set scale
@@ -1558,7 +1596,7 @@
* @memberof Kinetic.Node.prototype
*/
Kinetic.Node.addPointGetterSetter(Kinetic.Node, 'skew', 0);
Kinetic.Node.addPointGetterSetter(Kinetic.Node, 'skew', 0, _clearTransformCache);
/**
* set skew
@@ -1620,7 +1658,7 @@
* @memberof Kinetic.Node.prototype
*/
Kinetic.Node.addPointGetterSetter(Kinetic.Node, 'offset', 0);
Kinetic.Node.addPointGetterSetter(Kinetic.Node, 'offset', 0, _clearTransformCache);
/**
* set offset. A node's offset defines the position and rotation point
@@ -1719,7 +1757,7 @@
* @memberof Kinetic.Node.prototype
*/
Kinetic.Node.addSetter(Kinetic.Node, 'visible');
Kinetic.Node.addSetter(Kinetic.Node, 'visible', _clearVisibleCache);
/**
* set visible

View File

@@ -1,4 +1,6 @@
(function() {
var HAS_SHADOW = 'hasShadow';
function _fillFunc(context) {
context.fill();
}
@@ -11,6 +13,9 @@
function _strokeFuncHit(context) {
context.stroke();
}
function _clearHasShadowCache() {
this._clearCache(HAS_SHADOW);
}
Kinetic.Util.addMethods(Kinetic.Shape, {
__init: function(config) {
@@ -67,6 +72,9 @@
* @memberof Kinetic.Shape.prototype
*/
hasShadow: function() {
return this._getCache(HAS_SHADOW, this._hasShadow);
},
_hasShadow: function() {
return (this.getShadowOpacity() !== 0 && !!(this.getShadowColor() || this.getShadowBlur() || this.getShadowOffsetX() || this.getShadowOffsetY()));
},
/**
@@ -433,7 +441,7 @@
* @memberof Kinetic.Shape.prototype
*/
Kinetic.Node.addColorGetterSetter(Kinetic.Shape, 'shadowColor');
Kinetic.Node.addColorGetterSetter(Kinetic.Shape, 'shadowColor', undefined, _clearHasShadowCache);
/**
* set shadow color
@@ -516,7 +524,7 @@
* @memberof Kinetic.Shape.prototype
*/
Kinetic.Node.addGetterSetter(Kinetic.Shape, 'shadowBlur');
Kinetic.Node.addGetterSetter(Kinetic.Shape, 'shadowBlur', undefined, _clearHasShadowCache);
/**
* set shadow blur
@@ -533,7 +541,7 @@
* @memberof Kinetic.Shape.prototype
*/
Kinetic.Node.addGetterSetter(Kinetic.Shape, 'shadowOpacity');
Kinetic.Node.addGetterSetter(Kinetic.Shape, 'shadowOpacity', undefined, _clearHasShadowCache);
/**
* set shadow opacity
@@ -1239,7 +1247,7 @@
* @memberof Kinetic.Shape.prototype
*/
Kinetic.Node.addPointGetterSetter(Kinetic.Shape, 'shadowOffset', 0);
Kinetic.Node.addPointGetterSetter(Kinetic.Shape, 'shadowOffset', 0, _clearHasShadowCache);
/**
* set shadow offset

View File

@@ -89,7 +89,7 @@ Test.Modules.NODE = {
test(circle.getAbsoluteOpacity() === 0.25, 'abs opacity should be 0.25');
test(layer.getAbsoluteOpacity() === 0.5, 'abs opacity should be 0.5');
},
'*caching': function(containerId) {
'caching': function(containerId) {
var stage = new Kinetic.Stage({
container: containerId,
width: 578,
@@ -105,7 +105,7 @@ Test.Modules.NODE = {
strokeWidth: 4
});
test(!circle.cache.transform, '1) circle transform cache should be empty');
test(circle.cache.transform === undefined, '1) circle transform cache should be empty');
layer.add(circle);
stage.add(layer);
@@ -113,7 +113,7 @@ Test.Modules.NODE = {
// transform cache
test(circle.cache.transform, '2) circle transform cache should be primed');
circle.setX(100);
test(!circle.cache.transform, '3) circle transform cache should be empty');
test(circle.cache.transform === undefined, '3) circle transform cache should be empty');
layer.draw();
test(circle.cache.transform, '4) circle transform cache should be primed');
@@ -128,6 +128,16 @@ Test.Modules.NODE = {
stage.draw();
test(circle.cache.visible === true, '9) circle visible cache should be primed');
// shadow cache
test(circle.cache.hasShadow === false, '10) circle shadow cache should be primed');
circle.setShadowColor('red');
circle.setShadowOffset(10);
test(circle.cache.hasShadow === undefined, '11) circle shadow cache should be empty');
layer.draw();
test(circle.cache.hasShadow === true, '12) circle shadow cache should be primed');
layer.draw();
test(circle.cache.hasShadow === true, '13) circle shadow cache should still be primed after redraw');
},
'test pixel ratio toDataURL': function(containerId) {
var stage = new Kinetic.Stage({