first pass at new drawing caching mechanism

This commit is contained in:
Eric Rowell
2013-12-28 13:25:15 -08:00
parent 4866acdf93
commit b5165fa8fb
4 changed files with 149 additions and 124 deletions

View File

@@ -223,7 +223,7 @@
this.setAttr('lineJoin', lineJoin);
}
},
_applyAncestorTransforms: function(shape) {
_applyTransform: function(shape) {
var transformsEnabled = shape.getTransformsEnabled(),
m;
@@ -235,7 +235,6 @@
// best performance for position only transforms
this.translate(shape.getX(), shape.getY());
}
},
_clip: function(container) {
var clipX = container.getClipX(),
@@ -244,7 +243,7 @@
clipHeight = container.getClipHeight();
this.save();
this._applyAncestorTransforms(container);
this._applyTransform(container);
this.beginPath();
this.rect(clipX, clipY, clipWidth, clipHeight);
this.clip();

View File

@@ -109,22 +109,39 @@
* node.cache();
*/
cache: function(box) {
var sceneCanvasCache = new Kinetic.SceneCanvas({
var x = box.x || 0,
y = box.y || 0,
sceneCanvasCache = new Kinetic.SceneCanvas({
pixelRatio: 1,
width: box.width,
height: box.height
});
var hitCanvasCache = new Kinetic.HitCanvas({
}),
hitCanvasCache = new Kinetic.HitCanvas({
pixelRatio: 1,
width: box.width,
height: box.height
});
}),
origTransEnabled = this.transformsEnabled(),
origX = this.x(),
origY = this.y();
this.transformsEnabled('position');
this.x(x * -1);
this.y(y * -1);
this.drawScene(sceneCanvasCache);
this.drawHit(hitCanvasCache);
this._cache.sceneCanvas = sceneCanvasCache;
this._cache.hitCanvas = hitCanvasCache;
this.x(origX);
this.y(origY);
this.transformsEnabled(origTransEnabled);
this._cache.canvas = {
scene: sceneCanvasCache,
hit: hitCanvasCache,
x: x,
y: y
};
},
/*
* the default isDraggable method returns false.
@@ -599,14 +616,14 @@
* @returns {Kinetic.Node}
*/
setAbsolutePosition: function(pos) {
var trans = this._clearTransform(),
var origTrans = this._clearTransform(),
it;
// don't clear translation
this.attrs.x = trans.x;
this.attrs.y = trans.y;
delete trans.x;
delete trans.y;
this.attrs.x = origTrans.x;
this.attrs.y = origTrans.y;
delete origTrans.x;
delete origTrans.y;
// unravel transform
it = this.getAbsoluteTransform();
@@ -619,7 +636,8 @@
};
this.setPosition({x:pos.x, y:pos.y});
this._setTransform(trans);
this._setTransform(origTrans);
return this;
},
_setTransform: function(trans) {
@@ -658,6 +676,7 @@
this._clearCache(TRANSFORM);
this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM);
// return original transform
return trans;
},
/**
@@ -984,6 +1003,7 @@
},
_getTransform: function() {
var m = new Kinetic.Transform(),
cachedCanvas = this._cache.canvas,
x = this.getX(),
y = this.getY(),
rotation = this.getRotation(),
@@ -994,6 +1014,16 @@
offsetX = this.getOffsetX(),
offsetY = this.getOffsetY();
// NOTE: the cached canvas offsets must be handled in this method
// because there are situations where we need to access the original
// offset positions, i.e. setAbsolutePosition() and drag and drop
if (cachedCanvas) {
offsetX -= cachedCanvas.x;
}
if (cachedCanvas) {
offsetY -= cachedCanvas.y;
}
if(x !== 0 || y !== 0) {
m.translate(x, y);
}
@@ -1649,61 +1679,36 @@
Kinetic.Factory.addPointGetterSetter(Kinetic.Node, 'offset', 0);
/**
* set offset. A node's offset defines the position and rotation point
* @name setOffset
* get/set offset. A node's offset defines the position and rotation point
* @method
* @memberof Kinetic.Node.prototype
* @param {Number} x
* @param {Number} y
* @returns {Kinetic.Node}
* @param {Object} offset
* @param {Number} offset.x
* @param {Number} offset.y
* @returns {Object}
* @example
* // set x and y <br>
* shape.setOffset({<br>
* shape.offset({<br>
* x: 20<br>
* y: 10<br>
* });<br><br>
*/
/**
* get offset
* @name getOffset
* @method
* @memberof Kinetic.Node.prototype
* @returns {Object}
*/
/**
* set offset x
* @name setOffsetX
* @method
* get/set offset x
* @name offsetX
* @memberof Kinetic.Node.prototype
* @param {Number} x
* @returns {Kinetic.Node}
* @returns {Integer}
*/
/**
* get offset x
* @name getOffsetX
* @method
* @memberof Kinetic.Node.prototype
* @returns {Number}
*/
/**
* set offset y
* @name setOffsetY
* get/set offset y
* @name offsetY
* @method
* @memberof Kinetic.Node.prototype
* @param {Number} y
* @returns {Kinetic.Node}
*/
/**
* get offset y
* @name getOffsetY
* @method
* @memberof Kinetic.Node.prototype
* @returns {Number}
* @returns {Integer}
*/
Kinetic.Factory.addSetter(Kinetic.Node, 'width', 0);

View File

@@ -235,28 +235,20 @@
drawScene: function(can) {
var canvas = can || this.getLayer().getCanvas(),
context = canvas.getContext(),
cachedCanvas = this._cache.canvas,
cachedSceneCanvas = cachedCanvas && cachedCanvas.scene,
drawFunc = this.getDrawFunc(),
cachedSceneCanvas = this._cache.sceneCanvas;
if(this.isVisible()) {
context.save();
// if cache is available
if (cachedSceneCanvas) {
context.drawImage(cachedSceneCanvas._canvas, 0, 0);
}
else if (drawFunc) {
this._drawScene(context);
}
context.restore();
}
return this;
},
_drawScene: function(context) {
var drawFunc = this.getDrawFunc(),
hasShadow = this.hasShadow(),
stage, bufferCanvas, bufferContext;
if(this.isVisible()) {
context.save();
if (cachedSceneCanvas) {
context._applyTransform(this);
context.drawImage(cachedSceneCanvas._canvas, 0, 0);
}
else if (drawFunc) {
// if buffer canvas is needed
if (this._useBufferCanvas()) {
stage = this.getStage();
@@ -265,7 +257,8 @@
bufferContext.clear();
bufferContext.save();
bufferContext._applyLineJoin(this);
bufferContext._applyAncestorTransforms(this);
bufferContext._applyTransform(this);
drawFunc.call(this, bufferContext);
bufferContext.restore();
@@ -282,7 +275,7 @@
// if buffer canvas is not needed
else {
context._applyLineJoin(this);
context._applyAncestorTransforms(this);
context._applyTransform(this);
if (hasShadow) {
context.save();
@@ -294,21 +287,30 @@
context._applyOpacity(this);
drawFunc.call(this, context);
}
}
context.restore();
}
return this;
},
drawHit: function(can) {
var canvas = can || this.getLayer().hitCanvas,
context = canvas.getContext(),
drawFunc = this.getDrawHitFunc() || this.getDrawFunc(),
cachedHitCanvas = this._cache.hitCanvas;
cachedCanvas = this._cache.canvas,
cachedHitCanvas = cachedCanvas && cachedCanvas.hit;
if(this.shouldDrawHit()) {
context.save();
if (cachedHitCanvas) {
context._applyTransform(this);
context.drawImage(cachedHitCanvas._canvas, 0, 0);
}
else if (drawFunc) {
context._applyLineJoin(this);
context._applyAncestorTransforms(this);
context._applyTransform(this);
drawFunc.call(this, context);
}
context.restore();

View File

@@ -2897,8 +2897,8 @@ suite('Node', function() {
var layer = new Kinetic.Layer();
var group = new Kinetic.Group();
var circle = new Kinetic.Circle({
x: 100,
y: 100,
x: 70,
y: 70,
radius: 70,
fill: 'green',
stroke: 'black',
@@ -2911,29 +2911,48 @@ suite('Node', function() {
layer.add(group);
stage.add(layer);
console.log('-- before cache')
assert.equal(circle._cache['sceneCanvas'], undefined);
assert.equal(circle._cache['hitCanvas'], undefined);
assert.equal(circle._cache.canvas, undefined);
circle.cache({
width: 100,
height: 100
x: -74,
y: -74,
width: 148,
height: 148
});
assert.notEqual(circle._cache['sceneCanvas'], undefined);
assert.notEqual(circle._cache['hitCanvas'], undefined);
assert.notEqual(circle._cache.canvas.scene, undefined);
assert.notEqual(circle._cache.canvas.hit, undefined);
assert.equal(circle._cache.canvas.x, -74);
assert.equal(circle._cache.canvas.y, -74);
layer.draw();
document.body.appendChild(circle._cache.sceneCanvas._canvas);
document.body.appendChild(circle._cache.hitCanvas._canvas);
//document.body.appendChild(circle._cache.canvas.scene._canvas);
// document.body.appendChild(circle._cache.canvas.hit._canvas);
showHit(layer)
console.log(layer.getContext().getTrace());
//console.log(layer.getContext().getTrace());
assert.equal(layer.getContext().getTrace(), 'clearRect(0,0,578,200);save();transform(1,0,0,1,70,70);beginPath();arc(0,0,70,0,6.283,false);closePath();fillStyle=green;fill();lineWidth=4;strokeStyle=black;stroke();restore();clearRect(0,0,578,200);save();transform(1,0,0,1,-4,-4);drawImage([object HTMLCanvasElement],0,0);restore();');
// setTimeout(function() {
// console.log('draw')
// layer.draw();
// }, 1000)
// setTimeout(function() {
// console.log('draw')
// layer.draw();
// }, 2000)
// setTimeout(function() {
// console.log('draw')
// layer.draw();
// }, 3000)
});
});