mirror of
https://github.com/konvajs/konva.git
synced 2025-09-19 10:47:59 +08:00
transformsEnabled property now accepts all, none, or position. Also started prelim work for new caching system
This commit is contained in:
@@ -243,9 +243,9 @@
|
||||
clip = this.getClipWidth() && this.getClipHeight(),
|
||||
children, n, len;
|
||||
|
||||
if (!canvas && layer) {
|
||||
canvas = layer.getCanvas();
|
||||
}
|
||||
// if (!canvas && layer) {
|
||||
// canvas = layer.getCanvas();
|
||||
// }
|
||||
|
||||
if(this.isVisible()) {
|
||||
if (clip) {
|
||||
|
@@ -224,14 +224,15 @@
|
||||
}
|
||||
},
|
||||
_applyAncestorTransforms: function(shape) {
|
||||
var m;
|
||||
var transformsEnabled = shape.getTransformsEnabled(),
|
||||
m;
|
||||
|
||||
if (shape.isTransformsEnabled()) {
|
||||
if (transformsEnabled === 'all') {
|
||||
m = shape.getAbsoluteTransform().getMatrix();
|
||||
this.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
||||
}
|
||||
else {
|
||||
// best performance
|
||||
else if (transformsEnabled === 'position') {
|
||||
// best performance for position only transforms
|
||||
this.translate(shape.getX(), shape.getY());
|
||||
}
|
||||
|
||||
|
121
src/Node.js
121
src/Node.js
@@ -42,7 +42,7 @@
|
||||
this._id = Kinetic.idCounter++;
|
||||
this.eventListeners = {};
|
||||
this.attrs = {};
|
||||
this.cache = {};
|
||||
this._cache = {};
|
||||
this.setAttrs(config);
|
||||
|
||||
// event bindings for cache handling
|
||||
@@ -60,32 +60,18 @@
|
||||
that._clearSelfAndDescendantCache(ABSOLUTE_OPACITY);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* clear cached variables
|
||||
* @method
|
||||
* @memberof Kinetic.Node.prototype
|
||||
* @returns {Kinetic.Node}
|
||||
* @example
|
||||
* node.clearCache();
|
||||
*/
|
||||
clearCache: function() {
|
||||
this.cache = {};
|
||||
return this;
|
||||
},
|
||||
_clearCache: function(attr){
|
||||
delete this.cache[attr];
|
||||
delete this._cache[attr];
|
||||
},
|
||||
_getCache: function(attr, privateGetter){
|
||||
var cache = this.cache[attr];
|
||||
|
||||
|
||||
var cache = this._cache[attr];
|
||||
|
||||
// if not cached, we need to set it using the private getter method.
|
||||
if (cache === undefined) {
|
||||
this.cache[attr] = privateGetter.call(this);
|
||||
this._cache[attr] = privateGetter.call(this);
|
||||
}
|
||||
|
||||
return this.cache[attr];
|
||||
return this._cache[attr];
|
||||
},
|
||||
/*
|
||||
* when the logic for a cached result depends on ancestor propagation, use this
|
||||
@@ -100,6 +86,46 @@
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* clear cached canvas
|
||||
* @method
|
||||
* @memberof Kinetic.Node.prototype
|
||||
* @returns {Kinetic.Node}
|
||||
* @example
|
||||
* node.clearCache();
|
||||
*/
|
||||
clearCache: function() {
|
||||
this._cache = {};
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* cache node to improve drawing performance.
|
||||
* NOTE: if you have filters applied to your node, your shape is already cached.
|
||||
* explicitly calling cache() will override your filters.
|
||||
* @method
|
||||
* @memberof Kinetic.Node.prototype
|
||||
* @returns {Kinetic.Node}
|
||||
* @example
|
||||
* node.cache();
|
||||
*/
|
||||
cache: function(box) {
|
||||
var sceneCanvasCache = new Kinetic.SceneCanvas({
|
||||
pixelRatio: 1,
|
||||
width: box.width,
|
||||
height: box.height
|
||||
});
|
||||
var hitCanvasCache = new Kinetic.HitCanvas({
|
||||
pixelRatio: 1,
|
||||
width: box.width,
|
||||
height: box.height
|
||||
});
|
||||
|
||||
this.drawScene(sceneCanvasCache);
|
||||
this.drawHit(hitCanvasCache);
|
||||
|
||||
this._cache.sceneCanvas = sceneCanvasCache;
|
||||
this._cache.hitCanvas = hitCanvasCache;
|
||||
},
|
||||
/*
|
||||
* the default isDraggable method returns false.
|
||||
* if the DragAndDrop module is included, this is overwritten
|
||||
@@ -107,20 +133,6 @@
|
||||
isDraggable: function() {
|
||||
return false;
|
||||
},
|
||||
/*
|
||||
* when the logic for a cached result depends on descendant propagation, use this
|
||||
* method to clear self and ancestor cache
|
||||
*/
|
||||
/*
|
||||
_clearSelfAndAncestorCache: function(attr) {
|
||||
var parent = this.getParent();
|
||||
|
||||
this._clearCache(attr);
|
||||
if (parent) {
|
||||
parent._clearSelfAndAncestorCache(attr);
|
||||
}
|
||||
},
|
||||
*/
|
||||
/**
|
||||
* bind events to the node. KineticJS supports mouseover, mousemove,
|
||||
* mouseout, mouseenter, mouseleave, mousedown, mouseup, click, dblclick, touchstart, touchmove,
|
||||
@@ -954,7 +966,7 @@
|
||||
m;
|
||||
|
||||
this._eachAncestorReverse(function(node) {
|
||||
if (node.isTransformsEnabled()) {
|
||||
if (node.transformsEnabled() === 'all') {
|
||||
m = node.getTransform();
|
||||
am.multiply(m);
|
||||
}
|
||||
@@ -1339,26 +1351,6 @@
|
||||
this.drawScene();
|
||||
this.drawHit();
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* enable transforms
|
||||
* @method
|
||||
* @memberof Kinetic.Node.prototype
|
||||
* @returns {Node}
|
||||
*/
|
||||
enableTransforms: function() {
|
||||
this.setTransformsEnabled(true);
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* disable transforms
|
||||
* @method
|
||||
* @memberof Kinetic.Node.prototype
|
||||
* @returns {Node}
|
||||
*/
|
||||
disableTransforms: function() {
|
||||
this.setTransformsEnabled(false);
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1777,27 +1769,18 @@
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
Kinetic.Factory.addGetterSetter(Kinetic.Node, 'transformsEnabled', true);
|
||||
Kinetic.Factory.addGetterSetter(Kinetic.Node, 'transformsEnabled', 'all');
|
||||
|
||||
/**
|
||||
* enable/disable transforms
|
||||
* @name setTransformsEnabled
|
||||
* get/set transforms that are enabled. Can be "all", "none", or "position". The default
|
||||
* is "all"
|
||||
* @name transformsEnabled
|
||||
* @method
|
||||
* @memberof Kinetic.Node.prototype
|
||||
* @param {Boolean} enabled
|
||||
* @returns {Node}
|
||||
* @param {String} enabled
|
||||
* @returns {String}
|
||||
*/
|
||||
|
||||
/**
|
||||
* determine if transforms are enabled
|
||||
* @name getTransformsEnabled
|
||||
* @method
|
||||
* @memberof Kinetic.Node.prototype
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
Kinetic.Node.prototype.isTransformsEnabled = Kinetic.Node.prototype.getTransformsEnabled;
|
||||
|
||||
Kinetic.Collection.mapMethods([
|
||||
'on',
|
||||
'off',
|
||||
|
44
src/Shape.js
44
src/Shape.js
@@ -236,10 +236,27 @@
|
||||
var canvas = can || this.getLayer().getCanvas(),
|
||||
context = canvas.getContext(),
|
||||
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(drawFunc && this.isVisible()) {
|
||||
// if buffer canvas is needed
|
||||
if (this._useBufferCanvas()) {
|
||||
stage = this.getStage();
|
||||
@@ -252,7 +269,6 @@
|
||||
drawFunc.call(this, bufferContext);
|
||||
bufferContext.restore();
|
||||
|
||||
context.save();
|
||||
if (hasShadow) {
|
||||
context.save();
|
||||
context._applyShadow(this);
|
||||
@@ -262,11 +278,9 @@
|
||||
|
||||
context._applyOpacity(this);
|
||||
context.drawImage(bufferCanvas._canvas, 0, 0);
|
||||
context.restore();
|
||||
}
|
||||
// if buffer canvas is not needed
|
||||
else {
|
||||
context.save();
|
||||
context._applyLineJoin(this);
|
||||
context._applyAncestorTransforms(this);
|
||||
|
||||
@@ -279,25 +293,27 @@
|
||||
|
||||
context._applyOpacity(this);
|
||||
drawFunc.call(this, context);
|
||||
context.restore();
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
drawHit: function() {
|
||||
var attrs = this.getAttrs(),
|
||||
drawFunc = attrs.drawHitFunc || attrs.drawFunc,
|
||||
canvas = this.getLayer().hitCanvas,
|
||||
context = canvas.getContext();
|
||||
drawHit: function(can) {
|
||||
var canvas = can || this.getLayer().hitCanvas,
|
||||
context = canvas.getContext(),
|
||||
drawFunc = this.getDrawHitFunc() || this.getDrawFunc(),
|
||||
cachedHitCanvas = this._cache.hitCanvas;
|
||||
|
||||
if(drawFunc && this.shouldDrawHit()) {
|
||||
if(this.shouldDrawHit()) {
|
||||
context.save();
|
||||
if (cachedHitCanvas) {
|
||||
context.drawImage(cachedHitCanvas._canvas, 0, 0);
|
||||
}
|
||||
else if (drawFunc) {
|
||||
context._applyLineJoin(this);
|
||||
context._applyAncestorTransforms(this);
|
||||
drawFunc.call(this, context);
|
||||
}
|
||||
context.restore();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
@@ -114,17 +114,17 @@ suite('Node', function() {
|
||||
strokeWidth: 4
|
||||
});
|
||||
|
||||
assert.equal(circle.cache.transform, undefined);
|
||||
assert.equal(circle._cache.transform, undefined);
|
||||
|
||||
layer.add(circle);
|
||||
stage.add(layer);
|
||||
|
||||
// transform cache
|
||||
assert.notEqual(circle.cache.transform, undefined);
|
||||
assert.notEqual(circle._cache.transform, undefined);
|
||||
circle.setX(100);
|
||||
assert.equal(circle.cache.transform, undefined);
|
||||
assert.equal(circle._cache.transform, undefined);
|
||||
layer.draw();
|
||||
assert.notEqual(circle.cache.transform, undefined);
|
||||
assert.notEqual(circle._cache.transform, undefined);
|
||||
});
|
||||
|
||||
// ======================================================
|
||||
@@ -143,15 +143,15 @@ suite('Node', function() {
|
||||
stage.add(layer);
|
||||
|
||||
// visible cache
|
||||
assert.equal(circle.cache.visible, true);
|
||||
assert.equal(circle._cache.visible, true);
|
||||
circle.hide();
|
||||
assert.equal(circle.cache.visible, undefined);
|
||||
assert.equal(circle._cache.visible, undefined);
|
||||
stage.draw();
|
||||
assert.equal(circle.cache.visible, false);
|
||||
assert.equal(circle._cache.visible, false);
|
||||
circle.show();
|
||||
assert.equal(circle.cache.visible, undefined);
|
||||
assert.equal(circle._cache.visible, undefined);
|
||||
layer.draw();
|
||||
assert.equal(circle.cache.visible, true);
|
||||
assert.equal(circle._cache.visible, true);
|
||||
|
||||
});
|
||||
|
||||
@@ -171,14 +171,14 @@ suite('Node', function() {
|
||||
stage.add(layer);
|
||||
|
||||
// shadow cache
|
||||
assert.equal(circle.cache.hasShadow, false);
|
||||
assert.equal(circle._cache.hasShadow, false);
|
||||
circle.setShadowColor('red');
|
||||
circle.setShadowOffset(10);
|
||||
assert.equal(circle.cache.hasShadow, undefined);
|
||||
assert.equal(circle._cache.hasShadow, undefined);
|
||||
layer.draw();
|
||||
assert.equal(circle.cache.hasShadow, true);
|
||||
assert.equal(circle._cache.hasShadow, true);
|
||||
layer.draw();
|
||||
assert.equal(circle.cache.hasShadow, true);
|
||||
assert.equal(circle._cache.hasShadow, true);
|
||||
|
||||
});
|
||||
|
||||
@@ -198,11 +198,11 @@ suite('Node', function() {
|
||||
stage.add(layer);
|
||||
|
||||
// opacity cache
|
||||
assert.equal(circle.cache.absoluteOpacity, 1);
|
||||
assert.equal(circle._cache.absoluteOpacity, 1);
|
||||
circle.setOpacity(0.5);
|
||||
assert.equal(circle.cache.absoluteOpacity, undefined);
|
||||
assert.equal(circle._cache.absoluteOpacity, undefined);
|
||||
layer.draw();
|
||||
assert.equal(circle.cache.absoluteOpacity, 0.5);
|
||||
assert.equal(circle._cache.absoluteOpacity, 0.5);
|
||||
|
||||
});
|
||||
|
||||
@@ -226,11 +226,11 @@ suite('Node', function() {
|
||||
// prime the cache
|
||||
circle.isListening();
|
||||
|
||||
assert.equal(circle.cache.listening, true);
|
||||
assert.equal(circle._cache.listening, true);
|
||||
circle.setListening(false);
|
||||
assert.equal(circle.cache.listening, undefined);
|
||||
assert.equal(circle._cache.listening, undefined);
|
||||
circle.isListening();
|
||||
assert.equal(circle.cache.listening, false);
|
||||
assert.equal(circle._cache.listening, false);
|
||||
|
||||
});
|
||||
|
||||
@@ -251,7 +251,7 @@ suite('Node', function() {
|
||||
|
||||
// stage cache
|
||||
var st = circle.getStage();
|
||||
assert.equal(circle.cache.stage._id, stage._id);
|
||||
assert.equal(circle._cache.stage._id, stage._id);
|
||||
|
||||
});
|
||||
|
||||
@@ -2671,17 +2671,13 @@ suite('Node', function() {
|
||||
layer.add(group);
|
||||
stage.add(layer);
|
||||
|
||||
assert.equal(circle.isTransformsEnabled(), true);
|
||||
assert.equal(circle.transformsEnabled(), 'all');
|
||||
|
||||
circle.disableTransforms();
|
||||
|
||||
assert.equal(circle.isTransformsEnabled(), false);
|
||||
circle.transformsEnabled('position');
|
||||
assert.equal(circle.transformsEnabled(), 'position');
|
||||
|
||||
layer.draw();
|
||||
|
||||
circle.enableTransforms();
|
||||
|
||||
assert.equal(circle.isTransformsEnabled(), true);
|
||||
|
||||
|
||||
});
|
||||
@@ -2714,23 +2710,23 @@ suite('Node', function() {
|
||||
stage.add(layer);
|
||||
assert.equal(layer.getContext().getTrace(), 'clearRect(0,0,578,200);save();transform(1,0,0,1,400,100);beginPath();arc(0,0,40,0,6.283,false);closePath();fillStyle=green;fill();lineWidth=4;strokeStyle=black;stroke();restore();');
|
||||
|
||||
stage.disableTransforms();
|
||||
stage.transformsEnabled('none');
|
||||
layer.getContext().clearTrace();
|
||||
stage.draw();
|
||||
assert.equal(layer.getContext().getTrace(), 'clearRect(0,0,578,200);save();transform(1,0,0,1,300,100);beginPath();arc(0,0,40,0,6.283,false);closePath();fillStyle=green;fill();lineWidth=4;strokeStyle=black;stroke();restore();');
|
||||
|
||||
layer.disableTransforms();
|
||||
layer.transformsEnabled('none');
|
||||
layer.getContext().clearTrace();
|
||||
stage.draw();
|
||||
assert.equal(layer.getContext().getTrace(), 'clearRect(0,0,578,200);save();transform(1,0,0,1,200,100);beginPath();arc(0,0,40,0,6.283,false);closePath();fillStyle=green;fill();lineWidth=4;strokeStyle=black;stroke();restore();');
|
||||
|
||||
group.disableTransforms();
|
||||
group.transformsEnabled('none');
|
||||
layer.getContext().clearTrace();
|
||||
stage.draw();
|
||||
assert.equal(layer.getContext().getTrace(), 'clearRect(0,0,578,200);save();transform(1,0,0,1,100,100);beginPath();arc(0,0,40,0,6.283,false);closePath();fillStyle=green;fill();lineWidth=4;strokeStyle=black;stroke();restore();');
|
||||
|
||||
// disabling a shape transform disables all transforms but x and y. In this case, the Kinetic.Context uses translate instead of transform
|
||||
circle.disableTransforms();
|
||||
circle.transformsEnabled('position');
|
||||
layer.getContext().clearTrace();
|
||||
stage.draw();
|
||||
assert.equal(layer.getContext().getTrace(), 'clearRect(0,0,578,200);save();translate(100,100);beginPath();arc(0,0,40,0,6.283,false);closePath();fillStyle=green;fill();lineWidth=4;strokeStyle=black;stroke();restore();');
|
||||
@@ -2895,4 +2891,49 @@ suite('Node', function() {
|
||||
assert.equal(circle.position().x, 6);
|
||||
assert.equal(circle.position().y, 8);
|
||||
});
|
||||
|
||||
test('cache shape', function(){
|
||||
var stage = addStage();
|
||||
var layer = new Kinetic.Layer();
|
||||
var group = new Kinetic.Group();
|
||||
var circle = new Kinetic.Circle({
|
||||
x: 100,
|
||||
y: 100,
|
||||
radius: 70,
|
||||
fill: 'green',
|
||||
stroke: 'black',
|
||||
strokeWidth: 4,
|
||||
name: 'myCircle',
|
||||
draggable: true
|
||||
});
|
||||
|
||||
group.add(circle);
|
||||
layer.add(group);
|
||||
stage.add(layer);
|
||||
|
||||
console.log('-- before cache')
|
||||
|
||||
assert.equal(circle._cache['sceneCanvas'], undefined);
|
||||
assert.equal(circle._cache['hitCanvas'], undefined);
|
||||
|
||||
circle.cache({
|
||||
width: 100,
|
||||
height: 100
|
||||
});
|
||||
|
||||
assert.notEqual(circle._cache['sceneCanvas'], undefined);
|
||||
assert.notEqual(circle._cache['hitCanvas'], undefined);
|
||||
|
||||
|
||||
layer.draw();
|
||||
|
||||
|
||||
document.body.appendChild(circle._cache.sceneCanvas._canvas);
|
||||
document.body.appendChild(circle._cache.hitCanvas._canvas);
|
||||
|
||||
|
||||
console.log(layer.getContext().getTrace());
|
||||
|
||||
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user