added matrix transform caching, and optimized the clear() method. This has improved rendering performance by about 17%

This commit is contained in:
Eric Rowell
2013-04-21 22:42:25 -07:00
parent 90a2820e5b
commit 8a78b62cad
5 changed files with 89 additions and 37 deletions

View File

@@ -29,8 +29,6 @@
contextType = config.contextType || '2d';
this.pixelRatio = pixelRatio;
this.width = width;
this.height = height;
this.element = document.createElement('canvas');
this.element.style.padding = 0;
this.element.style.margin = 0;
@@ -62,9 +60,8 @@
* @param {Number} width
*/
setWidth: function(width) {
this.width = width;
// take into account pixel ratio
this.element.width = width * this.pixelRatio;
this.width = this.element.width = width * this.pixelRatio;
this.element.style.width = width + 'px';
},
/**
@@ -74,9 +71,8 @@
* @param {Number} height
*/
setHeight: function(height) {
this.height = height;
// take into account pixel ratio
this.element.height = height * this.pixelRatio;
this.height = this.element.height = height * this.pixelRatio;
this.element.style.height = height + 'px';
},
/**
@@ -127,7 +123,7 @@
clear: function() {
var context = this.getContext();
var el = this.getElement();
context.clearRect(0, 0, el.width, el.height);
context.clearRect(0, 0, this.getWidth(), this.getHeight());
},
/**
* to data url
@@ -226,9 +222,12 @@
}
},
_applyAncestorTransforms: function(node) {
var context = this.context;
var context = this.context,
t, m;
node._eachAncestorReverse(function(no) {
var t = no.getTransform(), m = t.getMatrix();
t = no.getTransform(true);
m = t.getMatrix();
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
}, true);
},

View File

@@ -199,8 +199,7 @@
drawScene: function(canvas) {
var layer = this.getLayer(),
clip = !!this.getClipFunc(),
stage = this.getStage(),
children, len;
children, n, len;
if (!canvas && layer) {
canvas = layer.getCanvas();
@@ -214,7 +213,7 @@
children = this.children;
len = children.length;
for(var n = 0; n < len; n++) {
for(n = 0; n < len; n++) {
children[n].drawScene(canvas);
}

View File

@@ -645,12 +645,7 @@
}, true);
return am;
},
/**
* get transform of the node
* @name getTransform
* @methodOf Kinetic.Node.prototype
*/
getTransform: function() {
_getAndCacheTransform: function() {
var m = new Kinetic.Transform(),
x = this.getX(),
y = this.getY(),
@@ -675,8 +670,24 @@
m.translate(-1 * offsetX, -1 * offsetY);
}
// cache result
this.cachedTransform = m;
return m;
},
/**
* get transform of the node
* @name getTransform
* @methodOf Kinetic.Node.prototype
*/
getTransform: function(useCache) {
var cachedTransform = this.cachedTransform;
if (useCache && cachedTransform) {
return cachedTransform;
}
else {
return this._getAndCacheTransform();
}
},
/**
* clone node. Returns a new Node instance with identical attributes
* @name clone
@@ -996,28 +1007,30 @@
};
// add getter and setter methods
Kinetic.Node.addGetterSetter = function(constructor, arr, def) {
Kinetic.Node.addGetterSetter = function(constructor, arr, def, isTransform) {
this.addGetter(constructor, arr, def);
this.addSetter(constructor, arr);
this.addSetter(constructor, arr, isTransform);
};
Kinetic.Node.addPointGetterSetter = function(constructor, arr, def) {
this.addGetter(constructor, arr, def);
this.addPointSetter(constructor, arr);
Kinetic.Node.addPointGetterSetter = function(constructor, arr, def, isTransform) {
this.addGetter(constructor, arr, def);
this.addPointSetter(constructor, arr, isTransform);
};
Kinetic.Node.addRotationGetterSetter = function(constructor, arr, def) {
Kinetic.Node.addRotationGetterSetter = function(constructor, arr, def, isTransform) {
this.addRotationGetter(constructor, arr, def);
this.addRotationSetter(constructor, arr);
this.addRotationSetter(constructor, arr, isTransform);
};
Kinetic.Node.addSetter = function(constructor, attr) {
Kinetic.Node.addSetter = function(constructor, attr, isTransform) {
var that = this,
method = SET + Kinetic.Type._capitalize(attr);
constructor.prototype[method] = function(val) {
this.setAttr(attr, val);
if (isTransform) {
this.cachedTransform = null;
}
};
};
Kinetic.Node.addPointSetter = function(constructor, attr) {
Kinetic.Node.addPointSetter = function(constructor, attr, isTransform) {
var that = this,
method = SET + Kinetic.Type._capitalize(attr);
@@ -1036,19 +1049,29 @@
pos.y = this.attrs[attr].y;
}
this.setAttr(attr, pos);
if (isTransform) {
this.cachedTransform = null;
}
};
};
Kinetic.Node.addRotationSetter = function(constructor, attr) {
Kinetic.Node.addRotationSetter = function(constructor, attr, isTransform) {
var that = this,
method = SET + Kinetic.Type._capitalize(attr);
// radians
constructor.prototype[method] = function(val) {
this.setAttr(attr, val);
if (isTransform) {
this.cachedTransform = null;
}
};
// degrees
constructor.prototype[method + DEG] = function(deg) {
this.setAttr(attr, Kinetic.Type._degToRad(deg));
if (isTransform) {
this.cachedTransform = null;
}
};
};
Kinetic.Node.addGetter = function(constructor, attr, def) {
@@ -1134,8 +1157,8 @@
return no;
};
// add getters setters
Kinetic.Node.addGetterSetter(Kinetic.Node, 'x', 0);
Kinetic.Node.addGetterSetter(Kinetic.Node, 'y', 0);
Kinetic.Node.addGetterSetter(Kinetic.Node, 'x', 0, true);
Kinetic.Node.addGetterSetter(Kinetic.Node, 'y', 0, true);
Kinetic.Node.addGetterSetter(Kinetic.Node, 'opacity', 1);
/**
@@ -1194,7 +1217,7 @@
* @methodOf Kinetic.Node.prototype
*/
Kinetic.Node.addRotationGetterSetter(Kinetic.Node, 'rotation', 0);
Kinetic.Node.addRotationGetterSetter(Kinetic.Node, 'rotation', 0, true);
/**
* set rotation in radians
@@ -1222,8 +1245,8 @@
* @methodOf Kinetic.Node.prototype
*/
Kinetic.Node.addPointGetterSetter(Kinetic.Node, 'scale', {x:1,y:1});
Kinetic.Node.addPointGetterSetter(Kinetic.Node, 'offset', {x:0,y:0});
Kinetic.Node.addPointGetterSetter(Kinetic.Node, 'scale', {x:1,y:1}, true);
Kinetic.Node.addPointGetterSetter(Kinetic.Node, 'offset', {x:0,y:0}, true);
/**
* set scale

View File

@@ -178,8 +178,7 @@
delete Kinetic.Global.shapes[this.colorKey];
},
drawScene: function(canvas) {
var attrs = this.getAttrs(),
drawFunc = attrs.drawFunc,
var drawFunc = this.getDrawFunc(),
canvas = canvas || this.getLayer().getCanvas(),
context = canvas.getContext();

View File

@@ -23,6 +23,38 @@ 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');
},
'transformation matrix caching': function(containerId) {
var stage = new Kinetic.Stage({
container: containerId,
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var circle = new Kinetic.Circle({
x: stage.getWidth() / 2,
y: stage.getHeight() / 2,
radius: 70,
fill: 'green',
stroke: 'black',
strokeWidth: 4
});
test(!circle.cachedTransform, 'circle transform cache should be empty');
layer.add(circle);
stage.add(layer);
test(circle.cachedTransform, 'circle transform cache should be present');
circle.setX(100);
test(!circle.cachedTransform, 'circle transform cache should be empty');
layer.draw();
test(circle.cachedTransform, 'circle transform cache should be present');
},
'test pixel ratio toDataURL': function(containerId) {
var stage = new Kinetic.Stage({
container: containerId,