IMUXIxD
IMUXIxD

Reputation: 1227

How can I make a div that is draggable/moveable horizontally, but not vertically?

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

Answers (3)

Prid
Prid

Reputation: 1624

Manual

Baseline Code - Dragging Horizontally

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.


Extra

Dragging Horizontally from CENTER of 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.

Dragging Horizontally from EXACT SPOT you pressed

Starting from the Baseline Code:

  1. Add a new variable at top: var elDragPointOffset = 0;

  2. 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)
  1. From the Baseline Code, change the last line 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?

Dragging Horizontally WITHIN Left and Right Boundaries

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 ;)

Help, my dragging is also selecting text and marking elements??

Just add this code at the beginning of the mousemove event:

if(dragging){
  evt.preventDefault();
  
  // ...
}

FULL CODE

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

Prid
Prid

Reputation: 1624

Lightweight Library

Check out Draggable (4kB): https://github.com/xenova/draggable

document.getElementById('drag-element').DraggableJS({ axis: 'x' });

Upvotes: 0

basarat
basarat

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

Related Questions