diff --git a/Thorfile b/Thorfile index 6c0d7498..8fc684e7 100644 --- a/Thorfile +++ b/Thorfile @@ -146,6 +146,7 @@ class Build < Thor content.gsub!("{{version}}", version) content.sub!("{{date}}", date) content.gsub!("{{NodeParams}}", IO.read("configParams/NodeParams.txt")) + content.gsub!("{{ContainerParams}}", IO.read("configParams/ContainerParams.txt")) content.gsub!("{{ShapeParams}}", IO.read("configParams/ShapeParams.txt")) return content diff --git a/configParams/containerParams.txt b/configParams/containerParams.txt new file mode 100644 index 00000000..e9c619ea --- /dev/null +++ b/configParams/containerParams.txt @@ -0,0 +1 @@ +@param {Function} [config.clipFunc] clipping function diff --git a/src/Canvas.js b/src/Canvas.js index c6bf95c9..2ec60e73 100644 --- a/src/Canvas.js +++ b/src/Canvas.js @@ -204,6 +204,15 @@ var t = no.getTransform(), m = t.getMatrix(); context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); }, true); + }, + _clip: function(container) { + var context = this.getContext(); + context.save(); + this._applyAncestorTransforms(container); + context.beginPath(); + container.getClipFunc()(this); + context.clip(); + context.setTransform(1, 0, 0, 1, 0, 0); } }; diff --git a/src/Container.js b/src/Container.js index 5f9ad4c4..9d38f575 100644 --- a/src/Container.js +++ b/src/Container.js @@ -5,6 +5,7 @@ * @augments Kinetic.Node * @param {Object} config * {{NodeParams}} + * {{ContainerParams}} */ Kinetic.Container = function(config) { this._containerInit(config); @@ -203,21 +204,56 @@ this.drawHit(); }, drawScene: function(canvas) { + var clip = !!this.getClipFunc() && canvas; + + if (clip) { + canvas._clip(this); + } if(this.isVisible()) { var children = this.children, len = children.length; for(var n = 0; n < len; n++) { children[n].drawScene(canvas); } } + if (clip) { + canvas.getContext().restore(); + } }, drawHit: function() { + var clip = !!this.getClipFunc() && this.nodeType !== 'Stage', + hitCanvas; + + if (clip) { + hitCanvas = this.getLayer().hitCanvas; + hitCanvas._clip(this); + } if(this.isVisible() && this.isListening()) { var children = this.children, len = children.length; for(var n = 0; n < len; n++) { children[n].drawHit(); } } + if (clip) { + hitCanvas.getContext().restore(); + } } }; + Kinetic.Global.extend(Kinetic.Container, Kinetic.Node); + + // add getters setters + Kinetic.Node.addGettersSetters(Kinetic.Container, ['clipFunc']); + + /** + * set clipping function + * @name setClipFunc + * @methodOf Kinetic.Container.prototype + * @param {Number} deg + */ + + /** + * get clipping function + * @name getClipFunc + * @methodOf Kinetic.Container.prototype + */ })(); diff --git a/src/Group.js b/src/Group.js index 7877419e..35427e00 100644 --- a/src/Group.js +++ b/src/Group.js @@ -5,6 +5,7 @@ * @augments Kinetic.Container * @param {Object} config * {{NodeParams}} + * {{ContainerParams}} */ Kinetic.Group = function(config) { this._initGroup(config); diff --git a/src/Layer.js b/src/Layer.js index 482043a7..4617a551 100644 --- a/src/Layer.js +++ b/src/Layer.js @@ -8,6 +8,7 @@ * @param {Boolean} [config.clearBeforeDraw] set this property to false if you don't want * to clear the canvas before each layer draw. The default value is true. * {{NodeParams}} + * {{ContainerParams}} */ Kinetic.Layer = function(config) { this._initLayer(config); diff --git a/src/Stage.js b/src/Stage.js index 681006c9..cf2b1ce1 100644 --- a/src/Stage.js +++ b/src/Stage.js @@ -6,6 +6,7 @@ * @param {Object} config * @param {String|DomElement} config.container Container id or DOM element * {{NodeParams}} + * {{ContainerParams}} */ Kinetic.Stage = function(config) { this._initStage(config); diff --git a/tests/js/unit/containerTests.js b/tests/js/unit/containerTests.js index 53d5e150..ef8a1e21 100644 --- a/tests/js/unit/containerTests.js +++ b/tests/js/unit/containerTests.js @@ -1,4 +1,34 @@ Test.Modules.CONTAINER = { + 'use clipping function': function(containerId) { + var stage = new Kinetic.Stage({ + container: containerId, + width: 578, + height: 200, + draggable: true + }); + var layer = new Kinetic.Layer({ + clipFunc: function(canvas) { + var context = canvas.getContext(); + context.rect(0, 0, 400, 100); + } + }); + var group = new Kinetic.Group(); + var circle = new Kinetic.Circle({ + x: stage.getWidth() / 2, + y: stage.getHeight() / 2, + radius: 70, + fill: 'green', + stroke: 'black', + strokeWidth: 4, + name: 'myCircle', + draggable: true + }); + + stage.add(layer); + layer.add(group); + group.add(circle); + layer.draw(); + }, 'add layer then group then shape': function(containerId) { var stage = new Kinetic.Stage({ container: containerId,