From 0da8adfb6e002cd50bedbd1fe18723ece4e6287b Mon Sep 17 00:00:00 2001 From: Eric Rowell Date: Thu, 22 Mar 2012 13:47:37 -0700 Subject: [PATCH] added Matrix.js and started integration --- Thorfile | 3 +- dist/kinetic-core.js | 215 +++++++++++++++++++----------------- dist/kinetic-core.min.js | 4 +- src/Matrix.js | 69 ++++++++++++ src/Node.js | 18 +++ src/Shape.js | 50 ++------- src/Stage.js | 75 +++---------- tests/js/functionalTests.js | 24 ++++ tests/js/unitTests.js | 33 ++++++ 9 files changed, 291 insertions(+), 200 deletions(-) create mode 100644 src/Matrix.js diff --git a/Thorfile b/Thorfile index 36156400..3394bad1 100644 --- a/Thorfile +++ b/Thorfile @@ -5,7 +5,8 @@ class Build < Thor FILES = [ "license.js", "src/GlobalObject.js", "src/Node.js", "src/Container.js", "src/Stage.js", "src/Layer.js", "src/Group.js", "src/Shape.js", "src/shapes/Rect.js", "src/shapes/Circle.js", "src/shapes/Image.js", - "src/shapes/Polygon.js", "src/shapes/RegularPolygon.js", "src/shapes/Star.js", "src/shapes/Text.js" + "src/shapes/Polygon.js", "src/shapes/RegularPolygon.js", "src/shapes/Star.js", "src/shapes/Text.js", + "src/Matrix.js" ] desc "dev", "Concatenate all the js files into /dist/kinetic-VERSION.js." diff --git a/dist/kinetic-core.js b/dist/kinetic-core.js index e6ff2443..c06b6067 100644 --- a/dist/kinetic-core.js +++ b/dist/kinetic-core.js @@ -3,7 +3,7 @@ * http://www.kineticjs.com/ * Copyright 2012, Eric Rowell * Licensed under the MIT or GPL Version 2 licenses. - * Date: Mar 21 2012 + * Date: Mar 22 2012 * * Copyright (C) 2011 - 2012 by Eric Rowell * @@ -762,6 +762,24 @@ Kinetic.Node.prototype = { getDragBounds: function() { return this.dragBounds; }, + getMatrix: function() { + var m = new Kinetic.Matrix(); + + if(this.x !== 0 || this.y !== 0) { + m.translate(this.x, this.y); + } + if(this.rotation !== 0) { + m.rotate(this.rotation); + } + if(this.scale.x !== 1 || this.scale.y !== 1) { + m.scale(this.scale.x, this.scale.y); + } + if(this.centerOffset.x !== 0 || this.centerOffset.y !== 0) { + m.translate(-1 * this.centerOffset.x, -1 * this.centerOffset.y); + } + + return m; + }, /** * initialize drag and drop */ @@ -945,6 +963,7 @@ Kinetic.Container.prototype = { * animations * @constructor * @augments Kinetic.Container + * @augments Kinetic.Node * @param {String|DomElement} cont Container id or DOM element * @param {int} width * @param {int} height @@ -991,8 +1010,9 @@ Kinetic.Stage = function(cont, width, height) { // add stage to global object Kinetic.GlobalObject.stages.push(this); - // call super constructor + // call super constructors Kinetic.Container.apply(this, []); + Kinetic.Node.apply(this, []); }; /* * Stage methods @@ -1049,48 +1069,6 @@ Kinetic.Stage.prototype = { this.backstageLayer.getCanvas().width = width; this.backstageLayer.getCanvas().height = height; }, - /** - * set stage scale. If only one parameter is passed in, then - * both scaleX and scaleY are set to the parameter - * @param {int} scaleX - * @param {int} scaleY - */ - setScale: function(scaleX, scaleY) { - var oldScaleX = this.scale.x; - var oldScaleY = this.scale.y; - - if(scaleY) { - this.scale.x = scaleX; - this.scale.y = scaleY; - } - else { - this.scale.x = scaleX; - this.scale.y = scaleX; - } - - /* - * scale all shape positions - */ - var layers = this.children; - var that = this; - function scaleChildren(children) { - for(var i = 0; i < children.length; i++) { - var child = children[i]; - child.x *= that.scale.x / oldScaleX; - child.y *= that.scale.y / oldScaleY; - if(child.children) { - scaleChildren(child.children); - } - } - } - scaleChildren(layers); - }, - /** - * get scale - */ - getScale: function() { - return this.scale; - }, /** * clear all layers */ @@ -1135,16 +1113,14 @@ Kinetic.Stage.prototype = { remove: function(layer) { // remove layer canvas from dom this.content.removeChild(layer.canvas); - this._remove(layer); }, /** - * bind event listener to stage (which is essentially - * the container DOM) + * bind event listener to container DOM element * @param {String} typesStr * @param {function} handler */ - on: function(typesStr, handler) { + onContainer: function(typesStr, handler) { var types = typesStr.split(' '); for(var n = 0; n < types.length; n++) { var baseEvent = types[n]; @@ -1376,7 +1352,7 @@ Kinetic.Stage.prototype = { * handle incoming event * @param {Event} evt */ - _handleEvent: function(evt) { + _handleStageEvent: function(evt) { var go = Kinetic.GlobalObject; if(!evt) { evt = window.event; @@ -1425,25 +1401,25 @@ Kinetic.Stage.prototype = { // desktop events this.container.addEventListener('mousedown', function(evt) { that.mouseDown = true; - that._handleEvent(evt); + that._handleStageEvent(evt); }, false); this.container.addEventListener('mousemove', function(evt) { that.mouseUp = false; that.mouseDown = false; - that._handleEvent(evt); + that._handleStageEvent(evt); }, false); this.container.addEventListener('mouseup', function(evt) { that.mouseUp = true; that.mouseDown = false; - that._handleEvent(evt); + that._handleStageEvent(evt); that.clickStart = false; }, false); this.container.addEventListener('mouseover', function(evt) { - that._handleEvent(evt); + that._handleStageEvent(evt); }, false); this.container.addEventListener('mouseout', function(evt) { @@ -1453,18 +1429,18 @@ Kinetic.Stage.prototype = { this.container.addEventListener('touchstart', function(evt) { evt.preventDefault(); that.touchStart = true; - that._handleEvent(evt); + that._handleStageEvent(evt); }, false); this.container.addEventListener('touchmove', function(evt) { evt.preventDefault(); - that._handleEvent(evt); + that._handleStageEvent(evt); }, false); this.container.addEventListener('touchend', function(evt) { evt.preventDefault(); that.touchEnd = true; - that._handleEvent(evt); + that._handleStageEvent(evt); }, false); }, /** @@ -1555,7 +1531,7 @@ Kinetic.Stage.prototype = { _prepareDrag: function() { var that = this; - this.on('mousemove touchmove', function(evt) { + this.onContainer('mousemove touchmove', function(evt) { var go = Kinetic.GlobalObject; var node = go.drag.node; if(node) { @@ -1586,7 +1562,7 @@ Kinetic.Stage.prototype = { } }, false); - this.on('mouseup touchend mouseout', function(evt) { + this.onContainer('mouseup touchend mouseout', function(evt) { that._endDrag(evt); }); }, @@ -1626,8 +1602,9 @@ Kinetic.Stage.prototype = { this.content.appendChild(this.backstageLayer.canvas); } }; -// extend Container +// Extend Container and Node Kinetic.GlobalObject.extend(Kinetic.Stage, Kinetic.Container); +Kinetic.GlobalObject.extend(Kinetic.Stage, Kinetic.Node); /////////////////////////////////////////////////////////////////////// // Layer @@ -1874,56 +1851,26 @@ Kinetic.Shape.prototype = { if(this.visible) { var stage = layer.getStage(); var context = layer.getContext(); - var family = []; + var parent = this.parent; family.unshift(this); - var parent = this.parent; - while(parent.className !== 'Stage') { + while(parent) { family.unshift(parent); parent = parent.parent; } - - // children transforms - for(var n = 0; n < family.length; n++) { - var obj = family[n]; - - context.save(); - if(obj.x !== 0 || obj.y !== 0) { - context.translate(obj.x, obj.y); - } - if(obj.centerOffset.x !== 0 || obj.centerOffset.y !== 0) { - context.translate(obj.centerOffset.x, obj.centerOffset.y); - } - if(obj.rotation !== 0) { - context.rotate(obj.rotation); - } - if(obj.scale.x !== 1 || obj.scale.y !== 1) { - context.scale(obj.scale.x, obj.scale.y); - } - if(obj.centerOffset.x !== 0 || obj.centerOffset.y !== 0) { - context.translate(-1 * obj.centerOffset.x, -1 * obj.centerOffset.y); - } - if(obj.getAbsoluteAlpha() !== 1) { - context.globalAlpha = obj.getAbsoluteAlpha(); - } - } - - // stage transform + context.save(); - if(stage && (stage.scale.x !== 1 || stage.scale.y !== 1)) { - context.scale(stage.scale.x, stage.scale.y); + for(var n = 0; n < family.length; n++) { + var node = family[n]; + var m = node.getMatrix(); + m.transformContext(context); + if(node.getAbsoluteAlpha() !== 1) { + context.globalAlpha = node.getAbsoluteAlpha(); + } } - this.tempLayer = layer; this.drawFunc.call(this); - - // children restore - for(var i = 0; i < family.length; i++) { - context.restore(); - } - - // stage restore context.restore(); } } @@ -2534,3 +2481,73 @@ Kinetic.Text.prototype = { // extend Shape Kinetic.GlobalObject.extend(Kinetic.Text, Kinetic.Shape); +/* +* Last updated November 2011 +* By Simon Sarris +* www.simonsarris.com +* sarris@acm.org +* +* Free to use and distribute at will +* So long as you are nice to people, etc +*/ + +/* +* The usage of this class was inspired by some of the work done by a forked +* project, KineticJS-Ext by Wappworks, which is based on Simon's Transform +* class. KineticJS has slightly modified the original class and added new methods +* specific for canvas. +*/ + +/** + * Matrix object + */ +Kinetic.Matrix = function() { + this.m = [1, 0, 0, 1, 0, 0]; +} + +Kinetic.Matrix.prototype = { + /** + * Apply translation + * @param {Number} x + * @param {Number} y + */ + translate: function(x, y) { + this.m[4] += this.m[0] * x + this.m[2] * y; + this.m[5] += this.m[1] * x + this.m[3] * y; + }, + /** + * Apply scale + * @param {Number} sx + * @param {Number} sy + */ + scale: function(sx, sy) { + this.m[0] *= sx; + this.m[1] *= sx; + this.m[2] *= sy; + this.m[3] *= sy; + }, + /** + * Apply rotation + * @param {Number} rad Angle in radians + */ + rotate: function(rad) { + var c = Math.cos(rad); + var s = Math.sin(rad); + var m11 = this.m[0] * c + this.m[2] * s; + var m12 = this.m[1] * c + this.m[3] * s; + var m21 = this.m[0] * -s + this.m[2] * c; + var m22 = this.m[1] * -s + this.m[3] * c; + this.m[0] = m11; + this.m[1] = m12; + this.m[2] = m21; + this.m[3] = m22; + }, + /** + * transform canvas context + */ + transformContext: function(context) { + var m = this.m; + context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); + } +}; + diff --git a/dist/kinetic-core.min.js b/dist/kinetic-core.min.js index d9658d6d..b2cebc23 100644 --- a/dist/kinetic-core.min.js +++ b/dist/kinetic-core.min.js @@ -3,7 +3,7 @@ * http://www.kineticjs.com/ * Copyright 2012, Eric Rowell * Licensed under the MIT or GPL Version 2 licenses. - * Date: Mar 21 2012 + * Date: Mar 22 2012 * * Copyright (C) 2011 - 2012 by Eric Rowell * @@ -25,4 +25,4 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -var Kinetic={};Kinetic.GlobalObject={stages:[],idCounter:0,frame:{time:0,timeDiff:0,lastTime:0},drag:{moving:!1,node:undefined,offset:{x:0,y:0}},extend:function(a,b){for(var c in b.prototype)b.prototype.hasOwnProperty(c)&&a.prototype[c]===undefined&&(a.prototype[c]=b.prototype[c])},_isaCanvasAnimating:function(){for(var a=0;a0)return!0}}return this.frame.lastTime=0,!1},_endTransition:function(){var a=this.config;for(var b in a)if(a.hasOwnProperty(b))if(a[b].x!==undefined||a[b].y!==undefined){var c=["x","y"];for(var d=0;d=h.config.duration*1e3?(this._endTransition.apply(h),this._clearTransition(h.node),h.config.callback!==undefined&&h.config.callback()):this._runTransition(h)}f&&e.draw()}}},_updateFrameObject:function(){var a=new Date,b=a.getTime();this.frame.lastTime===0?this.frame.lastTime=b:(this.frame.timeDiff=b-this.frame.lastTime,this.frame.lastTime=b,this.frame.time+=this.frame.timeDiff)},_animationLoop:function(){if(this._isaCanvasAnimating()){this._updateFrameObject(),this._runFrames();var a=this;requestAnimFrame(function(){a._animationLoop()})}},_handleAnimation:function(){var a=this;this._isaCanvasAnimating()&&a._animationLoop()}},window.requestAnimFrame=function(a){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){window.setTimeout(a,1e3/60)}}(),Kinetic.Node=function(a){this.visible=!0,this.isListening=!0,this.name=undefined,this.alpha=1,this.x=0,this.y=0,this.scale={x:1,y:1},this.rotation=0,this.centerOffset={x:0,y:0},this.eventListeners={},this.dragConstraint="none",this.dragBounds={},this._draggable=!1;if(a)for(var b in a)switch(b){case"draggable":this.draggable(a[b]);break;case"listen":this.listen(a[b]);break;case"rotationDeg":this.rotation=a[b]*Math.PI/180;break;default:this[b]=a[b]}this.centerOffset.x===undefined&&(this.centerOffset.x=0),this.centerOffset.y===undefined&&(this.centerOffset.y=0)},Kinetic.Node.prototype={on:function(a,b){var c=a.split(" ");for(var d=0;d1?g[1]:"";this.eventListeners[h]||(this.eventListeners[h]=[]),this.eventListeners[h].push({name:i,handler:b})}},off:function(a){var b=a.split(" ");for(var c=0;c1){var h=f[1];for(var i=0;i0&&(this.parent.children.splice(a,1),this.parent.children.splice(a-1,0,this),this.parent._setChildrenIndices())},moveToBottom:function(){var a=this.index;this.parent.children.splice(a,1),this.parent.children.unshift(this),this.parent._setChildrenIndices()},setZIndex:function(a){var b=this.index;this.parent.children.splice(b,1),this.parent.children.splice(a,0,this),this.parent._setChildrenIndices()},setAlpha:function(a){this.alpha=a},getAlpha:function(){return this.alpha},getAbsoluteAlpha:function(){var a=1,b=this;while(b.className!=="Stage")a*=b.alpha,b=b.parent;return a},draggable:function(a){this.draggable!==a&&(a?this._initDrag():this._dragCleanup(),this._draggable=a)},isDragging:function(){var a=Kinetic.GlobalObject;return a.drag.node!==undefined&&a.drag.node.id===this.id&&a.drag.moving},moveTo:function(a){var b=this.parent;b.children.splice(this.index,1),b._setChildrenIndices(),a.children.push(this),this.index=a.children.length-1,this.parent=a,a._setChildrenIndices(),this.name&&(b.childrenNames[this.name]=undefined,a.childrenNames[this.name]=this)},getParent:function(){return this.parent},getLayer:function(){return this.className==="Layer"?this:this.getParent().getLayer()},getStage:function(){return this.className==="Stage"?this:this.getParent().getStage()},getName:function(){return this.name},setCenterOffset:function(a,b){this.centerOffset.x=a,this.centerOffset.y=b},getCenterOffset:function(){return this.centerOffset},transitionTo:function(a){var b=this.getLayer(),c=this,d=a.duration*1e3,e={};Kinetic.GlobalObject._clearTransition(this);for(var f in a)if(a.hasOwnProperty(f)&&f!=="duration"&&f!=="easing"&&f!=="callback")if(a[f].x!==undefined||a[f].y!==undefined){e[f]={};var g=["x","y"];for(var h=0;h0)this.remove(this.children[0])},_remove:function(a){a.name!==undefined&&(this.childrenNames[a.name]=undefined),this.children.splice(a.index,1),this._setChildrenIndices(),a=undefined},_drawChildren:function(){var a=this.children;for(var b=0;b=0;d--){var e=c[d];if(e.className==="Shape"){var f=this._detectEvent(e,b);if(f)return!0}else{var f=this._traverseChildren(e,b);if(f)return!0}}return!1},_handleEvent:function(a){var b=Kinetic.GlobalObject;a||(a=window.event),this._setMousePosition(a),this._setTouchPosition(a);var c=this.backstageLayer;c.clear(),this.targetFound=!1;var d=!1;for(var e=this.children.length-1;e>=0;e--){var f=this.children[e];f.visible&&e>=0&&f.isListening&&this._traverseChildren(f,a)&&(e=-1,d=!0)}!d&&this.mouseoutShape&&(this.mouseoutShape._handleEvents("onmouseout",a),this.mouseoutShape=undefined)},_listen:function(){var a=this;this.container.addEventListener("mousedown",function(b){a.mouseDown=!0,a._handleEvent(b)},!1),this.container.addEventListener("mousemove",function(b){a.mouseUp=!1,a.mouseDown=!1,a._handleEvent(b)},!1),this.container.addEventListener("mouseup",function(b){a.mouseUp=!0,a.mouseDown=!1,a._handleEvent(b),a.clickStart=!1},!1),this.container.addEventListener("mouseover",function(b){a._handleEvent(b)},!1),this.container.addEventListener("mouseout",function(b){a.mousePos=undefined},!1),this.container.addEventListener("touchstart",function(b){b.preventDefault(),a.touchStart=!0,a._handleEvent(b)},!1),this.container.addEventListener("touchmove",function(b){b.preventDefault(),a._handleEvent(b)},!1),this.container.addEventListener("touchend",function(b){b.preventDefault(),a.touchEnd=!0,a._handleEvent(b)},!1)},_setMousePosition:function(a){var b=a.clientX-this._getContainerPosition().left+window.pageXOffset,c=a.clientY-this._getContainerPosition().top+window.pageYOffset;this.mousePos={x:b,y:c}},_setTouchPosition:function(a){if(a.touches!==undefined&&a.touches.length===1){var b=a.touches[0],c=b.clientX-this._getContainerPosition().left+window.pageXOffset,d=b.clientY-this._getContainerPosition().top+window.pageYOffset;this.touchPos={x:c,y:d}}},_getContainerPosition:function(){var a=this.container,b=0,c=0;while(a&&a.tagName!=="BODY")b+=a.offsetTop-a.scrollTop,c+=a.offsetLeft-a.scrollLeft,a=a.offsetParent;return{top:b,left:c}},_stripLayer:function(a){a.context.stroke=function(){},a.context.fill=function(){},a.context.fillRect=function(b,c,d,e){a.context.rect(b,c,d,e)},a.context.strokeRect=function(b,c,d,e){a.context.rect(b,c,d,e)},a.context.drawImage=function(){},a.context.fillText=function(){},a.context.strokeText=function(){}},_endDrag:function(a){var b=Kinetic.GlobalObject;b.drag.node&&b.drag.moving&&(b.drag.moving=!1,b.drag.node._handleEvents("ondragend",a)),b.drag.node=undefined},_prepareDrag:function(){var a=this;this.on("mousemove touchmove",function(b){var c=Kinetic.GlobalObject,d=c.drag.node;if(d){var e=a.getUserPosition(),f=d.dragConstraint,g=d.dragBounds;if(f==="none"||f==="horizontal"){var h=e.x-c.drag.offset.x;(g.left===undefined||g.lefth)&&(d.x=h)}if(f==="none"||f==="vertical"){var i=e.y-c.drag.offset.y;(g.top===undefined||g.topi)&&(d.y=i)}c.drag.node.getLayer().draw(),c.drag.moving||(c.drag.moving=!0,c.drag.node._handleEvents("ondragstart",b)),c.drag.node._handleEvents("ondragmove",b)}},!1),this.on("mouseup touchend mouseout",function(b){a._endDrag(b)})},_buildDOM:function(){this.content.style.width=this.width+"px",this.content.style.height=this.height+"px",this.content.style.position="relative",this.content.style.display="inline-block",this.content.className="kineticjs-content",this.container.appendChild(this.content),this.bufferLayer=new Kinetic.Layer,this.backstageLayer=new Kinetic.Layer,this.bufferLayer.parent=this,this.backstageLayer.parent=this,this._stripLayer(this.backstageLayer),this.bufferLayer.getCanvas().style.display="none",this.backstageLayer.getCanvas().style.display="none",this.bufferLayer.canvas.width=this.width,this.bufferLayer.canvas.height=this.height,this.content.appendChild(this.bufferLayer.canvas),this.backstageLayer.canvas.width=this.width,this.backstageLayer.canvas.height=this.height,this.content.appendChild(this.backstageLayer.canvas)}},Kinetic.GlobalObject.extend(Kinetic.Stage,Kinetic.Container),Kinetic.Layer=function(a){this.className="Layer",this.canvas=document.createElement("canvas"),this.context=this.canvas.getContext("2d"),this.canvas.style.position="absolute",this.transitions=[],this.transitionIdCounter=0,Kinetic.Container.apply(this,[]),Kinetic.Node.apply(this,[a])},Kinetic.Layer.prototype={draw:function(){this._draw()},clear:function(){var a=this.getContext(),b=this.getCanvas();a.clearRect(0,0,b.width,b.height)},getCanvas:function(){return this.canvas},getContext:function(){return this.context},add:function(a){this._add(a)},remove:function(a){this._remove(a)},_draw:function(){this.clear(),this.visible&&this._drawChildren()}},Kinetic.GlobalObject.extend(Kinetic.Layer,Kinetic.Container),Kinetic.GlobalObject.extend(Kinetic.Layer,Kinetic.Node),Kinetic.Group=function(a){this.className="Group",Kinetic.Container.apply(this,[]),Kinetic.Node.apply(this,[a])},Kinetic.Group.prototype={add:function(a){this._add(a)},remove:function(a){this._remove(a)},_draw:function(){this.visible&&this._drawChildren()}},Kinetic.GlobalObject.extend(Kinetic.Group,Kinetic.Container),Kinetic.GlobalObject.extend(Kinetic.Group,Kinetic.Node),Kinetic.Shape=function(a){this.className="Shape";if(a.stroke!==undefined||a.strokeWidth!==undefined)a.stroke===undefined?a.stroke="black":a.strokeWidth===undefined&&(a.strokeWidth=2);this.drawFunc=a.drawFunc,Kinetic.Node.apply(this,[a])},Kinetic.Shape.prototype={getContext:function(){return this.tempLayer.getContext()},getCanvas:function(){return this.tempLayer.getCanvas()},fillStroke:function(){var a=this.getContext();this.fill!==undefined&&(a.fillStyle=this.fill,a.fill()),this.stroke!==undefined&&(a.lineWidth=this.strokeWidth===undefined?1:this.strokeWidth,a.strokeStyle=this.stroke,a.stroke())},setFill:function(a){this.fill=a},getFill:function(){return this.fill},setStroke:function(a){this.stroke=a},getStroke:function(){return this.stroke},setStrokeWidth:function(a){this.strokeWidth=a},getStrokeWidth:function(){return this.strokeWidth},_draw:function(a){if(this.visible){var b=a.getStage(),c=a.getContext(),d=[];d.unshift(this);var e=this.parent;while(e.className!=="Stage")d.unshift(e),e=e.parent;for(var f=0;f0)return!0}}return this.frame.lastTime=0,!1},_endTransition:function(){var a=this.config;for(var b in a)if(a.hasOwnProperty(b))if(a[b].x!==undefined||a[b].y!==undefined){var c=["x","y"];for(var d=0;d=h.config.duration*1e3?(this._endTransition.apply(h),this._clearTransition(h.node),h.config.callback!==undefined&&h.config.callback()):this._runTransition(h)}f&&e.draw()}}},_updateFrameObject:function(){var a=new Date,b=a.getTime();this.frame.lastTime===0?this.frame.lastTime=b:(this.frame.timeDiff=b-this.frame.lastTime,this.frame.lastTime=b,this.frame.time+=this.frame.timeDiff)},_animationLoop:function(){if(this._isaCanvasAnimating()){this._updateFrameObject(),this._runFrames();var a=this;requestAnimFrame(function(){a._animationLoop()})}},_handleAnimation:function(){var a=this;this._isaCanvasAnimating()&&a._animationLoop()}},window.requestAnimFrame=function(a){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){window.setTimeout(a,1e3/60)}}(),Kinetic.Node=function(a){this.visible=!0,this.isListening=!0,this.name=undefined,this.alpha=1,this.x=0,this.y=0,this.scale={x:1,y:1},this.rotation=0,this.centerOffset={x:0,y:0},this.eventListeners={},this.dragConstraint="none",this.dragBounds={},this._draggable=!1;if(a)for(var b in a)switch(b){case"draggable":this.draggable(a[b]);break;case"listen":this.listen(a[b]);break;case"rotationDeg":this.rotation=a[b]*Math.PI/180;break;default:this[b]=a[b]}this.centerOffset.x===undefined&&(this.centerOffset.x=0),this.centerOffset.y===undefined&&(this.centerOffset.y=0)},Kinetic.Node.prototype={on:function(a,b){var c=a.split(" ");for(var d=0;d1?g[1]:"";this.eventListeners[h]||(this.eventListeners[h]=[]),this.eventListeners[h].push({name:i,handler:b})}},off:function(a){var b=a.split(" ");for(var c=0;c1){var h=f[1];for(var i=0;i0&&(this.parent.children.splice(a,1),this.parent.children.splice(a-1,0,this),this.parent._setChildrenIndices())},moveToBottom:function(){var a=this.index;this.parent.children.splice(a,1),this.parent.children.unshift(this),this.parent._setChildrenIndices()},setZIndex:function(a){var b=this.index;this.parent.children.splice(b,1),this.parent.children.splice(a,0,this),this.parent._setChildrenIndices()},setAlpha:function(a){this.alpha=a},getAlpha:function(){return this.alpha},getAbsoluteAlpha:function(){var a=1,b=this;while(b.className!=="Stage")a*=b.alpha,b=b.parent;return a},draggable:function(a){this.draggable!==a&&(a?this._initDrag():this._dragCleanup(),this._draggable=a)},isDragging:function(){var a=Kinetic.GlobalObject;return a.drag.node!==undefined&&a.drag.node.id===this.id&&a.drag.moving},moveTo:function(a){var b=this.parent;b.children.splice(this.index,1),b._setChildrenIndices(),a.children.push(this),this.index=a.children.length-1,this.parent=a,a._setChildrenIndices(),this.name&&(b.childrenNames[this.name]=undefined,a.childrenNames[this.name]=this)},getParent:function(){return this.parent},getLayer:function(){return this.className==="Layer"?this:this.getParent().getLayer()},getStage:function(){return this.className==="Stage"?this:this.getParent().getStage()},getName:function(){return this.name},setCenterOffset:function(a,b){this.centerOffset.x=a,this.centerOffset.y=b},getCenterOffset:function(){return this.centerOffset},transitionTo:function(a){var b=this.getLayer(),c=this,d=a.duration*1e3,e={};Kinetic.GlobalObject._clearTransition(this);for(var f in a)if(a.hasOwnProperty(f)&&f!=="duration"&&f!=="easing"&&f!=="callback")if(a[f].x!==undefined||a[f].y!==undefined){e[f]={};var g=["x","y"];for(var h=0;h0)this.remove(this.children[0])},_remove:function(a){a.name!==undefined&&(this.childrenNames[a.name]=undefined),this.children.splice(a.index,1),this._setChildrenIndices(),a=undefined},_drawChildren:function(){var a=this.children;for(var b=0;b=0;d--){var e=c[d];if(e.className==="Shape"){var f=this._detectEvent(e,b);if(f)return!0}else{var f=this._traverseChildren(e,b);if(f)return!0}}return!1},_handleStageEvent:function(a){var b=Kinetic.GlobalObject;a||(a=window.event),this._setMousePosition(a),this._setTouchPosition(a);var c=this.backstageLayer;c.clear(),this.targetFound=!1;var d=!1;for(var e=this.children.length-1;e>=0;e--){var f=this.children[e];f.visible&&e>=0&&f.isListening&&this._traverseChildren(f,a)&&(e=-1,d=!0)}!d&&this.mouseoutShape&&(this.mouseoutShape._handleEvents("onmouseout",a),this.mouseoutShape=undefined)},_listen:function(){var a=this;this.container.addEventListener("mousedown",function(b){a.mouseDown=!0,a._handleStageEvent(b)},!1),this.container.addEventListener("mousemove",function(b){a.mouseUp=!1,a.mouseDown=!1,a._handleStageEvent(b)},!1),this.container.addEventListener("mouseup",function(b){a.mouseUp=!0,a.mouseDown=!1,a._handleStageEvent(b),a.clickStart=!1},!1),this.container.addEventListener("mouseover",function(b){a._handleStageEvent(b)},!1),this.container.addEventListener("mouseout",function(b){a.mousePos=undefined},!1),this.container.addEventListener("touchstart",function(b){b.preventDefault(),a.touchStart=!0,a._handleStageEvent(b)},!1),this.container.addEventListener("touchmove",function(b){b.preventDefault(),a._handleStageEvent(b)},!1),this.container.addEventListener("touchend",function(b){b.preventDefault(),a.touchEnd=!0,a._handleStageEvent(b)},!1)},_setMousePosition:function(a){var b=a.clientX-this._getContainerPosition().left+window.pageXOffset,c=a.clientY-this._getContainerPosition().top+window.pageYOffset;this.mousePos={x:b,y:c}},_setTouchPosition:function(a){if(a.touches!==undefined&&a.touches.length===1){var b=a.touches[0],c=b.clientX-this._getContainerPosition().left+window.pageXOffset,d=b.clientY-this._getContainerPosition().top+window.pageYOffset;this.touchPos={x:c,y:d}}},_getContainerPosition:function(){var a=this.container,b=0,c=0;while(a&&a.tagName!=="BODY")b+=a.offsetTop-a.scrollTop,c+=a.offsetLeft-a.scrollLeft,a=a.offsetParent;return{top:b,left:c}},_stripLayer:function(a){a.context.stroke=function(){},a.context.fill=function(){},a.context.fillRect=function(b,c,d,e){a.context.rect(b,c,d,e)},a.context.strokeRect=function(b,c,d,e){a.context.rect(b,c,d,e)},a.context.drawImage=function(){},a.context.fillText=function(){},a.context.strokeText=function(){}},_endDrag:function(a){var b=Kinetic.GlobalObject;b.drag.node&&b.drag.moving&&(b.drag.moving=!1,b.drag.node._handleEvents("ondragend",a)),b.drag.node=undefined},_prepareDrag:function(){var a=this;this.onContainer("mousemove touchmove",function(b){var c=Kinetic.GlobalObject,d=c.drag.node;if(d){var e=a.getUserPosition(),f=d.dragConstraint,g=d.dragBounds;if(f==="none"||f==="horizontal"){var h=e.x-c.drag.offset.x;(g.left===undefined||g.lefth)&&(d.x=h)}if(f==="none"||f==="vertical"){var i=e.y-c.drag.offset.y;(g.top===undefined||g.topi)&&(d.y=i)}c.drag.node.getLayer().draw(),c.drag.moving||(c.drag.moving=!0,c.drag.node._handleEvents("ondragstart",b)),c.drag.node._handleEvents("ondragmove",b)}},!1),this.onContainer("mouseup touchend mouseout",function(b){a._endDrag(b)})},_buildDOM:function(){this.content.style.width=this.width+"px",this.content.style.height=this.height+"px",this.content.style.position="relative",this.content.style.display="inline-block",this.content.className="kineticjs-content",this.container.appendChild(this.content),this.bufferLayer=new Kinetic.Layer,this.backstageLayer=new Kinetic.Layer,this.bufferLayer.parent=this,this.backstageLayer.parent=this,this._stripLayer(this.backstageLayer),this.bufferLayer.getCanvas().style.display="none",this.backstageLayer.getCanvas().style.display="none",this.bufferLayer.canvas.width=this.width,this.bufferLayer.canvas.height=this.height,this.content.appendChild(this.bufferLayer.canvas),this.backstageLayer.canvas.width=this.width,this.backstageLayer.canvas.height=this.height,this.content.appendChild(this.backstageLayer.canvas)}},Kinetic.GlobalObject.extend(Kinetic.Stage,Kinetic.Container),Kinetic.GlobalObject.extend(Kinetic.Stage,Kinetic.Node),Kinetic.Layer=function(a){this.className="Layer",this.canvas=document.createElement("canvas"),this.context=this.canvas.getContext("2d"),this.canvas.style.position="absolute",this.transitions=[],this.transitionIdCounter=0,Kinetic.Container.apply(this,[]),Kinetic.Node.apply(this,[a])},Kinetic.Layer.prototype={draw:function(){this._draw()},clear:function(){var a=this.getContext(),b=this.getCanvas();a.clearRect(0,0,b.width,b.height)},getCanvas:function(){return this.canvas},getContext:function(){return this.context},add:function(a){this._add(a)},remove:function(a){this._remove(a)},_draw:function(){this.clear(),this.visible&&this._drawChildren()}},Kinetic.GlobalObject.extend(Kinetic.Layer,Kinetic.Container),Kinetic.GlobalObject.extend(Kinetic.Layer,Kinetic.Node),Kinetic.Group=function(a){this.className="Group",Kinetic.Container.apply(this,[]),Kinetic.Node.apply(this,[a])},Kinetic.Group.prototype={add:function(a){this._add(a)},remove:function(a){this._remove(a)},_draw:function(){this.visible&&this._drawChildren()}},Kinetic.GlobalObject.extend(Kinetic.Group,Kinetic.Container),Kinetic.GlobalObject.extend(Kinetic.Group,Kinetic.Node),Kinetic.Shape=function(a){this.className="Shape";if(a.stroke!==undefined||a.strokeWidth!==undefined)a.stroke===undefined?a.stroke="black":a.strokeWidth===undefined&&(a.strokeWidth=2);this.drawFunc=a.drawFunc,Kinetic.Node.apply(this,[a])},Kinetic.Shape.prototype={getContext:function(){return this.tempLayer.getContext()},getCanvas:function(){return this.tempLayer.getCanvas()},fillStroke:function(){var a=this.getContext();this.fill!==undefined&&(a.fillStyle=this.fill,a.fill()),this.stroke!==undefined&&(a.lineWidth=this.strokeWidth===undefined?1:this.strokeWidth,a.strokeStyle=this.stroke,a.stroke())},setFill:function(a){this.fill=a},getFill:function(){return this.fill},setStroke:function(a){this.stroke=a},getStroke:function(){return this.stroke},setStrokeWidth:function(a){this.strokeWidth=a},getStrokeWidth:function(){return this.strokeWidth},_draw:function(a){if(this.visible){var b=a.getStage(),c=a.getContext(),d=[],e=this.parent;d.unshift(this);while(e)d.unshift(e),e=e.parent;c.save();for(var f=0;f