Skip to content

Instantly share code, notes, and snippets.

@ricardocanelas
Last active April 26, 2020 04:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ricardocanelas/85457c2705d5124a3c5d1cd18f8a4260 to your computer and use it in GitHub Desktop.
Save ricardocanelas/85457c2705d5124a3c5d1cd18f8a4260 to your computer and use it in GitHub Desktop.
Draggable
function draggable({ dragElem, zoneElemBefore }) {
const $dragElem = document.querySelector(dragElem)
const $zoneElem = $dragElem.closest(zoneElemBefore)
const margin = 10
$dragElem.onmousedown = function (event) {
if (event.target.tagName === "TEXTAREA") return;
event.preventDefault();
let shiftY = event.clientY - $dragElem.getBoundingClientRect().top;
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
function onMouseMove(event) {
let boxBottomEdge = (event.clientY + ($dragElem.getBoundingClientRect().height - shiftY))
let newB = $zoneElem.getBoundingClientRect().bottom - boxBottomEdge
let topEdge = ($zoneElem.offsetHeight - $dragElem.offsetHeight);
if (newB < margin) newB = margin
if (newB > topEdge - margin) newB = topEdge - margin
$dragElem.style.bottom = newB + 'px';
}
function onMouseUp() {
document.removeEventListener('mouseup', onMouseUp);
document.removeEventListener('mousemove', onMouseMove);
}
};
$dragElem.ondragstart = function() {
return false;
};
}
draggable.reset = function (dragElem, pos) {
const $dragElem = document.querySelector(dragElem)
$dragElem.style.bottom = pos
}
export default draggable
draggable({
dragElem: document.querySelector('.draggable-box'),
zoneElem: document.querySelector('.draggable-zone')
})
function draggable({ dragElem, zoneElem }) {
dragElem.style.position = 'relative !important';
dragElem.onmousedown = function(event) {
event.preventDefault();
let shiftY = event.clientX - dragElem.getBoundingClientRect().top;
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
function onMouseMove(event) {
let newTop = event.clientY - shiftY - zoneElem.getBoundingClientRect().top;
let bottomEdge = zoneElem.offsetHeight - dragElem.offsetHeight;
if (newTop < 0) newTop = 0;
if (newTop > bottomEdge) newTop = bottomEdge;
dragElem.style.top = newTop + 'px';
}
function onMouseUp() {
document.removeEventListener('mouseup', onMouseUp);
document.removeEventListener('mousemove', onMouseMove);
}
};
dragElem.ondragstart = function() {
return false;
};
}
/**
- With support to mobile devices
- The position is based by bottom
How to use:
draggable({ dragElem: '.draggable-box', zoneElemBefore: '.draggable-zone' })
*/
function draggable({ dragElem, zoneElemBefore }) {
const $dragElem = document.querySelector(dragElem);
const $zoneElem = $dragElem.closest(zoneElemBefore);
const margin = 10;
let isClicked = false;
let shiftY = 0;
$dragElem.addEventListener("touchstart", onTouchStart);
$dragElem.addEventListener("touchmove", onTouchMove);
$dragElem.addEventListener("touchend", onTouchEnd);
$dragElem.addEventListener("mousedown", onMouseDown);
$dragElem.style.cursor = "grab";
function onTouchStart(event) {
start()
shiftY = getShiftY(event)
}
function onTouchMove(event) {
moveBox(event)
}
function onTouchEnd(event) {
end()
}
function onMouseDown(event) {
if (event.target.tagName === "TEXTAREA") return; // just an example to skip the action to drag
start()
event.preventDefault();
$dragElem.style.cursor = "grabbing";
shiftY = getShiftY(event)
document.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseup", onMouseUp);
function onMouseMove(event) {
moveBox(event, shiftY)
}
function onMouseUp() {
end()
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseup", onMouseUp);
}
}
$dragElem.ondragstart = function() {
return false;
};
// helpers
function start() {
isClicked = true;
$dragElem.style.cursor = "grabbing";
}
function end() {
isClicked = false;
$dragElem.style.cursor = "grab";
}
function moveBox(event) {
if(!isClicked) return;
let points = getClientPoints(event)
let boxBottomEdge =
points.clientY + ($dragElem.getBoundingClientRect().height - shiftY);
let newB = $zoneElem.getBoundingClientRect().bottom - boxBottomEdge;
let topEdge = $zoneElem.offsetHeight - $dragElem.offsetHeight;
if (newB < margin) newB = margin;
if (newB > topEdge - margin) newB = topEdge - margin;
$dragElem.style.bottom = newB + "px";
}
function getClientPoints(event) {
return event.touches
? event.touches[0] || event.changedTouches[0]
: { clientY: event.clientY, clientX: event.clientX };
}
function getShiftY(event) {
let points = getClientPoints(event)
return points.clientY - $dragElem.getBoundingClientRect().top;
}
}
draggable.reset = function(dragElem, pos) {
const $dragElem = document.querySelector(dragElem);
$dragElem.style.bottom = pos;
};
export default draggable;
// Transform to class
// Because it will be easy to unmount the events and scale
function Draggable() {
this.version = 2.1;
this.$dragElem = undefined;
this.$zoneElem = undefined;
this.isClicked = false;
this.margin = 10;
this.shiftY = 0;
this.events = {};
this.helpers = {};
}
Draggable.prototype.init = function({ dragElem, zoneElemBefore }) {
this.initHelpers()
this.initEvents()
this.$dragElem = document.querySelector(dragElem);
this.$zoneElem = this.$dragElem.closest(zoneElemBefore);
this.ontouchstart = this.events.onTouchStart.bind(this)
this.ontouchmove = this.events.onTouchMove.bind(this)
this.ontouchend = this.events.onTouchEnd.bind(this)
this.onmousedown = this.events.onMouseDown.bind(this)
this.$dragElem.addEventListener("touchstart", this.ontouchstart);
this.$dragElem.addEventListener("touchmove", this.ontouchmove);
this.$dragElem.addEventListener("touchend", this.ontouchend);
this.$dragElem.addEventListener("mousedown", this.onmousedown);
this.$dragElem.style.cursor = "grab";
this.$dragElem.ondragstart = function() {
return false;
};
};
Draggable.prototype.initHelpers = function() {
const that = this
that.helpers.start = function() {
that.isClicked = true;
that.$dragElem.style.cursor = "grabbing";
};
that.helpers.end = function() {
that.isClicked = false;
that.$dragElem.style.cursor = "grab";
};
that.helpers.moveBox = function(event) {
if (!that.isClicked) return;
let points = that.helpers.getClientPoints(event);
let boxBottomEdge =
points.clientY +
(that.$dragElem.getBoundingClientRect().height - that.shiftY);
let newB = that.$zoneElem.getBoundingClientRect().bottom - boxBottomEdge;
let topEdge = that.$zoneElem.offsetHeight - that.$dragElem.offsetHeight;
if (newB < that.margin) newB = that.margin;
if (newB > topEdge - that.margin) newB = topEdge - that.margin;
that.$dragElem.style.bottom = newB + "px";
};
that.helpers.getClientPoints = function(event) {
return event.touches
? event.touches[0] || event.changedTouches[0]
: { clientY: event.clientY, clientX: event.clientX };
};
that.helpers.getShiftY = function(event) {
let points = that.helpers.getClientPoints(event);
return points.clientY - that.$dragElem.getBoundingClientRect().top;
};
};
Draggable.prototype.initEvents = function() {
const that = this
that.events.onTouchStart = function(event) {
that.helpers.start();
that.shiftY = that.helpers.getShiftY(event);
};
that.events.onTouchMove = function(event) {
that.helpers.moveBox(event);
};
that.events.onTouchEnd = function(_event) {
that.helpers.end();
};
that.events.onMouseDown = function (event) {
if (event.target.tagName === "TEXTAREA") return;
that.helpers.start();
event.preventDefault();
that.$dragElem.style.cursor = "grabbing";
that.shiftY = that.helpers.getShiftY(event);
document.addEventListener("mousemove", that.events.onMouseMove);
document.addEventListener("mouseup", that.events.onMouseUp);
};
that.events.onMouseMove = function(event) {
that.helpers.moveBox(event, that.shiftY);
};
that.events.onMouseUp = function() {
that.helpers.end();
document.removeEventListener("mousemove", that.events.onMouseMove);
document.removeEventListener("mouseup", that.events.onMouseUp);
};
};
Draggable.prototype.reset = function(pos) {
this.$dragElem.style.bottom = pos;
};
Draggable.prototype.unmount = function() {
this.helpers.end()
this.$dragElem.style.cursor = "initial";
this.$dragElem.removeEventListener("touchstart", this.ontouchstart);
this.$dragElem.removeEventListener("touchmove", this.ontouchmove);
this.$dragElem.removeEventListener("touchend", this.ontouchend);
this.$dragElem.removeEventListener("mousedown", this.onmousedown);
};
export default new Draggable();
function Draggable() {
this.version = 2.2;
this.$dragElem = undefined;
this.$zoneElem = undefined;
this.isClicked = false;
this.margin = 0;
this.shiftY = 0;
this.shiftX = 0;
this.events = {};
this.helpers = {};
}
Draggable.prototype.init = function({
dragElem,
zoneElemBefore,
vertical,
horizontal
}) {
this.initHelpers();
this.initEvents();
this.options = {
vertical: vertical || true,
horizontal: horizontal || true
};
this.$dragElem = document.querySelector(dragElem);
this.$zoneElem = this.$dragElem.closest(zoneElemBefore);
this.ontouchstart = this.events.onTouchStart.bind(this);
this.ontouchmove = this.events.onTouchMove.bind(this);
this.ontouchend = this.events.onTouchEnd.bind(this);
this.onmousedown = this.events.onMouseDown.bind(this);
this.$dragElem.addEventListener("touchstart", this.ontouchstart);
this.$dragElem.addEventListener("touchmove", this.ontouchmove);
this.$dragElem.addEventListener("touchend", this.ontouchend);
this.$dragElem.addEventListener("mousedown", this.onmousedown);
this.$dragElem.style.cursor = "grab";
this.$dragElem.ondragstart = function() {
return false;
};
};
Draggable.prototype.initHelpers = function() {
const that = this;
that.helpers.start = function() {
that.isClicked = true;
that.$dragElem.style.cursor = "grabbing";
};
that.helpers.end = function() {
that.isClicked = false;
that.$dragElem.style.cursor = "grab";
};
that.helpers.moveBox = function(event) {
if (!that.isClicked) return;
let points = that.helpers.getClientPoints(event);
// --- vertical
let newTop =
points.clientY - that.shiftY - that.$zoneElem.getBoundingClientRect().top;
let bottomEdge = that.$zoneElem.offsetHeight - that.$dragElem.offsetHeight;
if (newTop < 0) newTop = 0;
if (newTop > bottomEdge) newTop = bottomEdge;
// --- horizontal
let newLeft =
points.clientX -
that.shiftX -
that.$zoneElem.getBoundingClientRect().left;
let rightEdge = that.$zoneElem.offsetWidth - that.$dragElem.offsetWidth;
if (newLeft < 0) newLeft = 0;
if (newLeft > rightEdge) newLeft = rightEdge;
// ---
if (that.options.horizontal) that.$dragElem.style.left = newLeft + "px";
if (that.options.vertical) that.$dragElem.style.top = newTop + "px";
const percentHorizontal = (that.$dragElem.offsetLeft * 100) / rightEdge;
const percentVertical = (that.$dragElem.offsetTop * 100) / bottomEdge;
if (that.onchange) that.onchange(percentHorizontal, percentVertical);
};
that.helpers.getClientPoints = function(event) {
return event.touches
? event.touches[0] || event.changedTouches[0]
: { clientY: event.clientY, clientX: event.clientX };
};
that.helpers.getShiftY = function(event) {
let points = that.helpers.getClientPoints(event);
return points.clientY - that.$dragElem.getBoundingClientRect().top;
};
that.helpers.getShiftX = function(event) {
let points = that.helpers.getClientPoints(event);
return points.clientX - that.$dragElem.getBoundingClientRect().left;
};
};
Draggable.prototype.initEvents = function() {
const that = this;
that.events.onTouchStart = function(event) {
that.helpers.start();
that.shiftY = that.helpers.getShiftY(event);
that.shiftX = that.helpers.getShiftX(event);
};
that.events.onTouchMove = function(event) {
that.helpers.moveBox(event);
};
that.events.onTouchEnd = function(_event) {
that.helpers.end();
};
that.events.onMouseDown = function(event) {
that.helpers.start();
event.preventDefault();
that.$dragElem.style.cursor = "grabbing";
that.shiftY = that.helpers.getShiftY(event);
that.shiftX = that.helpers.getShiftX(event);
document.addEventListener("mousemove", that.events.onMouseMove);
document.addEventListener("mouseup", that.events.onMouseUp);
};
that.events.onMouseMove = function(event) {
that.helpers.moveBox(event);
};
that.events.onMouseUp = function() {
that.helpers.end();
document.removeEventListener("mousemove", that.events.onMouseMove);
document.removeEventListener("mouseup", that.events.onMouseUp);
};
};
Draggable.prototype.setHorizontal = function(perc) {
// TODO
};
Draggable.prototype.reset = function(pos) {
this.$dragElem.style.bottom = pos;
};
Draggable.prototype.unmount = function() {
this.helpers.end();
this.$dragElem.style.cursor = "initial";
this.$dragElem.removeEventListener("touchstart", this.ontouchstart);
this.$dragElem.removeEventListener("touchmove", this.ontouchmove);
this.$dragElem.removeEventListener("touchend", this.ontouchend);
this.$dragElem.removeEventListener("mousedown", this.onmousedown);
};
export default new Draggable();
/**
draggable.init({
dragElem: ".slider .thumb",
zoneElemBefore: ".slider",
vertical: false,
horizontal: true
});
draggable.onchange = (pX, pY) => {
console.log('percentHorizontal', pX)
};
*/
<div class="card draggable-zone">
<div class="wrapper draggable-box">
<div class="qx-question-result ">
<div>Draggable</div>
</div>
</div>
</div>
.draggable-zone{
height: 500px;
width: 400px;
}
.draggable-box{
position: relative;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment