Draggable containment uses the Box Model to identify boundaries for draggable items.
containment Type: Selector or Element or String or Array, Default: false
Constrains dragging to within the bounds of the specified element or region. Multiple types supported:
- Selector: The draggable element will be contained to the bounding box of the first element found by the selector. If no element is found, no containment will be set.
- Element: The draggable element will be contained to the bounding box of this element.
- String: Possible values:
"parent"
, "document"
, "window"
.
- Array: An array defining a bounding box in the form
[ x1, y1, x2, y2 ]
.
Ref: http://api.jqueryui.com/draggable/
So this means you need to create either complex boxes or build collision detection into your drag
callback. When drag
is triggered, it is passed an event
and ui
object. ui.position
can be manipulated:
Current CSS position of the helper as { top, left }
object. The values may be changed to modify where the element will be positioned. This is useful for custom containment, snapping, etc.
This can be difficult, so if this is a beggining project or something small, consider using Collision plugin: jQuery Dragging With Collision Detection
Consider the following primitive example.
$(function() {
function log(obj) {
var str = "T: " + obj.top + " L:, " + obj.left + ", R: " + obj.right + ", B: " + obj.bottom;
$("#log").html(str);
}
function getObjectPos(obj) {
var oPos = obj.position();
oPos.right = oPos.left + obj.width();
oPos.bottom = oPos.top + obj.height();
return oPos;
}
function collision(a, b) {
var col = false;
var side;
var r1 = getObjectPos(a);
var r2 = getObjectPos(b);
/*
https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection
rect1.x < rect2.x + rect2.width && rect1.x + rect1.width > rect2.x && rect1.y < rect2.y + rect2.height && rect1.y + rect1.height > rect2.y
*/
if (r1.left < r2.right && r1.right > r2.left && r1.top < r2.bottom && r1.bottom > r2.top) {
col = true;
}
return {
col: col,
right: r1.right > r2.left,
left: r1.left > r2.right,
bottom: r1.bottom > r2.bottom,
top: r1.top > r2.top
};
}
$("#draggable").draggable({
containment: "#containment-wrapper",
start: function(e, ui) {
ui.helper.data("prev-pos", getObjectPos(ui.helper));
},
drag: function(e, ui) {
var oPrevPos = ui.helper.data("prev-pos");
var oPos = getObjectPos(ui.helper);
console.log(oPrevPos, oPos);
log(oPos);
$("#containment-wrapper .no-drag").each(function(ind, el) {
var c = collision(ui.helper, $(el));
var col = c.col;
var side;
if (col) {
switch (true) {
case c.top:
side = "top";
break;
case c.left:
side = "left";
break;
case c.bottom:
side = "bottom";
break;
case c.right:
side = "right";
break;
}
console.log("Collision: " + col, side, c);
switch (side) {
case "left":
case "right":
ui.position.left = oPrevPos.left
break;
case "top":
case "bottom":
ui.position.top = oPrevPos.top
break;
}
} else {
console.log("Collision: " + c.col, c);
ui.helper.data("prev-pos", oPos);
}
});
}
});
});
.draggable {
width: 100px;
height: 100px;
float: left;
margin: 0;
padding: 0;
background: #CCC;
}
#containment-wrapper {
width: 400px;
height: 250px;
border: 2px solid #ccc;
padding: 10px;
position: relative;
}
#containment-wrapper .no-drag {
width: 100px;
height: 100px;
border: 2px solid #ccc;
top: 168px;
left: 318px;
position: absolute;
}
.output {
margin-top: -2em;
}
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="containment-wrapper">
<div id="draggable" class="draggable">
</div>
<div class="no-drag">
</div>
</div>
<div id="log" class="output"></div>
This is a very basic example using some 2D Collision Detection. It's not great and could use improvement, yet you can see where to start.
Hope this helps.