Skip to content

Instantly share code, notes, and snippets.

@whatwewant
Last active May 16, 2018 05:59
Show Gist options
  • Save whatwewant/c785a6cdc1b01d8f430e896568cd9128 to your computer and use it in GitHub Desktop.
Save whatwewant/c785a6cdc1b01d8f430e896568cd9128 to your computer and use it in GitHub Desktop.
enable element move anywhere on browser
function isSupportPassive() {
let isSupport = false;
try {
const opts = Object.defineProperty({}, 'passive', {
get() {
isSupport = true;
},
});
window.addEventListener('test', null, opts);
} catch (e) {
//
}
return isSupport;
}
const passiveOptions = isSupportPassive() ? {
passive: true,
capture: false,
} : false;
function setStyle($node, name, value) {
$node.style[name] = typeof value === 'number' ? `${value}px` : value; // eslint-disable-line
}
function $(selector) {
return typeof selector === 'string' ? document.querySelector(selector) : selector;
}
export default class Movable {
/**
* Constructor
* params:
* handlerSelector: handler document node selector.
* containerSelector: container document node selector.
* boundable: support have boundary, default false.
*/
constructor(options = {}) {
const {
handlerSelector = '.handler',
containerSelector = '.container',
boundable = false,
} = options;
this.$handler = $(handlerSelector);
this.$container = $(containerSelector);
this.state = {
boundable,
movable: false,
currentX: 0,
currentY: 0,
top: 0,
left: 0,
maxLeft: 0,
maxTop: 0,
};
this.listen();
}
/**
* style memebers: handler + container
* 1 make container position absolute
* 2 make handler cursor as move
*/
styledMembers() {
// @1 make container absolute
setStyle(this.$container, 'position', 'absolute');
// @2 make handler cusor move
setStyle(this.$handler, 'cursor', 'move');
}
listen() {
this.styledMembers();
// @1 mouse down on handler
this.$handler.addEventListener('mousedown', this.onMouseDown, passiveOptions);
// @2 mouse up on document
document.addEventListener('mouseup', this.onMouseUp, passiveOptions);
// @3 mouse move on documnent
document.addEventListener('mousemove', this.onMouseMove, passiveOptions);
}
onMouseDown = (event) => {
const {
top,
left,
width,
height,
} = this.$container.getBoundingClientRect();
this.state.top = top;
this.state.left = left;
this.state.width = width;
this.state.height = height;
this.state.maxLeft = window.innerWidth - width;
this.state.maxTop = window.innerHeight - height;
this.state.currentX = event.clientX;
this.state.currentY = event.clientY;
this.state.movable = true;
};
onMouseUp = () => {
this.state.movable = false;
};
onMouseMove = (event) => {
if (!this.state.movable) return false;
const deltaX = event.clientX - this.state.currentX;
const deltaY = event.clientY - this.state.currentY;
let left = this.state.left + deltaX;
let top = this.state.top + deltaY;
if (this.state.boundable) {
if (left < 0) {
left = 0;
} else if (left > this.state.maxLeft) {
left = this.state.maxLeft;
}
if (top < 0) {
top = 0;
} else if (top > this.state.maxTop) {
top = this.state.maxTop;
}
}
setStyle(this.$container, 'top', top);
setStyle(this.$container, 'left', left);
};
}
// test
new Movable('.handler', '.container', true);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment