rewrote drag and drop logic. removed draggableX and draggableY. added new dragConstraint property and new dragBounds property

This commit is contained in:
Eric Rowell 2012-03-13 22:11:22 -07:00
parent a0c385261e
commit 039c9059a0
6 changed files with 350 additions and 156 deletions

153
dist/kinetic-core.js vendored
View File

@ -228,10 +228,9 @@ Kinetic.Node = function(config) {
y: 0
};
this.eventListeners = {};
this.drag = {
x: false,
y: false
};
this.dragConstraint = "none";
this.dragBounds = {};
this._draggable = false;
// set properties from config
if(config) {
@ -241,12 +240,6 @@ Kinetic.Node = function(config) {
case "draggable":
this.draggable(config[key]);
break;
case "draggableX":
this.draggableX(config[key]);
break;
case "draggableY":
this.draggableY(config[key]);
break;
case "listen":
this.listen(config[key]);
break;
@ -552,56 +545,17 @@ Kinetic.Node.prototype = {
},
/**
* enable or disable drag and drop
* @param {Boolean} setDraggable
* @param {Boolean} isDraggable
*/
draggable: function(setDraggable) {
if(setDraggable) {
var needInit = !this.drag.x && !this.drag.y;
this.drag.x = true;
this.drag.y = true;
if(needInit) {
draggable: function(isDraggable) {
if(this.draggable !== isDraggable) {
if(isDraggable) {
this._initDrag();
}
}
else {
this.drag.x = false;
this.drag.y = false;
this._dragCleanup();
}
},
/**
* enable or disable horizontal drag and drop
* @param {Boolean} setDraggable
*/
draggableX: function(setDraggable) {
if(setDraggable) {
var needInit = !this.drag.x && !this.drag.y;
this.drag.x = true;
if(needInit) {
this._initDrag();
else {
this._dragCleanup();
}
}
else {
this.drag.x = false;
this._dragCleanup();
}
},
/**
* enable or disable vertical drag and drop
* @param {Boolean} setDraggable
*/
draggableY: function(setDraggable) {
if(setDraggable) {
var needInit = !this.drag.x && !this.drag.y;
this.drag.y = true;
if(needInit) {
this._initDrag();
}
}
else {
this.drag.y = false;
this._dragCleanup();
this._draggable = isDraggable;
}
},
/**
@ -720,6 +674,36 @@ Kinetic.Node.prototype = {
changes: changes
});
},
/**
* set drag constraint
* @param {String} constraint
*/
setDragConstraint: function(constraint) {
this.dragConstraint = constraint;
},
/**
* get drag constraint
*/
getDragConstraint: function() {
return this.dragConstraint;
},
/**
* set drag bounds
* @param {Object} bounds
* @config {Number} [left] left bounds position
* @config {Number} [top] top bounds position
* @config {Number} [right] right bounds position
* @config {Number} [bottom] bottom bounds position
*/
setDragBounds: function(bounds) {
this.dragBounds = bounds;
},
/**
* get drag bounds
*/
getDragBounds: function() {
return this.dragBounds;
},
/**
* initialize drag and drop
*/
@ -741,10 +725,8 @@ Kinetic.Node.prototype = {
* remove drag and drop event listener
*/
_dragCleanup: function() {
if(!this.drag.x && !this.drag.y) {
this.off("mousedown.initdrag");
this.off("touchstart.initdrag");
}
this.off("mousedown.initdrag");
this.off("touchstart.initdrag");
},
/**
* handle node events
@ -1029,7 +1011,8 @@ Kinetic.Stage.prototype = {
if(scaleY) {
this.scale.x = scaleX;
this.scale.y = scaleY;
} else {
}
else {
this.scale.x = scaleX;
this.scale.y = scaleX;
}
@ -1049,7 +1032,6 @@ Kinetic.Stage.prototype = {
}
}
}
scaleChildren(layers);
},
/**
@ -1084,14 +1066,14 @@ Kinetic.Stage.prototype = {
n++;
if(n < layers.length) {
addLayer(n);
} else {
}
else {
callback(bufferLayer.getCanvas().toDataURL());
}
};
imageObj.src = dataURL;
}
bufferLayer.clear();
addLayer(0);
},
@ -1194,7 +1176,8 @@ Kinetic.Stage.prototype = {
return true;
}
// handle onmouseup & onclick
else if(this.mouseUp) {
else
if(this.mouseUp) {
this.mouseUp = false;
shape._handleEvents("onmouseup", evt);
@ -1220,7 +1203,8 @@ Kinetic.Stage.prototype = {
}
// handle touchstart
else if(this.touchStart) {
else
if(this.touchStart) {
this.touchStart = false;
shape._handleEvents("touchstart", evt);
@ -1240,20 +1224,23 @@ Kinetic.Stage.prototype = {
}
// handle touchend
else if(this.touchEnd) {
else
if(this.touchEnd) {
this.touchEnd = false;
shape._handleEvents("touchend", evt);
return true;
}
// handle touchmove
else if(!isDragging && el.touchmove) {
else
if(!isDragging && el.touchmove) {
shape._handleEvents("touchmove", evt);
return true;
}
//this condition is used to identify a new target shape.
else if(!isDragging && (!this.targetShape || (!this.targetFound && shape.id !== this.targetShape.id))) {
else
if(!isDragging && (!this.targetShape || (!this.targetFound && shape.id !== this.targetShape.id))) {
/*
* check if old target has an onmouseout event listener
*/
@ -1274,13 +1261,15 @@ Kinetic.Stage.prototype = {
}
// handle onmousemove
else if(!isDragging) {
else
if(!isDragging) {
shape._handleEvents("onmousemove", evt);
return true;
}
}
// handle mouseout condition
else if(!isDragging && this.targetShape && this.targetShape.id === shape.id) {
else
if(!isDragging && this.targetShape && this.targetShape.id === shape.id) {
this.targetShape = undefined;
shape._handleEvents("onmouseout", evt);
return true;
@ -1302,7 +1291,8 @@ Kinetic.Stage.prototype = {
if(exit) {
return true;
}
} else {
}
else {
this._traverseChildren(child);
}
}
@ -1483,13 +1473,22 @@ Kinetic.Stage.prototype = {
this.on("mousemove touchmove", function(evt) {
var go = Kinetic.GlobalObject;
if(go.drag.node) {
var node = go.drag.node;
if(node) {
var pos = that.getUserPosition();
if(go.drag.node.drag.x) {
go.drag.node.x = pos.x - go.drag.offset.x;
var ds = node.dragConstraint;
var db = node.dragBounds;
if(ds === "none" || ds === "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;
}
}
if(go.drag.node.drag.y) {
go.drag.node.y = pos.y - go.drag.offset.y;
if(ds === "none" || ds === "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;
}
}
go.drag.node.getLayer().draw();

File diff suppressed because one or more lines are too long

View File

@ -25,10 +25,9 @@ Kinetic.Node = function(config) {
y: 0
};
this.eventListeners = {};
this.drag = {
x: false,
y: false
};
this.dragConstraint = "none";
this.dragBounds = {};
this._draggable = false;
// set properties from config
if(config) {
@ -38,12 +37,6 @@ Kinetic.Node = function(config) {
case "draggable":
this.draggable(config[key]);
break;
case "draggableX":
this.draggableX(config[key]);
break;
case "draggableY":
this.draggableY(config[key]);
break;
case "listen":
this.listen(config[key]);
break;
@ -349,56 +342,17 @@ Kinetic.Node.prototype = {
},
/**
* enable or disable drag and drop
* @param {Boolean} setDraggable
* @param {Boolean} isDraggable
*/
draggable: function(setDraggable) {
if(setDraggable) {
var needInit = !this.drag.x && !this.drag.y;
this.drag.x = true;
this.drag.y = true;
if(needInit) {
draggable: function(isDraggable) {
if(this.draggable !== isDraggable) {
if(isDraggable) {
this._initDrag();
}
}
else {
this.drag.x = false;
this.drag.y = false;
this._dragCleanup();
}
},
/**
* enable or disable horizontal drag and drop
* @param {Boolean} setDraggable
*/
draggableX: function(setDraggable) {
if(setDraggable) {
var needInit = !this.drag.x && !this.drag.y;
this.drag.x = true;
if(needInit) {
this._initDrag();
else {
this._dragCleanup();
}
}
else {
this.drag.x = false;
this._dragCleanup();
}
},
/**
* enable or disable vertical drag and drop
* @param {Boolean} setDraggable
*/
draggableY: function(setDraggable) {
if(setDraggable) {
var needInit = !this.drag.x && !this.drag.y;
this.drag.y = true;
if(needInit) {
this._initDrag();
}
}
else {
this.drag.y = false;
this._dragCleanup();
this._draggable = isDraggable;
}
},
/**
@ -517,6 +471,36 @@ Kinetic.Node.prototype = {
changes: changes
});
},
/**
* set drag constraint
* @param {String} constraint
*/
setDragConstraint: function(constraint) {
this.dragConstraint = constraint;
},
/**
* get drag constraint
*/
getDragConstraint: function() {
return this.dragConstraint;
},
/**
* set drag bounds
* @param {Object} bounds
* @config {Number} [left] left bounds position
* @config {Number} [top] top bounds position
* @config {Number} [right] right bounds position
* @config {Number} [bottom] bottom bounds position
*/
setDragBounds: function(bounds) {
this.dragBounds = bounds;
},
/**
* get drag bounds
*/
getDragBounds: function() {
return this.dragBounds;
},
/**
* initialize drag and drop
*/
@ -538,10 +522,8 @@ Kinetic.Node.prototype = {
* remove drag and drop event listener
*/
_dragCleanup: function() {
if(!this.drag.x && !this.drag.y) {
this.off("mousedown.initdrag");
this.off("touchstart.initdrag");
}
this.off("mousedown.initdrag");
this.off("touchstart.initdrag");
},
/**
* handle node events

View File

@ -147,7 +147,8 @@ Kinetic.Stage.prototype = {
if(scaleY) {
this.scale.x = scaleX;
this.scale.y = scaleY;
} else {
}
else {
this.scale.x = scaleX;
this.scale.y = scaleX;
}
@ -167,7 +168,6 @@ Kinetic.Stage.prototype = {
}
}
}
scaleChildren(layers);
},
/**
@ -202,14 +202,14 @@ Kinetic.Stage.prototype = {
n++;
if(n < layers.length) {
addLayer(n);
} else {
}
else {
callback(bufferLayer.getCanvas().toDataURL());
}
};
imageObj.src = dataURL;
}
bufferLayer.clear();
addLayer(0);
},
@ -312,7 +312,8 @@ Kinetic.Stage.prototype = {
return true;
}
// handle onmouseup & onclick
else if(this.mouseUp) {
else
if(this.mouseUp) {
this.mouseUp = false;
shape._handleEvents("onmouseup", evt);
@ -338,7 +339,8 @@ Kinetic.Stage.prototype = {
}
// handle touchstart
else if(this.touchStart) {
else
if(this.touchStart) {
this.touchStart = false;
shape._handleEvents("touchstart", evt);
@ -358,20 +360,23 @@ Kinetic.Stage.prototype = {
}
// handle touchend
else if(this.touchEnd) {
else
if(this.touchEnd) {
this.touchEnd = false;
shape._handleEvents("touchend", evt);
return true;
}
// handle touchmove
else if(!isDragging && el.touchmove) {
else
if(!isDragging && el.touchmove) {
shape._handleEvents("touchmove", evt);
return true;
}
//this condition is used to identify a new target shape.
else if(!isDragging && (!this.targetShape || (!this.targetFound && shape.id !== this.targetShape.id))) {
else
if(!isDragging && (!this.targetShape || (!this.targetFound && shape.id !== this.targetShape.id))) {
/*
* check if old target has an onmouseout event listener
*/
@ -392,13 +397,15 @@ Kinetic.Stage.prototype = {
}
// handle onmousemove
else if(!isDragging) {
else
if(!isDragging) {
shape._handleEvents("onmousemove", evt);
return true;
}
}
// handle mouseout condition
else if(!isDragging && this.targetShape && this.targetShape.id === shape.id) {
else
if(!isDragging && this.targetShape && this.targetShape.id === shape.id) {
this.targetShape = undefined;
shape._handleEvents("onmouseout", evt);
return true;
@ -420,7 +427,8 @@ Kinetic.Stage.prototype = {
if(exit) {
return true;
}
} else {
}
else {
this._traverseChildren(child);
}
}
@ -601,13 +609,22 @@ Kinetic.Stage.prototype = {
this.on("mousemove touchmove", function(evt) {
var go = Kinetic.GlobalObject;
if(go.drag.node) {
var node = go.drag.node;
if(node) {
var pos = that.getUserPosition();
if(go.drag.node.drag.x) {
go.drag.node.x = pos.x - go.drag.offset.x;
var ds = node.dragConstraint;
var db = node.dragBounds;
if(ds === "none" || ds === "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;
}
}
if(go.drag.node.drag.y) {
go.drag.node.y = pos.y - go.drag.offset.y;
if(ds === "none" || ds === "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;
}
}
go.drag.node.getLayer().draw();

View File

@ -558,6 +558,155 @@ function Test() {
layer.add(circle1);
layer.add(circle2);
stage.add(layer);
}
},
"DRAG AND DROP - drag and drop constrianed horiztonally": function(containerId) {
var stage = new Kinetic.Stage(containerId, 578, 200);
var layer = new Kinetic.Layer();
var circle = new Kinetic.Circle({
x: stage.width / 2,
y: stage.height / 2,
radius: 70,
fill: "red",
stroke: "black",
strokeWidth: 4,
draggable: true,
dragConstraint: "horizontal"
});
layer.add(circle);
stage.add(layer);
},
"DRAG AND DROP - drag and drop constrianed vertically": function(containerId) {
var stage = new Kinetic.Stage(containerId, 578, 200);
var layer = new Kinetic.Layer();
var circle = new Kinetic.Circle({
x: stage.width / 2,
y: stage.height / 2,
radius: 70,
fill: "red",
stroke: "black",
strokeWidth: 4,
draggable: true,
dragConstraint: "vertical"
});
layer.add(circle);
stage.add(layer);
},
"DRAG AND DROP - drag and drop with explicit no constraint": function(containerId) {
var stage = new Kinetic.Stage(containerId, 578, 200);
var layer = new Kinetic.Layer();
var circle = new Kinetic.Circle({
x: stage.width / 2,
y: stage.height / 2,
radius: 70,
fill: "red",
stroke: "black",
strokeWidth: 4,
draggable: true,
dragConstraint: "none"
});
layer.add(circle);
stage.add(layer);
},
"DRAG AND DROP - drag and drop with left bounds": function(containerId) {
var stage = new Kinetic.Stage(containerId, 578, 200);
var layer = new Kinetic.Layer();
var circle = new Kinetic.Circle({
x: stage.width / 2,
y: stage.height / 2,
radius: 70,
fill: "red",
stroke: "black",
strokeWidth: 4,
draggable: true,
dragBounds: {
left: 150
}
});
layer.add(circle);
stage.add(layer);
},
"DRAG AND DROP - drag and drop with right bounds": function(containerId) {
var stage = new Kinetic.Stage(containerId, 578, 200);
var layer = new Kinetic.Layer();
var circle = new Kinetic.Circle({
x: stage.width / 2,
y: stage.height / 2,
radius: 70,
fill: "red",
stroke: "black",
strokeWidth: 4,
draggable: true,
dragBounds: {
right: 400
}
});
layer.add(circle);
stage.add(layer);
},
"DRAG AND DROP - drag and drop with top bounds": function(containerId) {
var stage = new Kinetic.Stage(containerId, 578, 200);
var layer = new Kinetic.Layer();
var circle = new Kinetic.Circle({
x: stage.width / 2,
y: stage.height / 2,
radius: 70,
fill: "red",
stroke: "black",
strokeWidth: 4,
draggable: true,
dragBounds: {
top: 80
}
});
layer.add(circle);
stage.add(layer);
},
"DRAG AND DROP - drag and drop with bottom bounds": function(containerId) {
var stage = new Kinetic.Stage(containerId, 578, 200);
var layer = new Kinetic.Layer();
var circle = new Kinetic.Circle({
x: stage.width / 2,
y: stage.height / 2,
radius: 70,
fill: "red",
stroke: "black",
strokeWidth: 4,
draggable: true,
dragBounds: {
bottom: 120
}
});
layer.add(circle);
stage.add(layer);
},
"DRAG AND DROP - drag and drop with full rect bounds": function(containerId) {
var stage = new Kinetic.Stage(containerId, 578, 200);
var layer = new Kinetic.Layer();
var circle = new Kinetic.Circle({
x: stage.width / 2,
y: stage.height / 2,
radius: 70,
fill: "red",
stroke: "black",
strokeWidth: 4,
draggable: true,
dragBounds: {
top: 80,
bottom: 120,
left: 150,
right: 578 - 150
}
});
layer.add(circle);
stage.add(layer);
},
};
}

View File

@ -716,6 +716,53 @@ function Test() {
layer.draw();
},
"NODE - test drag and drop properties and methods": function(containerId) {
var stage = new Kinetic.Stage(containerId, 578, 200);
var layer = new Kinetic.Layer();
var circle = new Kinetic.Circle({
x: stage.width / 2,
y: stage.height / 2,
radius: 70,
fill: "green",
stroke: "black",
strokeWidth: 4,
name: "myCircle"
});
stage.add(layer);
layer.add(circle);
layer.draw();
// test defaults
test(circle._draggable === false, "draggable should be false");
test(circle.dragConstraint === "none", "drag constraint should be none");
test(circle.dragBounds.left === undefined, "drag left should be undefined");
test(circle.dragBounds.top === undefined, "drag top should be undefined");
test(circle.dragBounds.right === undefined, "drag right should be undefined");
test(circle.dragBounds.bottom === undefined, "drag bottom should be undefined");
test(circle.getDragConstraint() === "none", "drag constraint should be none");
test(circle.getDragBounds().bottom === undefined, "drag bottom should be undefined");
//change properties
circle.draggable(true);
circle.setDragConstraint("vertical");
circle.setDragBounds({
left: 50,
top: 100,
right: 150,
bottom: 200
});
// test new properties
test(circle._draggable === true, "draggable should be true");
test(circle.dragConstraint === "vertical", "drag constraint should be vertical");
test(circle.dragBounds.left === 50, "drag left should be 50");
test(circle.dragBounds.top === 100, "drag top should be 100");
test(circle.dragBounds.right === 150, "drag right should be 150");
test(circle.dragBounds.bottom === 200, "drag bottom should be 200");
test(circle.getDragConstraint() === "vertical", "drag constraint should be vertical");
test(circle.getDragBounds().bottom === 200, "drag bottom should be 200");
},
"STAGE - add layer then shape": function(containerId) {
var stage = new Kinetic.Stage(containerId, 578, 200);
var layer = new Kinetic.Layer();