Reputation: 1227
How can I make a div that is draggable/moveable horizontally, but not vertically?
I would prefer if this could be done without JQuery UI. JQuery is fine. Or vanilla JS.
Upvotes: 6
Views: 14261
Reputation: 1624
This is what you came for:
#drag-element {
position: absolute;
}
#parent-element {
position: relative;
}
// SETUP
var dragEl = document.getElementById('drag-element');
// set CSS to 'position: absolute' or 'position: relative' !!
// and the parent element to 'position: relative' !!
var dragging = false;
// on mouse press on drag element
dragEl.addEventListener('mousedown', function(evt){
dragging = true;
});
// on mouse release
window.addEventListener('mouseup', function(evt){
dragging = false;
});
// on mouse move
window.addEventListener('mousemove', function(evt){
if(dragging){
// get X position of left side of parent element
var parentContainer = dragEl.parentElement;
var parentLeft = parentContainer.getBoundingClientRect().left;
// get current mouse X position
var mouseX = evt.pageX;
// MOVE -- set CSS 'left' value to mouse X - parent's left X = left offset for drag element
dragEl.style.left = mouseX - parentLeft;
}
});
⚠ This will allow horizontal dragging without any left or right boundaries (so you can drag them outside the parent container), and will start the dragging from the LEFT EDGE of your drag element.
Starting from the Baseline Code:
Change this last line dragEl.style.left = mouseX - parentLeft;
to this:
// move from MIDDLE
var elBounds = dragEl.getBoundingClientRect();
var elMiddleX = (elBounds.right - elBounds.left) / 2; // get width of element, divide by two = X of middle
// MOVE -- set CSS left value correctly
dragEl.style.left = mouseX - parentLeft - elMiddleX;
Want to drag the element from the exact position you started dragging from? A bit more code but let's do it.
Starting from the Baseline Code:
Add a new variable at top: var elDragPointOffset = 0;
In the mousedown
event code, add this at the end:
// move from EXACT SPOT you started dragging from
var elBounds = dragEl.getBoundingClientRect();
elDragPointOffset = evt.pageX - elBounds.left; // get X position of how far mouse X is inside the drag element from the drag element's left side (phew)
dragEl.style.left = mouseX - parentLeft;
to this:dragEl.style.left = mouseX - parentLeft - elDragPointOffset;
But what about limiting the left and right boundaries for the dragging?
Starting from the code for Dragging Horizontally from EXACT SPOT you pressed:
Replace the last line dragEl.style.left = mouseX - parentLeft - elDragPointOffset;
with this code:
var elBounds = dragEl.getBoundingClientRect();
var dragElWidth = elBounds.right - elBounds.left;
var parentBounds = parentContainer.getBoundingClientRect();
var parentWidth = parentBounds.right - parentBounds.left;
var newDragElLeftValue = mouseX - parentLeft - elDragPointOffset;
if(newDragElLeftValue < 0)
dragEl.style.left = 0;
else if(newDragElLeftValue > (parentWidth - dragElWidth))
dragEl.style.left = parentWidth - dragElWidth;
else
dragEl.style.left = newDragElLeftValue; // Normal move behavior (you can change this to e.g. drag from center only)
This will calculate the new left
position for the drag element BEFORE actually moving it (to prevent flicker), and then perform simple checks on the new value to see if it's within the left and right borders of the parent element. If it is, then move the drag element, but if it's not, keep the drag element hugging the borders ;)
Just add this code at the beginning of the mousemove
event:
if(dragging){
evt.preventDefault();
// ...
}
Dragging horizontally from where you pressed, and keeping the dragging within the borders of the parent element:
// SETUP
var dragEl = document.getElementById('drag-element');
// set CSS to 'position: absolute' or 'position: relative' !!
// and the parent element to 'position: relative' !!
var dragging = false;
var elDragPointOffset = 0; // how far in mouse X is relative to drag el's left border
// on mouse press on drag element
dragEl.addEventListener('mousedown', function(evt){
dragging = true;
// capture EXACT SPOT you started dragging from in the drag element
var elBounds = dragEl.getBoundingClientRect();
elDragPointOffset = evt.pageX - elBounds.left; // get X position of how far mouse X is inside the drag element from the drag element's left side (phew)
});
// on mouse release
window.addEventListener('mouseup', function(evt){
dragging = false;
});
// on mouse move
window.addEventListener('mousemove', function(evt){
if(dragging){
evt.preventDefault(); // prevent text selection while dragging
// get current mouse X position
var mouseX = evt.pageX;
// get width of drag element
var elBounds = dragEl.getBoundingClientRect();
var dragElWidth = elBounds.right - elBounds.left;
// get bounds of parent element
var parentContainer = dragEl.parentElement;
var parentBounds = parentContainer.getBoundingClientRect();
var parentLeft = parentBounds.left;
var parentWidth = parentBounds.right - parentBounds.left;
// new left position for drag element while dragging
var newDragElLeftValue = mouseX - parentLeft - elDragPointOffset;
// check if new left position is within parent's borders
if(newDragElLeftValue < 0)
dragEl.style.left = 0; // place at start
else if(newDragElLeftValue > (parentWidth - dragElWidth))
dragEl.style.left = parentWidth - dragElWidth; // place at end
else
dragEl.style.left = newDragElLeftValue + 'px'; // default behavior: MOVE the drag el (this can be changed to however you like to drag)
}
});
#parent {
position: relative;
}
#drag-element {
position: absolute;
background: black;
width: 30px;
height: 20px;
cursor: e-resize;
}
<div id="parent">
<div id="drag-element"></div>
</div>
Upvotes: 0
Reputation: 1624
Check out Draggable (4kB): https://github.com/xenova/draggable
document.getElementById('drag-element').DraggableJS({ axis: 'x' });
Upvotes: 0
Reputation: 275947
Creating such a behavior yourself would be quite a bit of work. I would recommend using jquery ui :
http://jsfiddle.net/basarat/f7nNf/1/
Its a single line of code:
$( "#draggable" ).draggable({ axis: "x" });
And you don't event need to download the complete jquery ui. You can do a custom build with only draggable here : http://jqueryui.com/download/
Read more about draggable here: http://jqueryui.com/draggable/#constrain-movement
Upvotes: 11