started working on context tracing. Added first context trace unit test

This commit is contained in:
Eric Rowell 2013-09-01 01:13:52 -07:00
parent f144c67264
commit 8c3a53dc9d
6 changed files with 243 additions and 127 deletions

View File

@ -1,4 +1,11 @@
(function() { (function() {
var COMMA = ',',
OPEN_PAREN = '(',
CLOSE_PAREN = ')',
EMPTY_STRING = '',
CONTEXT_METHODS = ['clearRect', 'rect', 'restore', 'save', 'setTransform', 'transform'],
CONTEXT_PROPERTIES = ['fillStyle', 'lineWidth', 'strokeStyle'];
/** /**
* Canvas Context constructor * Canvas Context constructor
* @constructor * @constructor
@ -13,6 +20,22 @@
init: function(canvas) { init: function(canvas) {
this.canvas = canvas; this.canvas = canvas;
this._context = canvas._canvas.getContext('2d'); this._context = canvas._canvas.getContext('2d');
if (Kinetic.enableTrace) {
this.traceArr = [];
this._enableTrace();
}
},
_trace: function(str) {
var traceArr = this.traceArr,
len;
traceArr.push(str);
len = traceArr.length;
if (len >= Kinetic.traceArrMax) {
traceArr.shift();
}
}, },
/** /**
* reset canvas context transform * reset canvas context transform
@ -21,7 +44,7 @@
*/ */
reset: function() { reset: function() {
var pixelRatio = this.getCanvas().getPixelRatio(); var pixelRatio = this.getCanvas().getPixelRatio();
this._context.setTransform(1 * pixelRatio, 0, 0, 1 * pixelRatio, 0, 0); this.setTransform(1 * pixelRatio, 0, 0, 1 * pixelRatio, 0, 0);
}, },
getCanvas: function() { getCanvas: function() {
return this.canvas; return this.canvas;
@ -32,17 +55,16 @@
* @memberof Kinetic.Context.prototype * @memberof Kinetic.Context.prototype
*/ */
clear: function(clip) { clear: function(clip) {
var _context = this._context, var canvas = this.getCanvas(),
canvas = this.getCanvas(),
pos, size; pos, size;
if (clip) { if (clip) {
pos = Kinetic.Util._getXY(clip); pos = Kinetic.Util._getXY(clip);
size = Kinetic.Util._getSize(clip); size = Kinetic.Util._getSize(clip);
_context.clearRect(pos.x || 0, pos.y || 0, size.width, size.height); this.clearRect(pos.x || 0, pos.y || 0, size.width, size.height);
} }
else { else {
_context.clearRect(0, 0, canvas.getWidth(), canvas.getHeight()); this.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
} }
}, },
/** /**
@ -93,11 +115,10 @@
* @param {Function} drawFunc * @param {Function} drawFunc
*/ */
applyShadow: function(shape, drawFunc) { applyShadow: function(shape, drawFunc) {
var _context = this._context; context.save();
_context.save();
this._applyShadow(shape); this._applyShadow(shape);
drawFunc(); drawFunc();
_context.restore(); context.restore();
drawFunc(); drawFunc();
}, },
_applyLineCap: function(shape) { _applyLineCap: function(shape) {
@ -120,7 +141,7 @@
}, },
_applyAncestorTransforms: function(shape) { _applyAncestorTransforms: function(shape) {
var m = shape.getAbsoluteTransform().getMatrix(); var m = shape.getAbsoluteTransform().getMatrix();
this._context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); this.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
}, },
_clip: function(container) { _clip: function(container) {
var _context = this._context, var _context = this._context,
@ -129,14 +150,59 @@
clipWidth = container.getClipWidth(), clipWidth = container.getClipWidth(),
clipHeight = container.getClipHeight(); clipHeight = container.getClipHeight();
_context.save(); this.save();
this._applyAncestorTransforms(container); this._applyAncestorTransforms(container);
_context.beginPath(); _context.beginPath();
_context.rect(clipX, clipY, clipWidth, clipHeight); this.rect(clipX, clipY, clipWidth, clipHeight);
_context.clip(); _context.clip();
this.reset(); this.reset();
container._drawChildren(this.getCanvas()); container._drawChildren(this.getCanvas());
_context.restore(); this.restore();
},
// context pass through methods
clearRect: function(x, y, width, height) {
this._context.clearRect(x, y, width, height);
},
rect: function(x, y, width, height) {
this._context.rect(x, y, width, height);
},
restore: function() {
this._context.restore();
},
save: function() {
this._context.save();
},
setTransform: function(a, b, c, d, e, f) {
this._context.setTransform(a, b, c, d, e, f);
},
transform: function(a, b, c, d, e, f) {
this._context.transform(a, b, c, d, e, f);
},
_enableTrace: function() {
var that = this,
len = CONTEXT_METHODS.length,
n;
// methods
for (n=0; n<len; n++) {
(function(contextMethod) {
var method = that[contextMethod],
args;
that[contextMethod] = function() {
args = Array.prototype.slice.call(arguments, 0);
method.apply(that, arguments);
that._trace(contextMethod + OPEN_PAREN + args.join(COMMA) + CLOSE_PAREN);
};
})(CONTEXT_METHODS[n]);
}
// properties
len = CONTEXT_PROPERTIES.length;
for (n=0; n<len; n++) {
}
} }
}; };
@ -346,5 +412,4 @@
} }
}; };
Kinetic.Util.extend(Kinetic.HitContext, Kinetic.Context); Kinetic.Util.extend(Kinetic.HitContext, Kinetic.Context);
})(); })();

View File

@ -30,122 +30,125 @@
*/ */
var Kinetic = {}; var Kinetic = {};
(function() { (function() {
Kinetic.version = '@@version'; Kinetic = {
version: '@@version',
enableTrace: false,
traceArrMax: 100,
/**
* @namespace Filters
* @memberof Kinetic
*/
Filters: {},
/** /**
* @namespace Filters * Node constructor. Nodes are entities that can be transformed, layered,
* @memberof Kinetic * and have bound events. The stage, layers, groups, and shapes all extend Node.
*/ * @constructor
Kinetic.Filters = {}; * @memberof Kinetic
* @abstract
* @param {Object} config
* @@nodeParams
*/
Node: function(config) {
this._init(config);
},
/** /**
* Node constructor. Nodes are entities that can be transformed, layered, * Shape constructor. Shapes are primitive objects such as rectangles,
* and have bound events. The stage, layers, groups, and shapes all extend Node. * circles, text, lines, etc.
* @constructor * @constructor
* @memberof Kinetic * @memberof Kinetic
* @abstract * @augments Kinetic.Node
* @param {Object} config * @param {Object} config
* @@nodeParams * @@shapeParams
*/ * @@nodeParams
Kinetic.Node = function(config) { * @example
this._init(config); * var customShape = new Kinetic.Shape({<br>
}; * x: 5,<br>
* y: 10,<br>
* fill: 'red',<br>
* // a Kinetic.Canvas renderer is passed into the drawFunc function<br>
* drawFunc: function(canvas) {<br>
* var context = canvas.getContext();<br>
* context.beginPath();<br>
* context.moveTo(200, 50);<br>
* context.lineTo(420, 80);<br>
* context.quadraticCurveTo(300, 100, 260, 170);<br>
* context.closePath();<br>
* canvas.fillStroke(this);<br>
* }<br>
*});
*/
Shape: function(config) {
this.__init(config);
},
/** /**
* Shape constructor. Shapes are primitive objects such as rectangles, * Container constructor.&nbsp; Containers are used to contain nodes or other containers
* circles, text, lines, etc. * @constructor
* @constructor * @memberof Kinetic
* @memberof Kinetic * @augments Kinetic.Node
* @augments Kinetic.Node * @abstract
* @param {Object} config * @param {Object} config
* @@shapeParams * @@nodeParams
* @@nodeParams * @@containerParams
* @example */
* var customShape = new Kinetic.Shape({<br> Container: function(config) {
* x: 5,<br> this.__init(config);
* y: 10,<br> },
* fill: 'red',<br>
* // a Kinetic.Canvas renderer is passed into the drawFunc function<br>
* drawFunc: function(canvas) {<br>
* var context = canvas.getContext();<br>
* context.beginPath();<br>
* context.moveTo(200, 50);<br>
* context.lineTo(420, 80);<br>
* context.quadraticCurveTo(300, 100, 260, 170);<br>
* context.closePath();<br>
* canvas.fillStroke(this);<br>
* }<br>
*});
*/
Kinetic.Shape = function(config) {
this.__init(config);
};
/** /**
* Container constructor.&nbsp; Containers are used to contain nodes or other containers * Stage constructor. A stage is used to contain multiple layers
* @constructor * @constructor
* @memberof Kinetic * @memberof Kinetic
* @augments Kinetic.Node * @augments Kinetic.Container
* @abstract * @param {Object} config
* @param {Object} config * @param {String|DomElement} config.container Container id or DOM element
* @@nodeParams * @@nodeParams
* @@containerParams * @@containerParams
*/ * @example
Kinetic.Container = function(config) { * var stage = new Kinetic.Stage({<br>
this.__init(config); * width: 500,<br>
}; * height: 800,<br>
* container: 'containerId'<br>
* });
*/
Stage: function(config) {
this.___init(config);
},
/** /**
* Stage constructor. A stage is used to contain multiple layers * Layer constructor. Layers are tied to their own canvas element and are used
* @constructor * to contain groups or shapes
* @memberof Kinetic * @constructor
* @augments Kinetic.Container * @memberof Kinetic
* @param {Object} config * @augments Kinetic.Container
* @param {String|DomElement} config.container Container id or DOM element * @param {Object} config
* @@nodeParams * @param {Boolean} [config.clearBeforeDraw] set this property to false if you don't want
* @@containerParams * to clear the canvas before each layer draw. The default value is true.
* @example * @@nodeParams
* var stage = new Kinetic.Stage({<br> * @@containerParams
* width: 500,<br> * @example
* height: 800,<br> * var layer = new Kinetic.Layer();
* container: 'containerId'<br> */
* }); Layer: function(config) {
*/ this.___init(config);
Kinetic.Stage = function(config) { },
this.___init(config);
};
/** /**
* Layer constructor. Layers are tied to their own canvas element and are used * Group constructor. Groups are used to contain shapes or other groups.
* to contain groups or shapes * @constructor
* @constructor * @memberof Kinetic
* @memberof Kinetic * @augments Kinetic.Container
* @augments Kinetic.Container * @param {Object} config
* @param {Object} config * @@nodeParams
* @param {Boolean} [config.clearBeforeDraw] set this property to false if you don't want * @@containerParams
* to clear the canvas before each layer draw. The default value is true. * @example
* @@nodeParams * var group = new Kinetic.Group();
* @@containerParams */
* @example Group: function(config) {
* var layer = new Kinetic.Layer(); this.___init(config);
*/ }
Kinetic.Layer = function(config) {
this.___init(config);
};
/**
* Group constructor. Groups are used to contain shapes or other groups.
* @constructor
* @memberof Kinetic
* @augments Kinetic.Container
* @param {Object} config
* @@nodeParams
* @@containerParams
* @example
* var group = new Kinetic.Group();
*/
Kinetic.Group = function(config) {
this.___init(config);
}; };
/** /**

View File

@ -215,12 +215,12 @@
context = canvas.getContext(); context = canvas.getContext();
if(drawFunc && this.isVisible()) { if(drawFunc && this.isVisible()) {
context._context.save(); context.save();
context._applyOpacity(this); context._applyOpacity(this);
context._applyLineJoin(this); context._applyLineJoin(this);
context._applyAncestorTransforms(this); context._applyAncestorTransforms(this);
drawFunc.call(this, context); drawFunc.call(this, context);
context._context.restore(); context.restore();
} }
return this; return this;
}, },

View File

@ -36,7 +36,7 @@
if(!cornerRadius) { if(!cornerRadius) {
// simple rect - don't bother doing all that complicated maths stuff. // simple rect - don't bother doing all that complicated maths stuff.
_context.rect(0, 0, width, height); context.rect(0, 0, width, height);
} }
else { else {
// arcTo would be nicer, but browser support is patchy (Opera) // arcTo would be nicer, but browser support is patchy (Opera)

View File

@ -1,19 +1,26 @@
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Mocha Tests</title> <title>KineticJS Mocha Tests</title>
<link rel="stylesheet" href="../node_modules/mocha/mocha.css" /> <link rel="stylesheet" href="../node_modules/mocha/mocha.css" />
</head> </head>
<body> <body>
<div id="mocha"></div> <div id="mocha"></div>
<!-- used for KineticJS container -->
<div id="container"></div>
<script src="../node_modules/mocha/mocha.js"></script> <script src="../node_modules/mocha/mocha.js"></script>
<script src="../node_modules/chai/chai.js"></script> <script src="../node_modules/chai/chai.js"></script>
<script src="../dist/kinetic-dev.js"></script> <script src="../dist/kinetic-dev.js"></script>
<script> <script>
mocha.ui('tdd'); mocha.ui('tdd');
var assert = chai.assert; var assert = chai.assert;
Kinetic.enableTrace = true;
</script> </script>
<script src="unit/Util-test.js"></script> <script src="unit/Util-test.js"></script>
<script src="unit/Rect-test.js"></script>
<script> <script>
if (window.mochaPhantomJS) { mochaPhantomJS.run(); } if (window.mochaPhantomJS) { mochaPhantomJS.run(); }
else { mocha.run(); } else { mocha.run(); }

41
test/unit/Rect-test.js Normal file
View File

@ -0,0 +1,41 @@
suite('Rect', function(){
var util;
setup(function(){
});
suite('add rect to stage', function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var rect = new Kinetic.Rect({
x: 100,
y: 50,
width: 100,
height: 50,
fill: 'green',
stroke: 'blue'
});
layer.add(rect);
stage.add(layer);
test('getters', function(){
assert.equal(rect.getX(), 100);
assert.equal(rect.getY(), 50);
});
test('context trace array', function() {
var traceArr = layer.getContext().traceArr;
console.log(traceArr)
assert.equal(traceArr[0], 'clearRect(0,0,578,200)');
});
});
});