From df8df63400f4291c6b81592f6b30658ff4a68848 Mon Sep 17 00:00:00 2001 From: Eric Rowell Date: Sat, 14 Apr 2012 16:27:00 -0700 Subject: [PATCH] refactored setAbsolutePosition() method and Shape _draw method --- dist/kinetic-core.js | 80 +++++++++++-------------------------- dist/kinetic-core.min.js | 4 +- src/GlobalObject.js | 1 - src/Node.js | 23 +++++------ src/Shape.js | 21 +++------- src/Stage.js | 35 ++++------------ tests/js/functionalTests.js | 33 +++++++++++++++ 7 files changed, 83 insertions(+), 114 deletions(-) diff --git a/dist/kinetic-core.js b/dist/kinetic-core.js index d07e29cd..a3f78b91 100644 --- a/dist/kinetic-core.js +++ b/dist/kinetic-core.js @@ -46,7 +46,6 @@ Kinetic.GlobalObject = { animIdCounter: 0, dragTimeInterval: 0, maxDragTimeInterval: 20, - //isChrome: navigator.userAgent.toLowerCase().indexOf('chrome') > -1, frame: { time: 0, timeDiff: 0, @@ -459,17 +458,24 @@ Kinetic.Node.prototype = { }, /** * set absolute position relative to stage + * @param {Object} pos object containing an x and + * y property */ - setAbsolutePosition: function(pos, override) { + setAbsolutePosition: function(pos) { /* - * save rotation and scale and then - * remove them from the transform + * save rotation and scale and + * then remove them from the transform */ var rot = this.attrs.rotation; var scale = { x: this.attrs.scale.x, y: this.attrs.scale.y }; + var centerOffset = { + x: this.attrs.centerOffset.x, + y: this.attrs.centerOffset.y + }; + this.attrs.rotation = 0; this.attrs.scale = { x: 1, @@ -485,16 +491,6 @@ Kinetic.Node.prototype = { y: this.attrs.y + it.getTranslation().y }; - // handle override - if(override !== undefined) { - if(override.x !== undefined) { - pos.x = override.x; - } - if(override.y !== undefined) { - pos.y = override.y; - } - } - this.setPosition(pos.x, pos.y); // restore rotation and scale @@ -1826,6 +1822,10 @@ Kinetic.Stage.prototype = { var pos = that.getUserPosition(); var dc = node.attrs.dragConstraint; var db = node.attrs.dragBounds; + var lastNodePos = { + x: node.attrs.x, + y: node.attrs.y + }; // default var newNodePos = { @@ -1833,28 +1833,6 @@ Kinetic.Stage.prototype = { y: pos.y - go.drag.offset.y }; - /* - * chrome currently has a bug that slows down drag and drop. - * For google chrome instances, dynamically set the dragTimeInterval - * to improve drag and drop performance while not effecting other browsers - */ - //if(go.isChrome) { - /* - * handle dynamice drag time interval. As the distance between - * the mouse and cursor increases, we need to increase the drag - * time interval to reduce the number of layer draws so that - * the node position can catch back up to the cursor. When the difference - * is zero, the time interval is zero. When the difference approahces - * infinity, the time interval approaches the max drag time interval - */ - /* - var dragDiffX = Math.abs(newNodePos.x - node.attrs.x); - var dragDiffY = Math.abs(newNodePos.y - node.attrs.y); - var dragDiff = Math.sqrt(Math.pow(dragDiffX, 2) + Math.pow(dragDiffY, 2)); - go.dragTimeInterval = go.maxDragTimeInterval * (dragDiff - 1) / (dragDiff + 1); - */ - //} - // bounds overrides if(db.left !== undefined && newNodePos.x < db.left) { newNodePos.x = db.left; @@ -1869,17 +1847,16 @@ Kinetic.Stage.prototype = { newNodePos.y = db.bottom; } + node.setAbsolutePosition(newNodePos); + // constraint overrides - var override = {}; if(dc === 'horizontal') { - override.y = node.attrs.y; + node.attrs.y = lastNodePos.y; } else if(dc === 'vertical') { - override.x = node.attrs.x; + node.attrs.x = lastNodePos.x; } - node.setAbsolutePosition(newNodePos, override); - go.drag.node.getLayer().draw(); if(!go.drag.moving) { @@ -2293,25 +2270,16 @@ Kinetic.Shape.prototype = { if(layer !== undefined && this.drawFunc !== undefined) { var stage = layer.getStage(); var context = layer.getContext(); - var family = []; - var parent = this.parent; - - family.unshift(this); - while(parent) { - family.unshift(parent); - parent = parent.parent; - } context.save(); - for(var n = 0; n < family.length; n++) { - var node = family[n]; - var m = node.getTransform().getMatrix(); - context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); - if(node.getAbsoluteAlpha() !== 1) { - context.globalAlpha = node.getAbsoluteAlpha(); - } + var m = this.getAbsoluteTransform().getMatrix(); + context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); + + if(this.getAbsoluteAlpha() !== 1) { + context.globalAlpha = this.getAbsoluteAlpha(); } + this.tempLayer = layer; this.drawFunc.call(this); context.restore(); diff --git a/dist/kinetic-core.min.js b/dist/kinetic-core.min.js index d4cbd645..340b8965 100644 --- a/dist/kinetic-core.min.js +++ b/dist/kinetic-core.min.js @@ -25,5 +25,5 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -var Kinetic={};Kinetic.GlobalObject={stages:[],idCounter:0,tempNodes:[],animations:[],animIdCounter:0,dragTimeInterval:0,maxDragTimeInterval:20,frame:{time:0,timeDiff:0,lastTime:0},drag:{moving:!1,node:undefined,offset:{x:0,y:0},lastDrawTime: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])},addAnimation:function(a){a.id=Kinetic.GlobalObject.animIdCounter++,this.animations.push(a)},removeAnimation:function(a){var b=this.animations;for(var c=0;c0){this._updateFrameObject(),this._runFrames();var a=this;requestAnimFrame(function(){a._animationLoop()})}else this.frame.lastTime=0},_handleAnimation:function(){var a=this;this.animations.length>0?a._animationLoop():this.frame.lastTime=0}},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.attrs===undefined&&(this.attrs={}),this.attrs.visible=!0,this.attrs.listening=!0,this.attrs.name=undefined,this.attrs.alpha=1,this.attrs.x=0,this.attrs.y=0,this.attrs.scale={x:1,y:1},this.attrs.rotation=0,this.attrs.centerOffset={x:0,y:0},this.attrs.dragConstraint="none",this.attrs.dragBounds={},this.attrs.draggable=!1,this.eventListeners={},this.setAttrs(a)},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&&f[0].getLevel()<=a&&e(f)}var a=this.getLevel(),b=this.getStage(),c=this,d=0;return c.nodeType!=="Stage"&&e(c.getStage().getChildren()),d},getLevel:function(){var a=0,b=this.parent;while(b)a++,b=b.parent;return a},setScale:function(a,b){b?(this.attrs.scale.x=a,this.attrs.scale.y=b):(this.attrs.scale.x=a,this.attrs.scale.y=a)},getScale:function(){return this.attrs.scale},setPosition:function(a,b){this.attrs.x=a,this.attrs.y=b},setX:function(a){this.attrs.x=a},setY:function(a){this.attrs.y=a},getPosition:function(){return{x:this.attrs.x,y:this.attrs.y}},getAbsolutePosition:function(){return this.getAbsoluteTransform().getTranslation()},setAbsolutePosition:function(a,b){var c=this.attrs.rotation,d={x:this.attrs.scale.x,y:this.attrs.scale.y};this.attrs.rotation=0,this.attrs.scale={x:1,y:1};var e=this.getAbsoluteTransform();e.invert(),e.translate(a.x,a.y),a={x:this.attrs.x+e.getTranslation().x,y:this.attrs.y+e.getTranslation().y},b!==undefined&&(b.x!==undefined&&(a.x=b.x),b.y!==undefined&&(a.y=b.y)),this.setPosition(a.x,a.y),this.rotate(c),this.attrs.scale={x:d.x,y:d.y}},move:function(a,b){this.attrs.x+=a,this.attrs.y+=b},setRotation:function(a){this.attrs.rotation=a},setRotationDeg:function(a){this.attrs.rotation=a*Math.PI/180},getRotation:function(){return this.attrs.rotation},getRotationDeg:function(){return this.attrs.rotation*180/Math.PI},rotate:function(a){this.attrs.rotation+=a},rotateDeg:function(a){this.attrs.rotation+=a*Math.PI/180},listen:function(a){this.attrs.listening=a},moveToTop:function(){var a=this.index;this.parent.children.splice(a,1),this.parent.children.push(this),this.parent._setChildrenIndices()},moveUp:function(){var a=this.index;this.parent.children.splice(a,1),this.parent.children.splice(a+1,0,this),this.parent._setChildrenIndices()},moveDown:function(){var a=this.index;a>0&&(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.attrs.alpha=a},getAlpha:function(){return this.attrs.alpha},getAbsoluteAlpha:function(){var a=1,b=this;while(b.nodeType!=="Stage")a*=b.attrs.alpha,b=b.parent;return a},draggable:function(a){this.attrs.draggable!==a&&(a?this._initDrag():this._dragCleanup(),this.attrs.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()},getParent:function(){return this.parent},getLayer:function(){return this.nodeType==="Layer"?this:this.getParent().getLayer()},getStage:function(){return this.nodeType==="Stage"?this:this.getParent()===undefined?undefined:this.getParent().getStage()},getName:function(){return this.attrs.name},setCenterOffset:function(a,b){this.attrs.centerOffset.x=a,this.attrs.centerOffset.y=b},getCenterOffset:function(){return this.attrs.centerOffset},transitionTo:function(a){var b=this.nodeType==="Stage"?this:this.getLayer(),c=this,d=Kinetic.GlobalObject,e=new Kinetic.Transition(this,a),f={func:function(){e.onEnterFrame()},node:b};return d.addAnimation(f),e.tweens[0].onFinished=function(){d.removeAnimation(f.id),a.callback!==undefined&&a.callback()},e.start(),d._handleAnimation(),e},setDragConstraint:function(a){this.attrs.dragConstraint=a},getDragConstraint:function(){return this.attrs.dragConstraint},setDragBounds:function(a){this.attrs.dragBounds=a},getDragBounds:function(){return this.attrs.dragBounds},getAbsoluteTransform:function(){var a=new Kinetic.Transform,b=[],c=this.parent;b.unshift(this);while(c)b.unshift(c),c=c.parent;for(var d=0;d0)this.remove(this.children[0])},_remove:function(a){if(this.children[a.index]._id==a._id){var b=this.getStage();b!==undefined&&(b._removeId(a),b._removeName(a));var c=Kinetic.GlobalObject;for(var d=0;d=0;d--){var e=c[d];if(e.attrs.listening)if(e.nodeType==="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),this.pathLayer.clear(),this.targetFound=!1;var c=!1;for(var d=this.children.length-1;d>=0;d--){var e=this.children[d];e.attrs.visible&&d>=0&&e.attrs.listening&&this._traverseChildren(e,a)&&(d=-1,c=!0)}!c&&this.mouseoutShape&&(this.mouseoutShape._handleEvents("onmouseout",a),this.mouseoutShape=undefined)},_listen:function(){var a=this;this.content.addEventListener("mousedown",function(b){a.mouseDown=!0,a._handleStageEvent(b)},!1),this.content.addEventListener("mousemove",function(b){a.mouseUp=!1,a.mouseDown=!1,a._handleStageEvent(b)},!1),this.content.addEventListener("mouseup",function(b){a.mouseUp=!0,a.mouseDown=!1,a._handleStageEvent(b),a.clickStart=!1},!1),this.content.addEventListener("mouseover",function(b){a._handleStageEvent(b)},!1),this.content.addEventListener("mouseout",function(b){var c=a.targetShape;c&&(c._handleEvents("onmouseout",b),a.targetShape=undefined),a.mousePos=undefined},!1),this.content.addEventListener("touchstart",function(b){b.preventDefault(),a.touchStart=!0,a._handleStageEvent(b)},!1),this.content.addEventListener("touchmove",function(b){b.preventDefault(),a._handleStageEvent(b)},!1),this.content.addEventListener("touchend",function(b){b.preventDefault(),a.touchEnd=!0,a._handleStageEvent(b)},!1)},_setMousePosition:function(a){var b=a.offsetX||a.clientX-this._getContentPosition().left+window.pageXOffset,c=a.offsetY||a.clientY-this._getContentPosition().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._getContentPosition().left+window.pageXOffset,d=b.clientY-this._getContentPosition().top+window.pageYOffset;this.touchPos={x:c,y:d}}},_getContentPosition:function(){var a=this.content,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}},_modifyPathContext:function(a){a.stroke=function(){},a.fill=function(){},a.fillRect=function(b,c,d,e){a.rect(b,c,d,e)},a.strokeRect=function(b,c,d,e){a.rect(b,c,d,e)},a.drawImage=function(){},a.fillText=function(){},a.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.onContent("mousemove touchmove",function(b){var c=Kinetic.GlobalObject,d=c.drag.node;if(d){var e=new Date,f=e.getTime();if(f-c.drag.lastDrawTime>c.dragTimeInterval){c.drag.lastDrawTime=f;var g=a.getUserPosition(),h=d.attrs.dragConstraint,i=d.attrs.dragBounds,j={x:g.x-c.drag.offset.x,y:g.y-c.drag.offset.y};i.left!==undefined&&j.xi.right&&(j.x=i.right),i.top!==undefined&&j.yi.bottom&&(j.y=i.bottom);var k={};h==="horizontal"?k.y=d.attrs.y:h==="vertical"&&(k.x=d.attrs.x),d.setAbsolutePosition(j,k),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.onContent("mouseup touchend mouseout",function(b){a._endDrag(b)})},_buildDOM:function(){this.content.style.width=this.attrs.width+"px",this.content.style.height=this.attrs.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({name:"bufferLayer"}),this.pathLayer=new Kinetic.Layer({name:"pathLayer"}),this.bufferLayer.parent=this,this.pathLayer.parent=this,this._modifyPathContext(this.pathLayer.context),this.bufferLayer.getCanvas().style.display="none",this.pathLayer.getCanvas().style.display="none",this.bufferLayer.canvas.width=this.attrs.width,this.bufferLayer.canvas.height=this.attrs.height,this.bufferLayer.canvas.className="kineticjs-buffer-layer",this.content.appendChild(this.bufferLayer.canvas),this.pathLayer.canvas.width=this.attrs.width,this.pathLayer.canvas.height=this.attrs.height,this.pathLayer.canvas.className="kineticjs-path-layer",this.content.appendChild(this.pathLayer.canvas)},_addId:function(a){a.attrs.id!==undefined&&(this.ids[a.attrs.id]=a)},_removeId:function(a){a.attrs.id!==undefined&&(this.ids[a.attrs.id]=undefined)},_addName:function(a){var b=a.attrs.name;b!==undefined&&(this.names[b]===undefined&&(this.names[b]=[]),this.names[b].push(a))},_removeName:function(a){if(a.attrs.name!==undefined){var b=this.names[a.attrs.name];if(b!==undefined)for(var c=0;cthis.getDuration()?this.looping?(this.rewind(a-this._duration),this.update(),this.broadcastMessage("onLooped",{target:this,type:"onLooped"})):(this._time=this._duration,this.update(),this.stop(),this.broadcastMessage("onFinished",{target:this,type:"onFinished"})):a<0?(this.rewind(),this.update()):(this._time=a,this.update())},getTime:function(){return this._time},setDuration:function(a){this._duration=a===null||a<=0?1e5:a},getDuration:function(){return this._duration},setPosition:function(a){this.prevPos=this._pos,this.propFunc(a),this._pos=a,this.broadcastMessage("onChanged",{target:this,type:"onChanged"})},getPosition:function(a){return a===undefined&&(a=this._time),this.func(a,this.begin,this._change,this._duration)},setFinish:function(a){this._change=a-this.begin},getFinish:function(){return this.begin+this._change},start:function(){this.rewind(),this.startEnterFrame(),this.broadcastMessage("onStarted",{target:this,type:"onStarted"})},rewind:function(a){this.stop(),this._time=a===undefined?0:a,this.fixTime(),this.update()},fforward:function(){this._time=this._duration,this.fixTime(),this.update()},update:function(){this.setPosition(this.getPosition(this._time))},startEnterFrame:function(){this.stopEnterFrame(),this.isPlaying=!0,this.onEnterFrame()},onEnterFrame:function(){this.isPlaying&&this.nextFrame()},nextFrame:function(){this.setTime((this.getTimer()-this._startTime)/1e3)},stop:function(){this.stopEnterFrame(),this.broadcastMessage("onStopped",{target:this,type:"onStopped"})},stopEnterFrame:function(){this.isPlaying=!1},continueTo:function(a,b){this.begin=this._pos,this.setFinish(a),this._duration!=undefined&&this.setDuration(b),this.start()},resume:function(){this.fixTime(),this.startEnterFrame(),this.broadcastMessage("onResumed",{target:this,type:"onResumed"})},yoyo:function(){this.continueTo(this.begin,this._time)},addListener:function(a){return this.removeListener(a),this._listeners.push(a)},removeListener:function(a){var b=this._listeners,c=b.length;while(c--)if(b[c]==a)return b.splice(c,1),!0;return!1},broadcastMessage:function(){var a=[];for(var b=0;b0){this._updateFrameObject(),this._runFrames();var a=this;requestAnimFrame(function(){a._animationLoop()})}else this.frame.lastTime=0},_handleAnimation:function(){var a=this;this.animations.length>0?a._animationLoop():this.frame.lastTime=0}},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.attrs===undefined&&(this.attrs={}),this.attrs.visible=!0,this.attrs.listening=!0,this.attrs.name=undefined,this.attrs.alpha=1,this.attrs.x=0,this.attrs.y=0,this.attrs.scale={x:1,y:1},this.attrs.rotation=0,this.attrs.centerOffset={x:0,y:0},this.attrs.dragConstraint="none",this.attrs.dragBounds={},this.attrs.draggable=!1,this.eventListeners={},this.setAttrs(a)},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&&f[0].getLevel()<=a&&e(f)}var a=this.getLevel(),b=this.getStage(),c=this,d=0;return c.nodeType!=="Stage"&&e(c.getStage().getChildren()),d},getLevel:function(){var a=0,b=this.parent;while(b)a++,b=b.parent;return a},setScale:function(a,b){b?(this.attrs.scale.x=a,this.attrs.scale.y=b):(this.attrs.scale.x=a,this.attrs.scale.y=a)},getScale:function(){return this.attrs.scale},setPosition:function(a,b){this.attrs.x=a,this.attrs.y=b},setX:function(a){this.attrs.x=a},setY:function(a){this.attrs.y=a},getPosition:function(){return{x:this.attrs.x,y:this.attrs.y}},getAbsolutePosition:function(){return this.getAbsoluteTransform().getTranslation()},setAbsolutePosition:function(a){var b=this.attrs.rotation,c={x:this.attrs.scale.x,y:this.attrs.scale.y},d={x:this.attrs.centerOffset.x,y:this.attrs.centerOffset.y};this.attrs.rotation=0,this.attrs.scale={x:1,y:1};var e=this.getAbsoluteTransform();e.invert(),e.translate(a.x,a.y),a={x:this.attrs.x+e.getTranslation().x,y:this.attrs.y+e.getTranslation().y},this.setPosition(a.x,a.y),this.rotate(b),this.attrs.scale={x:c.x,y:c.y}},move:function(a,b){this.attrs.x+=a,this.attrs.y+=b},setRotation:function(a){this.attrs.rotation=a},setRotationDeg:function(a){this.attrs.rotation=a*Math.PI/180},getRotation:function(){return this.attrs.rotation},getRotationDeg:function(){return this.attrs.rotation*180/Math.PI},rotate:function(a){this.attrs.rotation+=a},rotateDeg:function(a){this.attrs.rotation+=a*Math.PI/180},listen:function(a){this.attrs.listening=a},moveToTop:function(){var a=this.index;this.parent.children.splice(a,1),this.parent.children.push(this),this.parent._setChildrenIndices()},moveUp:function(){var a=this.index;this.parent.children.splice(a,1),this.parent.children.splice(a+1,0,this),this.parent._setChildrenIndices()},moveDown:function(){var a=this.index;a>0&&(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.attrs.alpha=a},getAlpha:function(){return this.attrs.alpha},getAbsoluteAlpha:function(){var a=1,b=this;while(b.nodeType!=="Stage")a*=b.attrs.alpha,b=b.parent;return a},draggable:function(a){this.attrs.draggable!==a&&(a?this._initDrag():this._dragCleanup(),this.attrs.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()},getParent:function(){return this.parent},getLayer:function(){return this.nodeType==="Layer"?this:this.getParent().getLayer()},getStage:function(){return this.nodeType==="Stage"?this:this.getParent()===undefined?undefined:this.getParent().getStage()},getName:function(){return this.attrs.name},setCenterOffset:function(a,b){this.attrs.centerOffset.x=a,this.attrs.centerOffset.y=b},getCenterOffset:function(){return this.attrs.centerOffset},transitionTo:function(a){var b=this.nodeType==="Stage"?this:this.getLayer(),c=this,d=Kinetic.GlobalObject,e=new Kinetic.Transition(this,a),f={func:function(){e.onEnterFrame()},node:b};return d.addAnimation(f),e.tweens[0].onFinished=function(){d.removeAnimation(f.id),a.callback!==undefined&&a.callback()},e.start(),d._handleAnimation(),e},setDragConstraint:function(a){this.attrs.dragConstraint=a},getDragConstraint:function(){return this.attrs.dragConstraint},setDragBounds:function(a){this.attrs.dragBounds=a},getDragBounds:function(){return this.attrs.dragBounds},getAbsoluteTransform:function(){var a=new Kinetic.Transform,b=[],c=this.parent;b.unshift(this);while(c)b.unshift(c),c=c.parent;for(var d=0;d0)this.remove(this.children[0])},_remove:function(a){if(this.children[a.index]._id==a._id){var b=this.getStage();b!==undefined&&(b._removeId(a),b._removeName(a));var c=Kinetic.GlobalObject;for(var d=0;d=0;d--){var e=c[d];if(e.attrs.listening)if(e.nodeType==="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),this.pathLayer.clear(),this.targetFound=!1;var c=!1;for(var d=this.children.length-1;d>=0;d--){var e=this.children[d];e.attrs.visible&&d>=0&&e.attrs.listening&&this._traverseChildren(e,a)&&(d=-1,c=!0)}!c&&this.mouseoutShape&&(this.mouseoutShape._handleEvents("onmouseout",a),this.mouseoutShape=undefined)},_listen:function(){var a=this;this.content.addEventListener("mousedown",function(b){a.mouseDown=!0,a._handleStageEvent(b)},!1),this.content.addEventListener("mousemove",function(b){a.mouseUp=!1,a.mouseDown=!1,a._handleStageEvent(b)},!1),this.content.addEventListener("mouseup",function(b){a.mouseUp=!0,a.mouseDown=!1,a._handleStageEvent(b),a.clickStart=!1},!1),this.content.addEventListener("mouseover",function(b){a._handleStageEvent(b)},!1),this.content.addEventListener("mouseout",function(b){var c=a.targetShape;c&&(c._handleEvents("onmouseout",b),a.targetShape=undefined),a.mousePos=undefined},!1),this.content.addEventListener("touchstart",function(b){b.preventDefault(),a.touchStart=!0,a._handleStageEvent(b)},!1),this.content.addEventListener("touchmove",function(b){b.preventDefault(),a._handleStageEvent(b)},!1),this.content.addEventListener("touchend",function(b){b.preventDefault(),a.touchEnd=!0,a._handleStageEvent(b)},!1)},_setMousePosition:function(a){var b=a.offsetX||a.clientX-this._getContentPosition().left+window.pageXOffset,c=a.offsetY||a.clientY-this._getContentPosition().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._getContentPosition().left+window.pageXOffset,d=b.clientY-this._getContentPosition().top+window.pageYOffset;this.touchPos={x:c,y:d}}},_getContentPosition:function(){var a=this.content,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}},_modifyPathContext:function(a){a.stroke=function(){},a.fill=function(){},a.fillRect=function(b,c,d,e){a.rect(b,c,d,e)},a.strokeRect=function(b,c,d,e){a.rect(b,c,d,e)},a.drawImage=function(){},a.fillText=function(){},a.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.onContent("mousemove touchmove",function(b){var c=Kinetic.GlobalObject,d=c.drag.node;if(d){var e=new Date,f=e.getTime();if(f-c.drag.lastDrawTime>c.dragTimeInterval){c.drag.lastDrawTime=f;var g=a.getUserPosition(),h=d.attrs.dragConstraint,i=d.attrs.dragBounds,j={x:d.attrs.x,y:d.attrs.y},k={x:g.x-c.drag.offset.x,y:g.y-c.drag.offset.y};i.left!==undefined&&k.xi.right&&(k.x=i.right),i.top!==undefined&&k.yi.bottom&&(k.y=i.bottom),d.setAbsolutePosition(k),h==="horizontal"?d.attrs.y=j.y:h==="vertical"&&(d.attrs.x=j.x),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.onContent("mouseup touchend mouseout",function(b){a._endDrag(b)})},_buildDOM:function(){this.content.style.width=this.attrs.width+"px",this.content.style.height=this.attrs.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({name:"bufferLayer"}),this.pathLayer=new Kinetic.Layer({name:"pathLayer"}),this.bufferLayer.parent=this,this.pathLayer.parent=this,this._modifyPathContext(this.pathLayer.context),this.bufferLayer.getCanvas().style.display="none",this.pathLayer.getCanvas().style.display="none",this.bufferLayer.canvas.width=this.attrs.width,this.bufferLayer.canvas.height=this.attrs.height,this.bufferLayer.canvas.className="kineticjs-buffer-layer",this.content.appendChild(this.bufferLayer.canvas),this.pathLayer.canvas.width=this.attrs.width,this.pathLayer.canvas.height=this.attrs.height,this.pathLayer.canvas.className="kineticjs-path-layer",this.content.appendChild(this.pathLayer.canvas)},_addId:function(a){a.attrs.id!==undefined&&(this.ids[a.attrs.id]=a)},_removeId:function(a){a.attrs.id!==undefined&&(this.ids[a.attrs.id]=undefined)},_addName:function(a){var b=a.attrs.name;b!==undefined&&(this.names[b]===undefined&&(this.names[b]=[]),this.names[b].push(a))},_removeName:function(a){if(a.attrs.name!==undefined){var b=this.names[a.attrs.name];if(b!==undefined)for(var c=0;cthis.getDuration()?this.looping?(this.rewind(a-this._duration),this.update(),this.broadcastMessage("onLooped",{target:this,type:"onLooped"})):(this._time=this._duration,this.update(),this.stop(),this.broadcastMessage("onFinished",{target:this,type:"onFinished"})):a<0?(this.rewind(),this.update()):(this._time=a,this.update())},getTime:function(){return this._time},setDuration:function(a){this._duration=a===null||a<=0?1e5:a},getDuration:function(){return this._duration},setPosition:function(a){this.prevPos=this._pos,this.propFunc(a),this._pos=a,this.broadcastMessage("onChanged",{target:this,type:"onChanged"})},getPosition:function(a){return a===undefined&&(a=this._time),this.func(a,this.begin,this._change,this._duration)},setFinish:function(a){this._change=a-this.begin},getFinish:function(){return this.begin+this._change},start:function(){this.rewind(),this.startEnterFrame(),this.broadcastMessage("onStarted",{target:this,type:"onStarted"})},rewind:function(a){this.stop(),this._time=a===undefined?0:a,this.fixTime(),this.update()},fforward:function(){this._time=this._duration,this.fixTime(),this.update()},update:function(){this.setPosition(this.getPosition(this._time))},startEnterFrame:function(){this.stopEnterFrame(),this.isPlaying=!0,this.onEnterFrame()},onEnterFrame:function(){this.isPlaying&&this.nextFrame()},nextFrame:function(){this.setTime((this.getTimer()-this._startTime)/1e3)},stop:function(){this.stopEnterFrame(),this.broadcastMessage("onStopped",{target:this,type:"onStopped"})},stopEnterFrame:function(){this.isPlaying=!1},continueTo:function(a,b){this.begin=this._pos,this.setFinish(a),this._duration!=undefined&&this.setDuration(b),this.start()},resume:function(){this.fixTime(),this.startEnterFrame(),this.broadcastMessage("onResumed",{target:this,type:"onResumed"})},yoyo:function(){this.continueTo(this.begin,this._time)},addListener:function(a){return this.removeListener(a),this._listeners.push(a)},removeListener:function(a){var b=this._listeners,c=b.length;while(c--)if(b[c]==a)return b.splice(c,1),!0;return!1},broadcastMessage:function(){var a=[];for(var b=0;b -1, frame: { time: 0, timeDiff: 0, diff --git a/src/Node.js b/src/Node.js index 891411ee..b8eada16 100644 --- a/src/Node.js +++ b/src/Node.js @@ -306,17 +306,24 @@ Kinetic.Node.prototype = { }, /** * set absolute position relative to stage + * @param {Object} pos object containing an x and + * y property */ - setAbsolutePosition: function(pos, override) { + setAbsolutePosition: function(pos) { /* - * save rotation and scale and then - * remove them from the transform + * save rotation and scale and + * then remove them from the transform */ var rot = this.attrs.rotation; var scale = { x: this.attrs.scale.x, y: this.attrs.scale.y }; + var centerOffset = { + x: this.attrs.centerOffset.x, + y: this.attrs.centerOffset.y + }; + this.attrs.rotation = 0; this.attrs.scale = { x: 1, @@ -332,16 +339,6 @@ Kinetic.Node.prototype = { y: this.attrs.y + it.getTranslation().y }; - // handle override - if(override !== undefined) { - if(override.x !== undefined) { - pos.x = override.x; - } - if(override.y !== undefined) { - pos.y = override.y; - } - } - this.setPosition(pos.x, pos.y); // restore rotation and scale diff --git a/src/Shape.js b/src/Shape.js index 16507684..896f3c6c 100644 --- a/src/Shape.js +++ b/src/Shape.js @@ -178,25 +178,16 @@ Kinetic.Shape.prototype = { if(layer !== undefined && this.drawFunc !== undefined) { var stage = layer.getStage(); var context = layer.getContext(); - var family = []; - var parent = this.parent; - - family.unshift(this); - while(parent) { - family.unshift(parent); - parent = parent.parent; - } context.save(); - for(var n = 0; n < family.length; n++) { - var node = family[n]; - var m = node.getTransform().getMatrix(); - context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); - if(node.getAbsoluteAlpha() !== 1) { - context.globalAlpha = node.getAbsoluteAlpha(); - } + var m = this.getAbsoluteTransform().getMatrix(); + context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); + + if(this.getAbsoluteAlpha() !== 1) { + context.globalAlpha = this.getAbsoluteAlpha(); } + this.tempLayer = layer; this.drawFunc.call(this); context.restore(); diff --git a/src/Stage.js b/src/Stage.js index 9b451a86..5632683a 100644 --- a/src/Stage.js +++ b/src/Stage.js @@ -717,6 +717,10 @@ Kinetic.Stage.prototype = { var pos = that.getUserPosition(); var dc = node.attrs.dragConstraint; var db = node.attrs.dragBounds; + var lastNodePos = { + x: node.attrs.x, + y: node.attrs.y + }; // default var newNodePos = { @@ -724,28 +728,6 @@ Kinetic.Stage.prototype = { y: pos.y - go.drag.offset.y }; - /* - * chrome currently has a bug that slows down drag and drop. - * For google chrome instances, dynamically set the dragTimeInterval - * to improve drag and drop performance while not effecting other browsers - */ - //if(go.isChrome) { - /* - * handle dynamice drag time interval. As the distance between - * the mouse and cursor increases, we need to increase the drag - * time interval to reduce the number of layer draws so that - * the node position can catch back up to the cursor. When the difference - * is zero, the time interval is zero. When the difference approahces - * infinity, the time interval approaches the max drag time interval - */ - /* - var dragDiffX = Math.abs(newNodePos.x - node.attrs.x); - var dragDiffY = Math.abs(newNodePos.y - node.attrs.y); - var dragDiff = Math.sqrt(Math.pow(dragDiffX, 2) + Math.pow(dragDiffY, 2)); - go.dragTimeInterval = go.maxDragTimeInterval * (dragDiff - 1) / (dragDiff + 1); - */ - //} - // bounds overrides if(db.left !== undefined && newNodePos.x < db.left) { newNodePos.x = db.left; @@ -760,17 +742,16 @@ Kinetic.Stage.prototype = { newNodePos.y = db.bottom; } + node.setAbsolutePosition(newNodePos); + // constraint overrides - var override = {}; if(dc === 'horizontal') { - override.y = node.attrs.y; + node.attrs.y = lastNodePos.y; } else if(dc === 'vertical') { - override.x = node.attrs.x; + node.attrs.x = lastNodePos.x; } - node.setAbsolutePosition(newNodePos, override); - go.drag.node.getLayer().draw(); if(!go.drag.moving) { diff --git a/tests/js/functionalTests.js b/tests/js/functionalTests.js index 9effa438..bf4f58cf 100644 --- a/tests/js/functionalTests.js +++ b/tests/js/functionalTests.js @@ -1674,6 +1674,39 @@ Test.prototype.tests = { layer.add(group); stage.add(layer); }, + 'DRAG AND DROP - translate, rotate, set center offset, and scale shape, and then drag and drop': function(containerId) { + var stage = new Kinetic.Stage({ + container: containerId, + width: 578, + height: 200 + }); + var layer = new Kinetic.Layer(); + var group = new Kinetic.Group(); + + var rect = new Kinetic.Rect({ + x: 200, + y: 200, + width: 100, + height: 50, + fill: 'red', + stroke: 'black', + strokeWidth: 4, + draggable: true, + rotationDeg: 60, + scale: { + x: 2, + y: 1 + }, + centerOffset: { + x: 50, + y: 25 + } + }); + + group.add(rect); + layer.add(group); + stage.add(layer); + }, 'STAGE - hide stage': function(containerId) { var stage = new Kinetic.Stage({ container: containerId,