From 0da8adfb6e002cd50bedbd1fe18723ece4e6287b Mon Sep 17 00:00:00 2001 From: Eric Rowell Date: Thu, 22 Mar 2012 13:47:37 -0700 Subject: [PATCH 1/3] 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 Date: Thu, 22 Mar 2012 23:17:52 -0700 Subject: [PATCH 2/3] changed Stage constructor to accept a config object. Now that Stage is a node, every KineticJS object requires the same config object which bubbles up through the parent classes --- dist/kinetic-core.js | 26 +-- dist/kinetic-core.min.js | 2 +- src/Node.js | 8 - src/Stage.js | 18 +- tests/js/functionalTests.js | 234 +++++++++++++++++++++----- tests/js/unitTests.js | 323 +++++++++++++++++++++++++++++------- 6 files changed, 489 insertions(+), 122 deletions(-) diff --git a/dist/kinetic-core.js b/dist/kinetic-core.js index c06b6067..a887fabd 100644 --- a/dist/kinetic-core.js +++ b/dist/kinetic-core.js @@ -296,14 +296,6 @@ Kinetic.Node = function(config) { } } } - - // overrides - if(this.centerOffset.x === undefined) { - this.centerOffset.x = 0; - } - if(this.centerOffset.y === undefined) { - this.centerOffset.y = 0; - } }; /* * Node methods @@ -968,13 +960,21 @@ Kinetic.Container.prototype = { * @param {int} width * @param {int} height */ -Kinetic.Stage = function(cont, width, height) { +Kinetic.Stage = function(config) { + /* + * if container is a string, assume it's an id for + * a DOM element + */ + if(typeof config.container === 'string') { + config.container = document.getElementById(config.container); + } + this.className = 'Stage'; - this.container = typeof cont === 'string' ? document.getElementById(cont) : cont; + this.container = config.container; this.content = document.createElement('div'); - this.width = width; - this.height = height; + this.width = config.width; + this.height = config.height; this.scale = { x: 1, y: 1 @@ -1012,7 +1012,7 @@ Kinetic.Stage = function(cont, width, height) { // call super constructors Kinetic.Container.apply(this, []); - Kinetic.Node.apply(this, []); + Kinetic.Node.apply(this, [config]); }; /* * Stage methods diff --git a/dist/kinetic-core.min.js b/dist/kinetic-core.min.js index b2cebc23..54cafaa3 100644 --- a/dist/kinetic-core.min.js +++ b/dist/kinetic-core.min.js @@ -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},_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;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]}},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 Date: Fri, 23 Mar 2012 23:39:54 -0700 Subject: [PATCH 3/3] finished matrix integration. the stage, layers, groups, and nodes can be transformed in anyway, and drag and drop on any of these nodes now works great regardless of parent node transforms --- dist/kinetic-core.js | 113 ++++++++++++++++++++++++++++++------ src/GlobalObject.js | 4 ++ src/Layer.js | 11 +++- src/Matrix.js | 41 +++++++++++-- src/Node.js | 33 +++++++++++ src/Shape.js | 7 ++- src/Stage.js | 15 +++-- tests/js/functionalTests.js | 19 +++--- 8 files changed, 197 insertions(+), 46 deletions(-) diff --git a/dist/kinetic-core.js b/dist/kinetic-core.js index a887fabd..09263c43 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 22 2012 + * Date: Mar 23 2012 * * Copyright (C) 2011 - 2012 by Eric Rowell * @@ -52,6 +52,10 @@ Kinetic.GlobalObject = { offset: { x: 0, y: 0 + }, + start: { + x: 0, + y: 0 } }, extend: function(obj1, obj2) { @@ -754,6 +758,35 @@ Kinetic.Node.prototype = { getDragBounds: function() { return this.dragBounds; }, + /** + * get matrix transform of the node while taking into + * account the matrix transforms of its parents + */ + getAbsoluteMatrix: function() { + // absolute matrix + var am = new Kinetic.Matrix(); + + var family = []; + var parent = this.parent; + + family.unshift(this); + while(parent) { + family.unshift(parent); + parent = parent.parent; + } + + for(var n = 0; n < family.length; n++) { + var node = family[n]; + var m = node.getMatrix(); + am.multiply(m); + } + + return am; + }, + /** + * get matrix transform of the node while not taking + * into account the matrix transforms of its parents + */ getMatrix: function() { var m = new Kinetic.Matrix(); @@ -783,9 +816,13 @@ Kinetic.Node.prototype = { var pos = stage.getUserPosition(); if(pos) { + var m = that.getMatrix().getTranslation(); + var am = that.getAbsoluteMatrix().getTranslation(); go.drag.node = that; go.drag.offset.x = pos.x - that.x; go.drag.offset.y = pos.y - that.y; + go.drag.start.x = m.x - am.x; + go.drag.start.y = m.y - am.y; } }); }, @@ -965,7 +1002,7 @@ Kinetic.Stage = function(config) { * if container is a string, assume it's an id for * a DOM element */ - if(typeof config.container === 'string') { + if( typeof config.container === 'string') { config.container = document.getElementById(config.container); } @@ -1536,18 +1573,21 @@ Kinetic.Stage.prototype = { var node = go.drag.node; if(node) { var pos = that.getUserPosition(); - var ds = node.dragConstraint; + var dc = node.dragConstraint; var db = node.dragBounds; - if(ds === 'none' || ds === 'horizontal') { + var m = node.getMatrix().getTranslation(); + var am = node.getAbsoluteMatrix().getTranslation(); + + if(dc === 'none' || dc === 'horizontal') { var newX = pos.x - go.drag.offset.x; if((db.left === undefined || db.left < newX) && (db.right === undefined || db.right > newX)) { - node.x = newX; + node.x = newX + m.x - (am.x + go.drag.start.x); } } - if(ds === 'none' || ds === 'vertical') { + if(dc === 'none' || dc === 'vertical') { var newY = pos.y - go.drag.offset.y; if((db.top === undefined || db.top < newY) && (db.bottom === undefined || db.bottom > newY)) { - node.y = newY; + node.y = newY + m.y - (am.y + go.drag.start.y); } } go.drag.node.getLayer().draw(); @@ -1634,13 +1674,17 @@ Kinetic.Layer = function(config) { */ Kinetic.Layer.prototype = { /** - * public draw children + * draw children nodes. this includes any groups + * or shapes */ draw: function() { this._draw(); }, /** - * clear layer + * clears the canvas context tied to the layer. Clearing + * a layer does not remove its children. The nodes within + * the layer will be redrawn whenever the .draw() method + * is used again. */ clear: function() { var context = this.getContext(); @@ -1660,7 +1704,8 @@ Kinetic.Layer.prototype = { return this.context; }, /** - * add node to layer + * add a node to the layer. New nodes are always + * placed at the top. * @param {Node} node */ add: function(child) { @@ -1859,12 +1904,13 @@ Kinetic.Shape.prototype = { family.unshift(parent); parent = parent.parent; } - + context.save(); for(var n = 0; n < family.length; n++) { var node = family[n]; - var m = node.getMatrix(); - m.transformContext(context); + var m = node.getMatrix().toArray(); + context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); + if(node.getAbsoluteAlpha() !== 1) { context.globalAlpha = node.getAbsoluteAlpha(); } @@ -2494,8 +2540,7 @@ Kinetic.GlobalObject.extend(Kinetic.Text, Kinetic.Shape); /* * 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. +* class. */ /** @@ -2543,11 +2588,41 @@ Kinetic.Matrix.prototype = { this.m[3] = m22; }, /** - * transform canvas context + * Returns the translation + * @returns {Object} 2D point(x, y) */ - transformContext: function(context) { - var m = this.m; - context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); + getTranslation: function() { + return { + x: this.m[4], + y: this.m[5] + }; + }, + /** + * Transform multiplication + * @param {Kinetic.Matrix} matrix + */ + multiply: function(matrix) { + var m11 = this.m[0] * matrix.m[0] + this.m[2] * matrix.m[1]; + var m12 = this.m[1] * matrix.m[0] + this.m[3] * matrix.m[1]; + + var m21 = this.m[0] * matrix.m[2] + this.m[2] * matrix.m[3]; + var m22 = this.m[1] * matrix.m[2] + this.m[3] * matrix.m[3]; + + var dx = this.m[0] * matrix.m[4] + this.m[2] * matrix.m[5] + this.m[4]; + var dy = this.m[1] * matrix.m[4] + this.m[3] * matrix.m[5] + this.m[5]; + + this.m[0] = m11; + this.m[1] = m12; + this.m[2] = m21; + this.m[3] = m22; + this.m[4] = dx; + this.m[5] = dy; + }, + /** + * return matrix as array + */ + toArray: function() { + return this.m; } }; diff --git a/src/GlobalObject.js b/src/GlobalObject.js index 9d3a15d2..dfe17083 100644 --- a/src/GlobalObject.js +++ b/src/GlobalObject.js @@ -24,6 +24,10 @@ Kinetic.GlobalObject = { offset: { x: 0, y: 0 + }, + start: { + x: 0, + y: 0 } }, extend: function(obj1, obj2) { diff --git a/src/Layer.js b/src/Layer.js index 063a1662..12b0277a 100644 --- a/src/Layer.js +++ b/src/Layer.js @@ -26,13 +26,17 @@ Kinetic.Layer = function(config) { */ Kinetic.Layer.prototype = { /** - * public draw children + * draw children nodes. this includes any groups + * or shapes */ draw: function() { this._draw(); }, /** - * clear layer + * clears the canvas context tied to the layer. Clearing + * a layer does not remove its children. The nodes within + * the layer will be redrawn whenever the .draw() method + * is used again. */ clear: function() { var context = this.getContext(); @@ -52,7 +56,8 @@ Kinetic.Layer.prototype = { return this.context; }, /** - * add node to layer + * add a node to the layer. New nodes are always + * placed at the top. * @param {Node} node */ add: function(child) { diff --git a/src/Matrix.js b/src/Matrix.js index 1fb50e9a..facbd38a 100644 --- a/src/Matrix.js +++ b/src/Matrix.js @@ -11,8 +11,7 @@ /* * 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. +* class. */ /** @@ -60,10 +59,40 @@ Kinetic.Matrix.prototype = { this.m[3] = m22; }, /** - * transform canvas context + * Returns the translation + * @returns {Object} 2D point(x, y) */ - transformContext: function(context) { - var m = this.m; - context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); + getTranslation: function() { + return { + x: this.m[4], + y: this.m[5] + }; + }, + /** + * Transform multiplication + * @param {Kinetic.Matrix} matrix + */ + multiply: function(matrix) { + var m11 = this.m[0] * matrix.m[0] + this.m[2] * matrix.m[1]; + var m12 = this.m[1] * matrix.m[0] + this.m[3] * matrix.m[1]; + + var m21 = this.m[0] * matrix.m[2] + this.m[2] * matrix.m[3]; + var m22 = this.m[1] * matrix.m[2] + this.m[3] * matrix.m[3]; + + var dx = this.m[0] * matrix.m[4] + this.m[2] * matrix.m[5] + this.m[4]; + var dy = this.m[1] * matrix.m[4] + this.m[3] * matrix.m[5] + this.m[5]; + + this.m[0] = m11; + this.m[1] = m12; + this.m[2] = m21; + this.m[3] = m22; + this.m[4] = dx; + this.m[5] = dy; + }, + /** + * return matrix as array + */ + toArray: function() { + return this.m; } }; diff --git a/src/Node.js b/src/Node.js index d326a193..88e9fb5b 100644 --- a/src/Node.js +++ b/src/Node.js @@ -507,6 +507,35 @@ Kinetic.Node.prototype = { getDragBounds: function() { return this.dragBounds; }, + /** + * get matrix transform of the node while taking into + * account the matrix transforms of its parents + */ + getAbsoluteMatrix: function() { + // absolute matrix + var am = new Kinetic.Matrix(); + + var family = []; + var parent = this.parent; + + family.unshift(this); + while(parent) { + family.unshift(parent); + parent = parent.parent; + } + + for(var n = 0; n < family.length; n++) { + var node = family[n]; + var m = node.getMatrix(); + am.multiply(m); + } + + return am; + }, + /** + * get matrix transform of the node while not taking + * into account the matrix transforms of its parents + */ getMatrix: function() { var m = new Kinetic.Matrix(); @@ -536,9 +565,13 @@ Kinetic.Node.prototype = { var pos = stage.getUserPosition(); if(pos) { + var m = that.getMatrix().getTranslation(); + var am = that.getAbsoluteMatrix().getTranslation(); go.drag.node = that; go.drag.offset.x = pos.x - that.x; go.drag.offset.y = pos.y - that.y; + go.drag.start.x = m.x - am.x; + go.drag.start.y = m.y - am.y; } }); }, diff --git a/src/Shape.js b/src/Shape.js index 7504a163..0b550cdd 100644 --- a/src/Shape.js +++ b/src/Shape.js @@ -120,12 +120,13 @@ Kinetic.Shape.prototype = { family.unshift(parent); parent = parent.parent; } - + context.save(); for(var n = 0; n < family.length; n++) { var node = family[n]; - var m = node.getMatrix(); - m.transformContext(context); + var m = node.getMatrix().toArray(); + context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); + if(node.getAbsoluteAlpha() !== 1) { context.globalAlpha = node.getAbsoluteAlpha(); } diff --git a/src/Stage.js b/src/Stage.js index 055d2f8e..1b8ae494 100644 --- a/src/Stage.js +++ b/src/Stage.js @@ -16,7 +16,7 @@ Kinetic.Stage = function(config) { * if container is a string, assume it's an id for * a DOM element */ - if(typeof config.container === 'string') { + if( typeof config.container === 'string') { config.container = document.getElementById(config.container); } @@ -587,18 +587,21 @@ Kinetic.Stage.prototype = { var node = go.drag.node; if(node) { var pos = that.getUserPosition(); - var ds = node.dragConstraint; + var dc = node.dragConstraint; var db = node.dragBounds; - if(ds === 'none' || ds === 'horizontal') { + var m = node.getMatrix().getTranslation(); + var am = node.getAbsoluteMatrix().getTranslation(); + + if(dc === 'none' || dc === 'horizontal') { var newX = pos.x - go.drag.offset.x; if((db.left === undefined || db.left < newX) && (db.right === undefined || db.right > newX)) { - node.x = newX; + node.x = newX + m.x - (am.x + go.drag.start.x); } } - if(ds === 'none' || ds === 'vertical') { + if(dc === 'none' || dc === 'vertical') { var newY = pos.y - go.drag.offset.y; if((db.top === undefined || db.top < newY) && (db.bottom === undefined || db.bottom > newY)) { - node.y = newY; + node.y = newY + m.y - (am.y + go.drag.start.y); } } go.drag.node.getLayer().draw(); diff --git a/tests/js/functionalTests.js b/tests/js/functionalTests.js index 5573581e..a2623643 100644 --- a/tests/js/functionalTests.js +++ b/tests/js/functionalTests.js @@ -979,27 +979,28 @@ Test.prototype.tests = { circle.draggable(false); }, - 'DRAG AND DROP - scale stage after add layer then drag and drop shape': function(containerId) { + 'DRAG AND DROP - scale and rotate stage after add layer then drag and drop shape': function(containerId) { var stage = new Kinetic.Stage({ container: containerId, width: 578, height: 200 }); var layer = new Kinetic.Layer(); - var circle = new Kinetic.Circle({ - x: stage.width / 2, - y: stage.height / 2, - radius: 70, + var rect = new Kinetic.Rect({ + x: 200, + y: 80, + width: 100, + height: 50, fill: 'red', stroke: 'black', - strokeWidth: 4 + strokeWidth: 4, + draggable: true }); - circle.draggable(true); - - layer.add(circle); + layer.add(rect); stage.add(layer); + stage.rotateDeg(20); stage.setScale(0.5); stage.draw();