mirror of
https://github.com/konvajs/konva.git
synced 2025-09-19 19:07:59 +08:00
first pass at new drawing caching mechanism
This commit is contained in:
@@ -223,7 +223,7 @@
|
|||||||
this.setAttr('lineJoin', lineJoin);
|
this.setAttr('lineJoin', lineJoin);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_applyAncestorTransforms: function(shape) {
|
_applyTransform: function(shape) {
|
||||||
var transformsEnabled = shape.getTransformsEnabled(),
|
var transformsEnabled = shape.getTransformsEnabled(),
|
||||||
m;
|
m;
|
||||||
|
|
||||||
@@ -235,7 +235,6 @@
|
|||||||
// best performance for position only transforms
|
// best performance for position only transforms
|
||||||
this.translate(shape.getX(), shape.getY());
|
this.translate(shape.getX(), shape.getY());
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
_clip: function(container) {
|
_clip: function(container) {
|
||||||
var clipX = container.getClipX(),
|
var clipX = container.getClipX(),
|
||||||
@@ -244,7 +243,7 @@
|
|||||||
clipHeight = container.getClipHeight();
|
clipHeight = container.getClipHeight();
|
||||||
|
|
||||||
this.save();
|
this.save();
|
||||||
this._applyAncestorTransforms(container);
|
this._applyTransform(container);
|
||||||
this.beginPath();
|
this.beginPath();
|
||||||
this.rect(clipX, clipY, clipWidth, clipHeight);
|
this.rect(clipX, clipY, clipWidth, clipHeight);
|
||||||
this.clip();
|
this.clip();
|
||||||
|
103
src/Node.js
103
src/Node.js
@@ -109,22 +109,39 @@
|
|||||||
* node.cache();
|
* node.cache();
|
||||||
*/
|
*/
|
||||||
cache: function(box) {
|
cache: function(box) {
|
||||||
var sceneCanvasCache = new Kinetic.SceneCanvas({
|
var x = box.x || 0,
|
||||||
|
y = box.y || 0,
|
||||||
|
sceneCanvasCache = new Kinetic.SceneCanvas({
|
||||||
pixelRatio: 1,
|
pixelRatio: 1,
|
||||||
width: box.width,
|
width: box.width,
|
||||||
height: box.height
|
height: box.height
|
||||||
});
|
}),
|
||||||
var hitCanvasCache = new Kinetic.HitCanvas({
|
hitCanvasCache = new Kinetic.HitCanvas({
|
||||||
pixelRatio: 1,
|
pixelRatio: 1,
|
||||||
width: box.width,
|
width: box.width,
|
||||||
height: box.height
|
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.drawScene(sceneCanvasCache);
|
||||||
this.drawHit(hitCanvasCache);
|
this.drawHit(hitCanvasCache);
|
||||||
|
|
||||||
this._cache.sceneCanvas = sceneCanvasCache;
|
this.x(origX);
|
||||||
this._cache.hitCanvas = hitCanvasCache;
|
this.y(origY);
|
||||||
|
this.transformsEnabled(origTransEnabled);
|
||||||
|
|
||||||
|
this._cache.canvas = {
|
||||||
|
scene: sceneCanvasCache,
|
||||||
|
hit: hitCanvasCache,
|
||||||
|
x: x,
|
||||||
|
y: y
|
||||||
|
};
|
||||||
},
|
},
|
||||||
/*
|
/*
|
||||||
* the default isDraggable method returns false.
|
* the default isDraggable method returns false.
|
||||||
@@ -599,14 +616,14 @@
|
|||||||
* @returns {Kinetic.Node}
|
* @returns {Kinetic.Node}
|
||||||
*/
|
*/
|
||||||
setAbsolutePosition: function(pos) {
|
setAbsolutePosition: function(pos) {
|
||||||
var trans = this._clearTransform(),
|
var origTrans = this._clearTransform(),
|
||||||
it;
|
it;
|
||||||
|
|
||||||
// don't clear translation
|
// don't clear translation
|
||||||
this.attrs.x = trans.x;
|
this.attrs.x = origTrans.x;
|
||||||
this.attrs.y = trans.y;
|
this.attrs.y = origTrans.y;
|
||||||
delete trans.x;
|
delete origTrans.x;
|
||||||
delete trans.y;
|
delete origTrans.y;
|
||||||
|
|
||||||
// unravel transform
|
// unravel transform
|
||||||
it = this.getAbsoluteTransform();
|
it = this.getAbsoluteTransform();
|
||||||
@@ -619,7 +636,8 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.setPosition({x:pos.x, y:pos.y});
|
this.setPosition({x:pos.x, y:pos.y});
|
||||||
this._setTransform(trans);
|
this._setTransform(origTrans);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
_setTransform: function(trans) {
|
_setTransform: function(trans) {
|
||||||
@@ -658,6 +676,7 @@
|
|||||||
this._clearCache(TRANSFORM);
|
this._clearCache(TRANSFORM);
|
||||||
this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM);
|
this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM);
|
||||||
|
|
||||||
|
// return original transform
|
||||||
return trans;
|
return trans;
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@@ -984,6 +1003,7 @@
|
|||||||
},
|
},
|
||||||
_getTransform: function() {
|
_getTransform: function() {
|
||||||
var m = new Kinetic.Transform(),
|
var m = new Kinetic.Transform(),
|
||||||
|
cachedCanvas = this._cache.canvas,
|
||||||
x = this.getX(),
|
x = this.getX(),
|
||||||
y = this.getY(),
|
y = this.getY(),
|
||||||
rotation = this.getRotation(),
|
rotation = this.getRotation(),
|
||||||
@@ -994,6 +1014,16 @@
|
|||||||
offsetX = this.getOffsetX(),
|
offsetX = this.getOffsetX(),
|
||||||
offsetY = this.getOffsetY();
|
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) {
|
if(x !== 0 || y !== 0) {
|
||||||
m.translate(x, y);
|
m.translate(x, y);
|
||||||
}
|
}
|
||||||
@@ -1649,61 +1679,36 @@
|
|||||||
Kinetic.Factory.addPointGetterSetter(Kinetic.Node, 'offset', 0);
|
Kinetic.Factory.addPointGetterSetter(Kinetic.Node, 'offset', 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set offset. A node's offset defines the position and rotation point
|
* get/set offset. A node's offset defines the position and rotation point
|
||||||
* @name setOffset
|
|
||||||
* @method
|
* @method
|
||||||
* @memberof Kinetic.Node.prototype
|
* @memberof Kinetic.Node.prototype
|
||||||
* @param {Number} x
|
* @param {Object} offset
|
||||||
* @param {Number} y
|
* @param {Number} offset.x
|
||||||
* @returns {Kinetic.Node}
|
* @param {Number} offset.y
|
||||||
|
* @returns {Object}
|
||||||
* @example
|
* @example
|
||||||
* // set x and y <br>
|
* // set x and y <br>
|
||||||
* shape.setOffset({<br>
|
* shape.offset({<br>
|
||||||
* x: 20<br>
|
* x: 20<br>
|
||||||
* y: 10<br>
|
* y: 10<br>
|
||||||
* });<br><br>
|
* });<br><br>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get offset
|
* get/set offset x
|
||||||
* @name getOffset
|
* @name offsetX
|
||||||
* @method
|
|
||||||
* @memberof Kinetic.Node.prototype
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set offset x
|
|
||||||
* @name setOffsetX
|
|
||||||
* @method
|
|
||||||
* @memberof Kinetic.Node.prototype
|
* @memberof Kinetic.Node.prototype
|
||||||
* @param {Number} x
|
* @param {Number} x
|
||||||
* @returns {Kinetic.Node}
|
* @returns {Integer}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get offset x
|
* get/set offset y
|
||||||
* @name getOffsetX
|
* @name offsetY
|
||||||
* @method
|
|
||||||
* @memberof Kinetic.Node.prototype
|
|
||||||
* @returns {Number}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set offset y
|
|
||||||
* @name setOffsetY
|
|
||||||
* @method
|
* @method
|
||||||
* @memberof Kinetic.Node.prototype
|
* @memberof Kinetic.Node.prototype
|
||||||
* @param {Number} y
|
* @param {Number} y
|
||||||
* @returns {Kinetic.Node}
|
* @returns {Integer}
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get offset y
|
|
||||||
* @name getOffsetY
|
|
||||||
* @method
|
|
||||||
* @memberof Kinetic.Node.prototype
|
|
||||||
* @returns {Number}
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Kinetic.Factory.addSetter(Kinetic.Node, 'width', 0);
|
Kinetic.Factory.addSetter(Kinetic.Node, 'width', 0);
|
||||||
|
46
src/Shape.js
46
src/Shape.js
@@ -235,28 +235,20 @@
|
|||||||
drawScene: function(can) {
|
drawScene: function(can) {
|
||||||
var canvas = can || this.getLayer().getCanvas(),
|
var canvas = can || this.getLayer().getCanvas(),
|
||||||
context = canvas.getContext(),
|
context = canvas.getContext(),
|
||||||
|
cachedCanvas = this._cache.canvas,
|
||||||
|
cachedSceneCanvas = cachedCanvas && cachedCanvas.scene,
|
||||||
drawFunc = this.getDrawFunc(),
|
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(),
|
hasShadow = this.hasShadow(),
|
||||||
stage, bufferCanvas, bufferContext;
|
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 buffer canvas is needed
|
||||||
if (this._useBufferCanvas()) {
|
if (this._useBufferCanvas()) {
|
||||||
stage = this.getStage();
|
stage = this.getStage();
|
||||||
@@ -265,7 +257,8 @@
|
|||||||
bufferContext.clear();
|
bufferContext.clear();
|
||||||
bufferContext.save();
|
bufferContext.save();
|
||||||
bufferContext._applyLineJoin(this);
|
bufferContext._applyLineJoin(this);
|
||||||
bufferContext._applyAncestorTransforms(this);
|
bufferContext._applyTransform(this);
|
||||||
|
|
||||||
drawFunc.call(this, bufferContext);
|
drawFunc.call(this, bufferContext);
|
||||||
bufferContext.restore();
|
bufferContext.restore();
|
||||||
|
|
||||||
@@ -282,7 +275,7 @@
|
|||||||
// if buffer canvas is not needed
|
// if buffer canvas is not needed
|
||||||
else {
|
else {
|
||||||
context._applyLineJoin(this);
|
context._applyLineJoin(this);
|
||||||
context._applyAncestorTransforms(this);
|
context._applyTransform(this);
|
||||||
|
|
||||||
if (hasShadow) {
|
if (hasShadow) {
|
||||||
context.save();
|
context.save();
|
||||||
@@ -294,21 +287,30 @@
|
|||||||
context._applyOpacity(this);
|
context._applyOpacity(this);
|
||||||
drawFunc.call(this, context);
|
drawFunc.call(this, context);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
},
|
},
|
||||||
drawHit: function(can) {
|
drawHit: function(can) {
|
||||||
var canvas = can || this.getLayer().hitCanvas,
|
var canvas = can || this.getLayer().hitCanvas,
|
||||||
context = canvas.getContext(),
|
context = canvas.getContext(),
|
||||||
drawFunc = this.getDrawHitFunc() || this.getDrawFunc(),
|
drawFunc = this.getDrawHitFunc() || this.getDrawFunc(),
|
||||||
cachedHitCanvas = this._cache.hitCanvas;
|
cachedCanvas = this._cache.canvas,
|
||||||
|
cachedHitCanvas = cachedCanvas && cachedCanvas.hit;
|
||||||
|
|
||||||
if(this.shouldDrawHit()) {
|
if(this.shouldDrawHit()) {
|
||||||
context.save();
|
context.save();
|
||||||
if (cachedHitCanvas) {
|
if (cachedHitCanvas) {
|
||||||
|
context._applyTransform(this);
|
||||||
context.drawImage(cachedHitCanvas._canvas, 0, 0);
|
context.drawImage(cachedHitCanvas._canvas, 0, 0);
|
||||||
}
|
}
|
||||||
else if (drawFunc) {
|
else if (drawFunc) {
|
||||||
context._applyLineJoin(this);
|
context._applyLineJoin(this);
|
||||||
context._applyAncestorTransforms(this);
|
context._applyTransform(this);
|
||||||
|
|
||||||
drawFunc.call(this, context);
|
drawFunc.call(this, context);
|
||||||
}
|
}
|
||||||
context.restore();
|
context.restore();
|
||||||
|
@@ -2897,8 +2897,8 @@ suite('Node', function() {
|
|||||||
var layer = new Kinetic.Layer();
|
var layer = new Kinetic.Layer();
|
||||||
var group = new Kinetic.Group();
|
var group = new Kinetic.Group();
|
||||||
var circle = new Kinetic.Circle({
|
var circle = new Kinetic.Circle({
|
||||||
x: 100,
|
x: 70,
|
||||||
y: 100,
|
y: 70,
|
||||||
radius: 70,
|
radius: 70,
|
||||||
fill: 'green',
|
fill: 'green',
|
||||||
stroke: 'black',
|
stroke: 'black',
|
||||||
@@ -2911,29 +2911,48 @@ suite('Node', function() {
|
|||||||
layer.add(group);
|
layer.add(group);
|
||||||
stage.add(layer);
|
stage.add(layer);
|
||||||
|
|
||||||
console.log('-- before cache')
|
assert.equal(circle._cache.canvas, undefined);
|
||||||
|
|
||||||
assert.equal(circle._cache['sceneCanvas'], undefined);
|
|
||||||
assert.equal(circle._cache['hitCanvas'], undefined);
|
|
||||||
|
|
||||||
circle.cache({
|
circle.cache({
|
||||||
width: 100,
|
x: -74,
|
||||||
height: 100
|
y: -74,
|
||||||
|
width: 148,
|
||||||
|
height: 148
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.notEqual(circle._cache['sceneCanvas'], undefined);
|
assert.notEqual(circle._cache.canvas.scene, undefined);
|
||||||
assert.notEqual(circle._cache['hitCanvas'], undefined);
|
assert.notEqual(circle._cache.canvas.hit, undefined);
|
||||||
|
assert.equal(circle._cache.canvas.x, -74);
|
||||||
|
assert.equal(circle._cache.canvas.y, -74);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
layer.draw();
|
layer.draw();
|
||||||
|
|
||||||
|
|
||||||
document.body.appendChild(circle._cache.sceneCanvas._canvas);
|
//document.body.appendChild(circle._cache.canvas.scene._canvas);
|
||||||
document.body.appendChild(circle._cache.hitCanvas._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)
|
||||||
});
|
});
|
||||||
});
|
});
|
Reference in New Issue
Block a user