Last active
June 24, 2020 00:26
-
-
Save aarongeorge/2e1c970a4d0032e98fa2eb51bb40e00b to your computer and use it in GitHub Desktop.
A library for dragging DOM elements around
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Draggie.ts | |
* | |
* A library for dragging elements around | |
* | |
* Github: https://gist.github.com/aarongeorge/2e1c970a4d0032e98fa2eb51bb40e00b | |
* Demo: https://codepen.io/AaronGeorge/full/oGZoBg/ | |
*/ | |
interface Constraints { | |
x: { min: number, max: number } | |
y: { min: number, max: number } | |
} | |
interface Coordinates2D { | |
x: number | |
y: number | |
} | |
const defaultConstraints: Constraints = { | |
x: { min: -Infinity, max: Infinity }, | |
y: { min: -Infinity, max: Infinity } | |
} | |
const Draggie = class { | |
constraints: Constraints | |
dragPosition: Coordinates2D | |
element: HTMLElement | |
isDragging: boolean | |
mousePosition: Coordinates2D | |
constructor (element: HTMLElement, constraints = defaultConstraints) { | |
this.element = element | |
this.setConstraints(constraints) | |
this.isDragging = false | |
this.inputDown = this.inputDown.bind(this) | |
this.inputMove = this.inputMove.bind(this) | |
this.inputUp = this.inputUp.bind(this) | |
const { a, b, c, d, e, f } = this.getMatrix(this.element) | |
this.applyMatrix(this.element, a, b, c, d, e, f) | |
this.dragPosition = { x: e, y: f } | |
this.bindEvents() | |
} | |
inputDown (e) { | |
this.mousePosition = { | |
x: e.pageX ? e.pageX : e.targetTouches[0].pageX, | |
y: e.pageY ? e.pageY : e.targetTouches[0].pageY | |
} | |
this.isDragging = true | |
} | |
inputMove (e) { | |
if (this.isDragging) { | |
const currentTransform = this.getMatrix(this.element) | |
const newTransform = { | |
x: currentTransform.e + ((e.pageX ? e.pageX : e.targetTouches[0].pageX) - this.mousePosition.x), | |
y: currentTransform.f + ((e.pageY ? e.pageY : e.targetTouches[0].pageY) - this.mousePosition.y) | |
} | |
const clampedX = Math.min(Math.max(newTransform.x, this.constraints.x.min), this.constraints.x.max) | |
const clampedY = Math.min(Math.max(newTransform.y, this.constraints.y.min), this.constraints.y.max) | |
this.applyMatrix(this.element, currentTransform.a, currentTransform.b, currentTransform.c, currentTransform.d, clampedX, clampedY) | |
this.mousePosition = { | |
x: e.pageX ? e.pageX : e.targetTouches[0].pageX, | |
y: e.pageY ? e.pageY : e.targetTouches[0].pageY | |
} | |
this.dragPosition = { x: clampedX, y: clampedY } | |
} | |
} | |
inputUp () { | |
this.isDragging = false | |
} | |
bindEvents () { | |
this.element.addEventListener('mousedown', this.inputDown) | |
this.element.addEventListener('touchstart', this.inputDown) | |
document.addEventListener('mousemove', this.inputMove) | |
document.addEventListener('touchmove', this.inputMove) | |
document.addEventListener('mouseup', this.inputUp) | |
document.addEventListener('touchend', this.inputUp) | |
} | |
unbindEvents () { | |
this.element.removeEventListener('mousedown', this.inputDown) | |
this.element.removeEventListener('touchstart', this.inputDown) | |
document.removeEventListener('mousemove', this.inputMove) | |
document.removeEventListener('touchmove', this.inputMove) | |
document.removeEventListener('mouseup', this.inputUp) | |
document.removeEventListener('touchend', this.inputUp) | |
} | |
applyMatrix (element, a = 1, b = 0, c = 0, d = 1, e = 0, f = 0) { | |
element.style.transform = `matrix(${a}, ${b}, ${c}, ${d}, ${e}, ${f})` | |
} | |
setConstraints (userConstraints: Constraints) { | |
this.constraints = Object.assign({}, defaultConstraints, userConstraints) | |
} | |
getMatrix (element: HTMLElement) { | |
return new DOMMatrix(window.getComputedStyle(element).transform) | |
} | |
} | |
/** | |
* Initialise Draggie | |
*/ | |
// Create instance of `Draggie` | |
const test = new Draggie(document.querySelector('div')) | |
// Bind horizontal constraints | |
document.querySelector('[data-value=horizontal]').addEventListener('click', () => { | |
const {f} = test.getMatrix(test.element) | |
test.setConstraints({ | |
x: { min: -Infinity, max: Infinity }, | |
y: { min: f, max: f } | |
}) | |
test.element.innerText = 'Drag Me (Horizontal)' | |
}) | |
// Bind vertical constraints | |
document.querySelector('[data-value=vertical]').addEventListener('click', () => { | |
const {e} = test.getMatrix(test.element) | |
test.setConstraints({ | |
x: { min: e, max: e }, | |
y: { min: -Infinity, max: Infinity } | |
}) | |
test.element.innerText = 'Drag Me (Vertical)' | |
}) | |
// Bind remove constraints | |
document.querySelector('[data-value=remove]').addEventListener('click', () => { | |
test.setConstraints(defaultConstraints) | |
test.element.innerText = 'Drag Me (Unconstrained)' | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment