Skip to content

Instantly share code, notes, and snippets.

@dysfunc
Created March 12, 2019 18:48
Show Gist options
  • Save dysfunc/60db9b7f011e84c9434fc69c1c32f6ba to your computer and use it in GitHub Desktop.
Save dysfunc/60db9b7f011e84c9434fc69c1c32f6ba to your computer and use it in GitHub Desktop.
Simple JS Draggable Script

JS:

const setTranslate = (x, y, element) => {
  element.style.transform = `translate3d(${x}px, ${y}px, 0)`;
};

/**
 * Simple Draggable Utility
 * @param {String}   selector    CSS Selector of the container element
 * @param {String}   dragElement CSS Selector of the drag handler element (optional)
 * @param {Function} onDrag      Callback handler to fire while dragging
 * @param {Function} onDragEnd   Callback handler to fire on drag end
 * @param {Function} onDragStart Callback handler to fire on drag start
 */
const draggable = ({ selector, dragElement, onDrag, onDragEnd, onDragStart }) => {
  let dragging;
  let currentX, currentY, initialX, initialY;
  let xOffset = 0;
  let yOffset = 0;
  
  const container = document.querySelector(selector);
  
  container.addEventListener('mousedown', function(e) {
    e.preventDefault();

    if (!dragElement || dragElement && e.target.closest(dragElement) !== null) {
      initialX = e.clientX - xOffset;
      initialY = e.clientY - yOffset;

      dragging = container;

      dragging.classList.add('ui-dragging');
      
      if (typeof(onDragStart) === 'function') {
        onDragStart(e, dragging, initialX, initialY);
      }
    }
  });

  document.addEventListener('mouseup', function(e) {
    if (dragging) {
      initialX = currentX;
      initialY = currentY;

      dragging.classList.remove('ui-dragging');

      if (typeof(onDragEnd) === 'function') {
        onDragEnd(e, dragging, initialX, initialY);
      }
    }

    dragging = null;
  });

  document.addEventListener('mousemove', function(e) {
    if (dragging) {
      e.preventDefault();

      currentX = e.clientX - initialX;
      currentY = e.clientY - initialY;

      xOffset = currentX;
      yOffset = currentY;

      setTranslate(currentX, currentY, dragging);

      if (typeof(onDrag) === 'function') {
        onDrag(e, dragging, currentX, currentY);
      }
    }
  });
}

CSS

[draggable] {
  position: absolute;
}

.ui-drag {
  cursor: grab;
}

.ui-dragging .ui-drag,
.ui-drag.ui-dragging {
  cursor: grabbing;
}

.ui-dragging {
  user-select: none;
  will-change: transform;
  -webkit-touch-callout: none;
  z-index: 2147483500;
}

HTML:

<div draggable class="box-one ui-drag" data-container=".box-one">
  <div class="ui-drag">Drag me</div>
</div>

<div draggable class="box-two" data-container=".box-two" data-drag-element=".ui-drag">
  <div class="header ui-drag">Drag me</div>
  content
</div>

Demo

https://codepen.io/kieran/pen/JzOEYK

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment