From 46f71d283f66a9d86a9f6851efeed114e547b8d2 Mon Sep 17 00:00:00 2001 From: Eric Rowell Date: Fri, 15 Feb 2013 18:20:34 -0800 Subject: [PATCH] added clipping functionality to containers. Currently, the clipping function can only be applied to layers and groups. The clipping region is also subject to the containers transforms, which means that you can also create transformed clipping regions. --- Thorfile | 1 + configParams/containerParams.txt | 1 + src/Canvas.js | 9 ++++++++ src/Container.js | 36 ++++++++++++++++++++++++++++++++ src/Group.js | 1 + src/Layer.js | 1 + src/Stage.js | 1 + tests/js/unit/containerTests.js | 30 ++++++++++++++++++++++++++ 8 files changed, 80 insertions(+) create mode 100644 configParams/containerParams.txt 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,