I am wondering if there is a way to make the jQuery draggable to only drag straight up, down and left, right. I want to prevent the user from dragging a div diagonally. Usin
jQueryUI supports two methods for controlling dragging on a fixed track.
You can use the axis option to limit dragging movement on a particular axis. For instance:
$('.draggable_horiz').draggable({axis: "x"});
More Info here: http://api.jqueryui.com/draggable/#option-axis
You can constrain movement using an element or an array of x/y coordinates that define a bounding box.
$('.draggable_track').draggable({ containment: [0,0, 250, 24] });
or to just use the parent element as a reference track:
$('.draggable_track').draggable({ containment: 'parent' });
More info here: http://api.jqueryui.com/draggable/#option-containment
I hope this helps.
I wrote a plugin that allows moving a draggable in both axes. It gets the job done but it would be better-implemented as a jQuery UI widget rather than a simple jQuery plugin.
Hosted Demo: http://jsbin.com/ugadu/1 (Editable via http://jsbin.com/ugadu/1/edit)
Plugin code:
$.fn.draggableXY = function(options) {
var defaultOptions = {
distance: 5,
dynamic: false
};
options = $.extend(defaultOptions, options);
this.draggable({
distance: options.distance,
start: function (event, ui) {
ui.helper.data('draggableXY.originalPosition', ui.position || {top: 0, left: 0});
ui.helper.data('draggableXY.newDrag', true);
},
drag: function (event, ui) {
var originalPosition = ui.helper.data('draggableXY.originalPosition');
var deltaX = Math.abs(originalPosition.left - ui.position.left);
var deltaY = Math.abs(originalPosition.top - ui.position.top);
var newDrag = options.dynamic || ui.helper.data('draggableXY.newDrag');
ui.helper.data('draggableXY.newDrag', false);
var xMax = newDrag ? Math.max(deltaX, deltaY) === deltaX : ui.helper.data('draggableXY.xMax');
ui.helper.data('draggableXY.xMax', xMax);
var newPosition = ui.position;
if(xMax) {
newPosition.top = originalPosition.top;
}
if(!xMax){
newPosition.left = originalPosition.left;
}
return newPosition;
}
});
};
I don't have exact code for you, but I might be able to point you in the right direction by helping you to think about the problem a little bit more deeply.
So the user begins to drag an unconstrained object. As the object moves one pixel away from the starting point, if the first pixel is at any of these four (x,y) coordinates, where x and y are the starting point: (x-1,y-1), (x-1,y+1),(x+1,y-1) or (x-1,y+1), it is still unclear which way the user means to go, For instance, if the object is at one down and on left, it's impossible to tell whether the constraint should be on the x or y axis.
Once you move more than one pixel away, it gets easier. But you still have to do some rounding on the pixel coordinates where, as in the coordinates above, abs(xoffset) == abs(yoffset), Then you can fire an event to apply the constraint when the x and/or y distance are greater than some arbitrary small integer, say "3".
The next problem to deal with is how far from the last firing of the axis constraint do you want to allow the user to change the axis. I'm guessing that you want a grid effect, so you'll have to set a number-of-pixels moved threshold before you remove the constraint and look for the next "direction" that the user wants to drag.
This is an interesting challenge and a good learning experience if you figure out how to do it.
I'm posting this answer after much fiddling to say that it's not possible with just jqueryui calls on the object. It seems that it will not allow you to change the restraint axis while you are already dragging.
Please prove me wrong?
use the drag event to your advantage
$('.selector').draggable({
drag: function(event, ui) { ... }
});
i'm not 100% sure how, but inside here, you can do a check on the coordinates. as ~jack-laplante said, this is where you would compare. if the coordinates are closer to the x axis than the y, change the axis to x
//setter
$('.selector').draggable('option', 'axis', 'x');
if the other way around change it to y. this will get you a snapping motion to always have the item either on the x axis or the y axis (from the starting point). you'd have to do a check to leave the item wherever it is if the axis was say (x+n,y+n), but it would be pretty impressive if someone got more than a few pixels staying on the |x|=|y| line.
you didn't specify if the axes always remain where they originally started or if they change depending on where the draggable item is on drag start (like if you move it a little bit, then let go, and try to drag it some more). there's a start: and end: event too that could help you with that part.
what exactly are you trying to drag that can't go diagonal, but can go left, right, up, and down?