2012-12-02 04:04:10 +08:00
|
|
|
(function() {
|
|
|
|
Kinetic.DD = {
|
|
|
|
anim: new Kinetic.Animation(),
|
|
|
|
moving: false,
|
|
|
|
offset: {
|
|
|
|
x: 0,
|
|
|
|
y: 0
|
2013-01-10 15:45:30 +08:00
|
|
|
}
|
2012-12-02 04:04:10 +08:00
|
|
|
};
|
2013-01-28 13:29:22 +08:00
|
|
|
|
|
|
|
Kinetic.getNodeDragging = function() {
|
2013-01-28 14:25:16 +08:00
|
|
|
return Kinetic.DD.node;
|
2013-01-28 13:29:22 +08:00
|
|
|
};
|
|
|
|
|
2013-01-14 12:16:58 +08:00
|
|
|
Kinetic.DD._setupDragLayerAndGetContainer = function(no) {
|
2013-01-28 13:29:22 +08:00
|
|
|
var stage = no.getStage(), nodeType = no.nodeType, lastContainer, group;
|
2013-01-10 14:34:14 +08:00
|
|
|
|
|
|
|
// re-construct node tree
|
2013-01-14 11:59:35 +08:00
|
|
|
no._eachAncestorReverse(function(node) {
|
2013-01-10 14:34:14 +08:00
|
|
|
if(node.nodeType === 'Layer') {
|
2013-01-29 13:27:08 +08:00
|
|
|
stage.dragLayer.setAttrs(node.getAttrs());
|
2013-01-13 15:39:56 +08:00
|
|
|
lastContainer = stage.dragLayer;
|
|
|
|
stage.add(stage.dragLayer);
|
2013-01-10 14:34:14 +08:00
|
|
|
}
|
|
|
|
else if(node.nodeType === 'Group') {
|
2013-01-29 13:27:08 +08:00
|
|
|
group = new Kinetic.Group(node.getAttrs());
|
2013-01-10 14:34:14 +08:00
|
|
|
lastContainer.add(group);
|
|
|
|
lastContainer = group;
|
|
|
|
}
|
|
|
|
});
|
2013-01-14 12:16:58 +08:00
|
|
|
return lastContainer;
|
2013-01-10 14:34:14 +08:00
|
|
|
};
|
2013-01-14 14:32:08 +08:00
|
|
|
Kinetic.DD._initDragLayer = function(stage) {
|
|
|
|
stage.dragLayer = new Kinetic.Layer();
|
2013-01-13 15:39:56 +08:00
|
|
|
stage.dragLayer.getCanvas().getElement().className = 'kinetic-drag-and-drop-layer';
|
|
|
|
};
|
2012-12-31 15:14:23 +08:00
|
|
|
Kinetic.DD._drag = function(evt) {
|
2013-01-28 14:25:16 +08:00
|
|
|
var dd = Kinetic.DD, node = dd.node;
|
2012-10-15 09:46:04 +08:00
|
|
|
|
2012-12-02 04:04:10 +08:00
|
|
|
if(node) {
|
|
|
|
var pos = node.getStage().getUserPosition();
|
|
|
|
var dbf = node.attrs.dragBoundFunc;
|
2012-11-18 14:29:07 +08:00
|
|
|
|
2012-12-02 04:04:10 +08:00
|
|
|
var newNodePos = {
|
|
|
|
x: pos.x - dd.offset.x,
|
|
|
|
y: pos.y - dd.offset.y
|
|
|
|
};
|
|
|
|
|
|
|
|
if(dbf !== undefined) {
|
|
|
|
newNodePos = dbf.call(node, newNodePos, evt);
|
|
|
|
}
|
|
|
|
|
|
|
|
node.setAbsolutePosition(newNodePos);
|
|
|
|
|
|
|
|
if(!dd.moving) {
|
|
|
|
dd.moving = true;
|
|
|
|
node.setListening(false);
|
2012-10-15 09:46:04 +08:00
|
|
|
|
2012-12-02 04:04:10 +08:00
|
|
|
// execute dragstart events if defined
|
|
|
|
node._handleEvent('dragstart', evt);
|
|
|
|
}
|
|
|
|
|
2013-01-13 15:39:56 +08:00
|
|
|
// execute ondragmove if defined
|
2012-12-02 04:04:10 +08:00
|
|
|
node._handleEvent('dragmove', evt);
|
2012-10-15 11:22:22 +08:00
|
|
|
}
|
2012-12-02 04:04:10 +08:00
|
|
|
};
|
|
|
|
Kinetic.DD._endDrag = function(evt) {
|
2013-01-28 14:25:16 +08:00
|
|
|
var dd = Kinetic.DD, node = dd.node;
|
2013-01-14 11:59:35 +08:00
|
|
|
|
2013-01-28 14:25:16 +08:00
|
|
|
if(node) {
|
|
|
|
var nodeType = node.nodeType, stage = node.getStage();
|
2012-12-02 04:04:10 +08:00
|
|
|
node.setListening(true);
|
2012-12-31 15:14:23 +08:00
|
|
|
if(nodeType === 'Stage') {
|
2012-12-02 04:04:10 +08:00
|
|
|
node.draw();
|
|
|
|
}
|
2013-01-30 01:54:26 +08:00
|
|
|
// else if group, shape, or layer
|
2012-12-02 04:04:10 +08:00
|
|
|
else {
|
2013-01-10 15:45:30 +08:00
|
|
|
if((nodeType === 'Group' || nodeType === 'Shape') && node.getDragOnTop() && dd.prevParent) {
|
2012-12-31 15:14:23 +08:00
|
|
|
node.moveTo(dd.prevParent);
|
2013-01-14 11:59:35 +08:00
|
|
|
node.getStage().dragLayer.remove();
|
2012-12-31 15:14:23 +08:00
|
|
|
dd.prevParent = null;
|
|
|
|
}
|
|
|
|
|
2012-12-02 04:04:10 +08:00
|
|
|
node.getLayer().draw();
|
|
|
|
}
|
2013-01-30 01:54:26 +08:00
|
|
|
|
|
|
|
delete dd.node;
|
|
|
|
dd.anim.stop();
|
2012-12-02 04:04:10 +08:00
|
|
|
|
2013-01-08 11:51:20 +08:00
|
|
|
// only fire dragend event if the drag and drop
|
|
|
|
// operation actually started. This can be detected by
|
|
|
|
// checking dd.moving
|
2012-12-02 04:04:10 +08:00
|
|
|
if(dd.moving) {
|
|
|
|
dd.moving = false;
|
|
|
|
node._handleEvent('dragend', evt);
|
|
|
|
}
|
2012-10-15 11:22:22 +08:00
|
|
|
}
|
2012-12-02 04:04:10 +08:00
|
|
|
};
|
2013-01-28 13:29:22 +08:00
|
|
|
Kinetic.Node.prototype._startDrag = function(evt) {
|
2013-01-28 14:25:16 +08:00
|
|
|
var dd = Kinetic.DD, that = this, stage = this.getStage(), pos = stage.getUserPosition();
|
2013-01-14 14:32:08 +08:00
|
|
|
|
|
|
|
if(pos) {
|
|
|
|
var m = this.getTransform().getTranslation(), ap = this.getAbsolutePosition(), nodeType = this.nodeType, container;
|
|
|
|
|
|
|
|
dd.node = this;
|
|
|
|
dd.offset.x = pos.x - ap.x;
|
|
|
|
dd.offset.y = pos.y - ap.y;
|
|
|
|
|
|
|
|
// Stage and Layer node types
|
|
|
|
if(nodeType === 'Stage' || nodeType === 'Layer') {
|
|
|
|
dd.anim.node = this;
|
|
|
|
dd.anim.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Group or Shape node types
|
|
|
|
else {
|
|
|
|
if(this.getDragOnTop()) {
|
|
|
|
container = dd._setupDragLayerAndGetContainer(this);
|
|
|
|
dd.anim.node = stage.dragLayer;
|
|
|
|
dd.prevParent = this.getParent();
|
|
|
|
// WARNING: it's important to delay the moveTo operation,
|
|
|
|
// layer redraws, and anim.start() until after the method execution
|
|
|
|
// has completed or else there will be a flicker on mobile devices
|
|
|
|
// due to the time it takes to append the dd canvas to the DOM
|
|
|
|
setTimeout(function() {
|
|
|
|
if(dd.node) {
|
|
|
|
that.moveTo(container);
|
|
|
|
dd.prevParent.getLayer().draw();
|
|
|
|
stage.dragLayer.draw();
|
|
|
|
dd.anim.start();
|
|
|
|
}
|
|
|
|
}, 0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dd.anim.node = this.getLayer();
|
|
|
|
dd.anim.start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2012-12-02 04:04:10 +08:00
|
|
|
/**
|
|
|
|
* set draggable
|
|
|
|
* @name setDraggable
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {String} draggable
|
|
|
|
*/
|
|
|
|
Kinetic.Node.prototype.setDraggable = function(draggable) {
|
|
|
|
this.setAttr('draggable', draggable);
|
|
|
|
this._dragChange();
|
|
|
|
};
|
|
|
|
/**
|
|
|
|
* get draggable
|
|
|
|
* @name getDraggable
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
Kinetic.Node.prototype.getDraggable = function() {
|
|
|
|
return this.attrs.draggable;
|
|
|
|
};
|
|
|
|
/**
|
|
|
|
* determine if node is currently in drag and drop mode
|
|
|
|
* @name isDragging
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
Kinetic.Node.prototype.isDragging = function() {
|
2013-01-28 14:25:16 +08:00
|
|
|
var dd = Kinetic.DD;
|
2012-12-02 04:04:10 +08:00
|
|
|
return dd.node && dd.node._id === this._id && dd.moving;
|
|
|
|
};
|
2012-10-15 11:22:22 +08:00
|
|
|
|
2012-12-02 04:04:10 +08:00
|
|
|
Kinetic.Node.prototype._listenDrag = function() {
|
|
|
|
this._dragCleanup();
|
2013-01-28 13:29:22 +08:00
|
|
|
var that = this;
|
|
|
|
this.on('mousedown.kinetic touchstart.kinetic', function(evt) {
|
|
|
|
if(!Kinetic.getNodeDragging()) {
|
|
|
|
that._startDrag(evt);
|
|
|
|
}
|
|
|
|
});
|
2012-12-02 04:04:10 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
Kinetic.Node.prototype._dragChange = function() {
|
|
|
|
if(this.attrs.draggable) {
|
|
|
|
this._listenDrag();
|
2012-10-15 09:46:04 +08:00
|
|
|
}
|
|
|
|
else {
|
2012-12-02 04:04:10 +08:00
|
|
|
// remove event listeners
|
|
|
|
this._dragCleanup();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* force drag and drop to end
|
|
|
|
* if this node is currently in
|
|
|
|
* drag and drop mode
|
|
|
|
*/
|
|
|
|
var stage = this.getStage();
|
|
|
|
var dd = Kinetic.DD;
|
|
|
|
if(stage && dd.node && dd.node._id === this._id) {
|
|
|
|
dd._endDrag();
|
|
|
|
}
|
2012-10-15 09:46:04 +08:00
|
|
|
}
|
2012-12-02 04:04:10 +08:00
|
|
|
};
|
|
|
|
Kinetic.Node.prototype._dragCleanup = function() {
|
|
|
|
this.off('mousedown.kinetic');
|
|
|
|
this.off('touchstart.kinetic');
|
|
|
|
};
|
|
|
|
/**
|
|
|
|
* get draggable. Alias of getDraggable()
|
|
|
|
* @name isDraggable
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
Kinetic.Node.prototype.isDraggable = Kinetic.Node.prototype.getDraggable;
|
|
|
|
|
2013-01-10 15:45:30 +08:00
|
|
|
Kinetic.Node.addGettersSetters(Kinetic.Node, ['dragBoundFunc', 'dragOnTop']);
|
2012-12-02 04:04:10 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* set drag bound function. This is used to override the default
|
|
|
|
* drag and drop position
|
|
|
|
* @name setDragBoundFunc
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Function} dragBoundFunc
|
|
|
|
*/
|
|
|
|
|
2013-01-10 15:45:30 +08:00
|
|
|
/**
|
|
|
|
* set flag which enables or disables automatically moving the draggable node to a
|
|
|
|
* temporary top layer to improve performance. The default is true
|
|
|
|
* @name setDragOnTop
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Function} dragOnTop
|
|
|
|
*/
|
|
|
|
|
2012-12-02 04:04:10 +08:00
|
|
|
/**
|
|
|
|
* get dragBoundFunc
|
|
|
|
* @name getDragBoundFunc
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
2013-01-10 15:45:30 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* get flag which enables or disables automatically moving the draggable node to a
|
|
|
|
* temporary top layer to improve performance.
|
|
|
|
* @name getDragOnTop
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
2013-01-28 14:25:16 +08:00
|
|
|
|
2013-01-30 02:12:24 +08:00
|
|
|
// listen for capturing phase so that the _endDrag method is
|
|
|
|
// called before the stage mouseup event is triggered in order
|
|
|
|
// to render the hit graph just in time to pick up the event
|
2013-01-28 14:25:16 +08:00
|
|
|
var html = document.getElementsByTagName('html')[0];
|
2013-01-30 02:12:24 +08:00
|
|
|
html.addEventListener('mouseup', Kinetic.DD._endDrag, true);
|
|
|
|
html.addEventListener('touchend', Kinetic.DD._endDrag, true);
|
2012-12-02 04:04:10 +08:00
|
|
|
})();
|