drag and drop operatons now dynamically generate a temporary top layer for high performance drag and drop. When completed, the top layer is removed. Also cleaned up a bit of drag and drop logic

This commit is contained in:
Eric Rowell 2012-12-30 23:14:23 -08:00
parent 36584a3ce2
commit 7ba40a6a68
7 changed files with 130 additions and 81 deletions

View File

@ -31,7 +31,6 @@
this.frame.timeDiff = 0; this.frame.timeDiff = 0;
this.frame.lastTime = new Date().getTime(); this.frame.lastTime = new Date().getTime();
Kinetic.Animation._addAnimation(this); Kinetic.Animation._addAnimation(this);
Kinetic.Animation._handleAnimation();
}, },
/** /**
* stop animation * stop animation
@ -59,6 +58,7 @@
Kinetic.Animation._addAnimation = function(anim) { Kinetic.Animation._addAnimation = function(anim) {
this.animations.push(anim); this.animations.push(anim);
this._handleAnimation();
}; };
Kinetic.Animation._removeAnimation = function(anim) { Kinetic.Animation._removeAnimation = function(anim) {
var id = anim.id; var id = anim.id;

View File

@ -150,8 +150,6 @@
/** /**
* apply shadow * apply shadow
* @name applyShadow * @name applyShadow
* @param {CanvasContext} context
* @param {Function} func draw function
* @methodOf Kinetic.Canvas.prototype * @methodOf Kinetic.Canvas.prototype
* @param {Kinetic.Shape} shape * @param {Kinetic.Shape} shape
* @param {Function} drawFunc * @param {Function} drawFunc
@ -194,6 +192,13 @@
pixelRatio = 1 / pixelRatio; pixelRatio = 1 / pixelRatio;
this.getContext().scale(pixelRatio, pixelRatio); this.getContext().scale(pixelRatio, pixelRatio);
} }
},
_applyAncestorTransforms: function(node) {
var context = this.context;
node.eachAncestorReverse(function(no) {
var t = no.getTransform(), m = t.getMatrix();
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
});
} }
}; };

View File

@ -5,12 +5,74 @@
offset: { offset: {
x: 0, x: 0,
y: 0 y: 0
},
prevParent: null,
topLayer: null
};
Kinetic.Node.prototype._startDrag = function() {
var dd = Kinetic.DD;
var stage = this.getStage();
var pos = stage.getUserPosition();
if(pos) {
var m = this.getTransform().getTranslation(), ap = this.getAbsolutePosition(), nodeType = this.nodeType;
dd.node = this;
dd.offset.x = pos.x - ap.x;
dd.offset.y = pos.y - ap.y;
/*
* if dragging and dropping the stage,
* draw all of the layers
*/
if(nodeType === 'Stage') {
dd.anim.node = this;
}
else {
/*
* if node type is a group or shape, create a top layer,
* and move the node to the top layer
*/
if(nodeType === 'Group' || nodeType === 'Shape') {
var lastContainer = null;
dd.prevParent = this.getParent();
// re-construct node tree
this.eachAncestorReverse(function(node) {
if(node.nodeType === 'Layer') {
dd.topLayer = new Kinetic.Layer({
x: node.getX(),
y: node.getY(),
scale: node.getScale(),
rotation: node.getRotation()
});
lastContainer = dd.topLayer;
stage.add(dd.topLayer);
}
else if(node.nodeType === 'Group') {
var group = new Kinetic.Group({
x: node.getX(),
y: node.getY(),
scale: node.getScale(),
rotation: node.getRotation()
});
lastContainer.add(group);
lastContainer = group;
}
});
this.moveTo(lastContainer);
dd.prevParent.getLayer().draw();
}
dd.anim.node = this.getLayer();
}
dd.anim.start();
} }
}; };
Kinetic.DD._drag = function(evt) {
Kinetic.DD._startDrag = function(evt) { var dd = Kinetic.DD, node = dd.node;
var dd = Kinetic.DD;
var node = dd.node;
if(node) { if(node) {
var pos = node.getStage().getUserPosition(); var pos = node.getStage().getUserPosition();
@ -40,14 +102,21 @@
} }
}; };
Kinetic.DD._endDrag = function(evt) { Kinetic.DD._endDrag = function(evt) {
var dd = Kinetic.DD; var dd = Kinetic.DD, node = dd.node;
var node = dd.node;
if(node) { if(node) {
var nodeType = node.nodeType;
node.setListening(true); node.setListening(true);
if(node.nodeType === 'Stage') { if(nodeType === 'Stage') {
node.draw(); node.draw();
} }
else { else {
if(nodeType === 'Group' || nodeType === 'Shape') {
node.moveTo(dd.prevParent);
dd.topLayer.remove();
dd.prevParent = null;
dd.topLayer = null;
}
node.getLayer().draw(); node.getLayer().draw();
} }
@ -90,37 +159,9 @@
Kinetic.Node.prototype._listenDrag = function() { Kinetic.Node.prototype._listenDrag = function() {
this._dragCleanup(); this._dragCleanup();
var that = this; this.on('mousedown.kinetic touchstart.kinetic', this._startDrag);
this.on('mousedown.kinetic touchstart.kinetic', function(evt) {
that._initDrag();
});
}; };
Kinetic.Node.prototype._initDrag = function() {
var dd = Kinetic.DD;
var stage = this.getStage();
var pos = stage.getUserPosition();
if(pos) {
var m = this.getTransform().getTranslation();
var am = this.getAbsoluteTransform().getTranslation();
var ap = this.getAbsolutePosition();
dd.node = this;
dd.offset.x = pos.x - ap.x;
dd.offset.y = pos.y - ap.y;
/*
* if dragging and dropping the stage,
* draw all of the layers
*/
if(this.nodeType === 'Stage') {
dd.anim.node = this;
}
else {
dd.anim.node = this.getLayer();
}
dd.anim.start();
}
};
Kinetic.Node.prototype._dragChange = function() { Kinetic.Node.prototype._dragChange = function() {
if(this.attrs.draggable) { if(this.attrs.draggable) {
this._listenDrag(); this._listenDrag();
@ -145,7 +186,6 @@
this.off('mousedown.kinetic'); this.off('mousedown.kinetic');
this.off('touchstart.kinetic'); this.off('touchstart.kinetic');
}; };
/** /**
* get draggable. Alias of getDraggable() * get draggable. Alias of getDraggable()
* @name isDraggable * @name isDraggable

View File

@ -436,6 +436,42 @@
getRotationDeg: function() { getRotationDeg: function() {
return Kinetic.Type._radToDeg(this.getRotation()); return Kinetic.Type._radToDeg(this.getRotation());
}, },
/**
* iterate through ancestors in reverse
* @name eachAncestorReverse
* @methodOf Kinetic.Node.prototype
* @param {Function} func function is passed two arguments, a node and
* the iterator integer
*/
eachAncestorReverse: function(func) {
var family = [], parent = this.getParent();
// build family by traversing ancestors
family.unshift(this);
while(parent) {
family.unshift(parent);
parent = parent.parent;
}
var len = family.length;
for(var n = 0; n < len; n++) {
func(family[n], n);
}
},
/**
* iterate through ancestors
* @name eachAncestor
* @methodOf Kinetic.Node.prototype
* @param {Function} func function is passed two arguments, a node and
* the iterator integer
*/
eachAncestor: function(func) {
var family = [], parent = this.getParent(), n = 0;
while(parent) {
func(parent, n++);
parent = parent.parent;
}
},
/** /**
* set rotation in degrees * set rotation in degrees
* @name setRotationDeg * @name setRotationDeg

View File

@ -205,23 +205,11 @@
var attrs = this.attrs, drawFunc = attrs.drawFunc, canvas = canvas || this.getLayer().getCanvas(), context = canvas.getContext(); var attrs = this.attrs, drawFunc = attrs.drawFunc, canvas = canvas || this.getLayer().getCanvas(), context = canvas.getContext();
if(drawFunc && this.isVisible()) { if(drawFunc && this.isVisible()) {
var stage = this.getStage(), family = [], parent = this.parent;
family.unshift(this);
while(parent) {
family.unshift(parent);
parent = parent.parent;
}
context.save(); context.save();
canvas._handlePixelRatio(); canvas._handlePixelRatio();
canvas._applyOpacity(this); canvas._applyOpacity(this);
canvas._applyLineJoin(this); canvas._applyLineJoin(this);
var len = family.length; canvas._applyAncestorTransforms(this);
for(var n = 0; n < len; n++) {
var node = family[n], t = node.getTransform(), m = t.getMatrix();
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
}
drawFunc.call(this, canvas); drawFunc.call(this, canvas);
context.restore(); context.restore();
@ -231,21 +219,9 @@
var attrs = this.attrs, drawFunc = attrs.drawHitFunc || attrs.drawFunc, canvas = this.getLayer().hitCanvas, context = canvas.getContext(); var attrs = this.attrs, drawFunc = attrs.drawHitFunc || attrs.drawFunc, canvas = this.getLayer().hitCanvas, context = canvas.getContext();
if(drawFunc && this.isVisible() && this.isListening()) { if(drawFunc && this.isVisible() && this.isListening()) {
var stage = this.getStage(), family = [], parent = this.parent;
family.unshift(this);
while(parent) {
family.unshift(parent);
parent = parent.parent;
}
context.save(); context.save();
canvas._applyLineJoin(this); canvas._applyLineJoin(this);
var len = family.length; canvas._applyAncestorTransforms(this);
for(var n = 0; n < len; n++) {
var node = family[n], t = node.getTransform(), m = t.getMatrix();
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
}
drawFunc.call(this, canvas); drawFunc.call(this, canvas);
context.restore(); context.restore();

View File

@ -26,12 +26,9 @@
this._id = Kinetic.Global.idCounter++; this._id = Kinetic.Global.idCounter++;
this._buildDOM(); this._buildDOM();
this._bindContentEvents(); this._bindContentEvents();
Kinetic.Global.stages.push(this);
var go = Kinetic.Global;
go.stages.push(this);
this._addId(this); this._addId(this);
this._addName(this); this._addName(this);
}, },
/** /**
* set container dom element which contains the stage wrapper div element * set container dom element which contains the stage wrapper div element
@ -333,11 +330,6 @@
this.targetShape = null; this.targetShape = null;
} }
this.mousePos = undefined; this.mousePos = undefined;
// end drag and drop
if(dd) {
dd._endDrag(evt);
}
}, },
_mousemove: function(evt) { _mousemove: function(evt) {
this._setUserPosition(evt); this._setUserPosition(evt);
@ -373,7 +365,7 @@
// start drag and drop // start drag and drop
if(dd) { if(dd) {
dd._startDrag(evt); dd._drag(evt);
} }
}, },
_mousedown: function(evt) { _mousedown: function(evt) {
@ -387,7 +379,7 @@
//init stage drag and drop //init stage drag and drop
if(Kinetic.DD && this.attrs.draggable) { if(Kinetic.DD && this.attrs.draggable) {
this._initDrag(); this._startDrag();
} }
}, },
_mouseup: function(evt) { _mouseup: function(evt) {
@ -440,7 +432,7 @@
* init stage drag and drop * init stage drag and drop
*/ */
if(Kinetic.DD && this.attrs.draggable) { if(Kinetic.DD && this.attrs.draggable) {
this._initDrag(); this._startDrag();
} }
}, },
_touchend: function(evt) { _touchend: function(evt) {
@ -491,7 +483,7 @@
// start drag and drop // start drag and drop
if(dd) { if(dd) {
dd._startDrag(evt); dd._drag(evt);
} }
}, },
/** /**

View File

@ -177,7 +177,7 @@ Test.Modules.MANUAL = {
anim.stop(); anim.stop();
}, 3000); }, 3000);
}, },
'*ANIMATION - test multiple animations': function(containerId) { 'ANIMATION - test multiple animations': function(containerId) {
var stage = new Kinetic.Stage({ var stage = new Kinetic.Stage({
container: containerId, container: containerId,
width: 578, width: 578,