Last active
January 2, 2019 13:21
-
-
Save kyleparisi/6aaf592026ec90bf511b7ac71264736f to your computer and use it in GitHub Desktop.
A single script to handle dragging of html or svg elements
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
function coroutine(f) { | |
var o = f(); // instantiate the coroutine | |
o.next(); // execute until the first yield | |
return function(x) { | |
o.next(x); | |
} | |
} | |
var loop = coroutine(function*() { | |
var e; | |
while (e = yield) { | |
if (e.type == 'mousedown') { | |
while (e = yield) { | |
if (e.type == 'mousemove') | |
move(e); | |
if (e.type == 'mouseup') | |
break; | |
} | |
} | |
// ignore mousemoves | |
} | |
}); | |
$('#box').mousedown(loop); | |
$(window).mousemove(loop) | |
.mouseup(loop); |
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
try { | |
if (document) { | |
} | |
} catch (e) { | |
throw new Error("Drag module only works in browsers"); | |
} | |
const Drag = function(view) { | |
let documentation = ` | |
# Usage | |
\`Drag([HTMLElement] view).in([HTMLElement] document.body)\` -> draghandler | |
For side affect changes: | |
draghandler | |
.onDrag([Function] fn) | |
`; | |
if (!view) { | |
console.warn("No view defined for drag handler"); | |
return; | |
} | |
let handler = { | |
get: (state, key) => { | |
if (key === "endDrag") { | |
delete state.drag; | |
if (state.dragging) { | |
delete state.dragging; | |
} | |
return state; | |
} | |
if (key === "state") { | |
return state; | |
} | |
return state[key]; | |
}, | |
set: function(state, property, value) { | |
if (property === "mouse") state.mouse = value; | |
let valid = [true]; | |
if (property === "dragging") { | |
state.dragging = value; | |
// if dragging is not an array, make it an array | |
if (!(state.dragging instanceof Array)) | |
state.dragging = new Array(state.dragging); | |
// validate all the entries | |
valid = state.dragging.map(currentValue => { | |
if ( | |
!(currentValue instanceof HTMLElement) && | |
!(currentValue instanceof SVGElement) | |
) { | |
console.error( | |
"Dragging property is not an HTMLElement", | |
currentValue | |
); | |
return false; | |
} | |
}); | |
// establish all the initial positions for the drag | |
state.drag = state.dragging.map(currentValue => { | |
return { | |
startX: view.offsetLeft, | |
startY: view.offsetTop, | |
startMouseX: state.mouse.clientX, | |
startMouseY: state.mouse.clientY | |
}; | |
}); | |
} | |
// conduct modifications of elements | |
if (property === "mouse" && state.dragging && valid[0]) { | |
state.dragging.map((currentValue, index) => { | |
// amount traveled | |
state.drag[index].dx = value.clientX - state.drag[index].startMouseX; | |
state.drag[index].dy = value.clientY - state.drag[index].startMouseY; | |
state.left = state.drag[index].startX + state.drag[index].dx; | |
state.styleLeft = state.left + "px"; | |
state.right = | |
state.left + Math.round(currentValue.getBoundingClientRect().width); | |
state.styleRight = state.right + "px"; | |
state.top = state.drag[index].startY + state.drag[index].dy; | |
state.styleTop = state.top + "px"; | |
}); | |
window.getSelection().removeAllRanges(); | |
state.onDrag(); | |
} | |
return state; | |
} | |
}; | |
let cbs = []; | |
let state = { | |
documentation: documentation, | |
in: function(boundry) { | |
boundry.addEventListener("mousemove", e => (proxy.mouse = e)); | |
return this; | |
}, | |
onDrag: function(cb) { | |
if (cb) { | |
cbs.push(cb); | |
return false; | |
} | |
cbs.map(callback => { | |
callback(state); | |
}); | |
} | |
}; | |
let proxy = new Proxy(state, handler); | |
view.onmousedown = e => { | |
proxy.dragging = e.target; | |
}; | |
view.onmouseup = () => proxy.endDrag; | |
return proxy; | |
}; | |
// allow to be used as common js module for browserify, etc. | |
try { | |
module.exports = Drag; | |
} catch (e) {} |
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
try { | |
if (document) {} | |
} catch(e) { | |
throw new Error('Drag module only works in browsers') | |
} | |
var Drag = function (view) { | |
let documentation = | |
` | |
# Usage | |
\`Drag([HTMLElement] view).in([HTMLElement] document.body)\` -> draghandler | |
For side affect changes: | |
draghandler | |
.onDrag([Function] fn) | |
`; | |
if (!view) { | |
console.warn('No view defined for drag handler'); | |
return | |
} | |
let handler = { | |
get: (state, key) => { | |
if (key === 'endDrag') { | |
delete state.drag; | |
if (state.dragging) { | |
var els = document.querySelectorAll('.dragging'); | |
[].forEach.call(els, function(el) { | |
el.className = el.className.replace('dragging', 'draggable'); | |
}); | |
delete state.dragging | |
} | |
} | |
if (key === 'state') { | |
return state | |
} | |
return state[key] | |
}, | |
set: function (state, property, value) { | |
if (property === 'mouse') state.mouse = value; | |
var valid = [true]; | |
if (property === 'dragging') { | |
state.dragging = value; | |
// if dragging is not an array, make it an array | |
if (!(state.dragging instanceof Array)) state.dragging = new Array(state.dragging); | |
// validate all the entries | |
valid = state.dragging.map((currentValue) => { | |
if (!(currentValue instanceof HTMLElement) && | |
!(currentValue instanceof SVGElement)) { | |
console.error('Dragging property is not an HTMLElement', currentValue); | |
return false; | |
} | |
if ((!currentValue.style || !currentValue.style.position) && | |
!(currentValue instanceof SVGElement)) { | |
console.error('Element needs to have style position: fixed', currentValue) | |
return false; | |
} | |
}); | |
// establish all the initial positions for the drag | |
state.drag = state.dragging.map((currentValue) => { | |
return { | |
startX: currentValue.offsetLeft, | |
startY: currentValue.offsetTop, | |
startMouseX: state.mouse.clientX, | |
startMouseY: state.mouse.clientY | |
} | |
}) | |
} | |
// conduct modifications of elements | |
if (property === 'mouse' && state.dragging && valid[0]) { | |
state.dragging.map((currentValue, index) => { | |
state.drag[index].dx = value.clientX - state.drag[index].startMouseX; | |
state.drag[index].dy = value.clientY - state.drag[index].startMouseY; | |
state.left = state.drag[index].startX + state.drag[index].dx; | |
state.right = state.left + Math.round(currentValue.getBoundingClientRect().width); | |
currentValue.style.left = state.left + 'px'; | |
state.top = state.drag[index].startY + state.drag[index].dy; | |
currentValue.style.top = state.top + 'px'; | |
currentValue.className = currentValue.className.replace('draggable', 'dragging'); | |
}); | |
state.onDrag() | |
} | |
return state | |
} | |
}; | |
let cbs = []; | |
let state = { | |
documentation: documentation, | |
in: function (boundry) { | |
boundry.addEventListener('mousemove', e => proxy.mouse = e); | |
return this | |
}, | |
onDrag: function (cb) { | |
if (cb) cbs.push(cb); | |
cbs.map(callback => { | |
callback(state) | |
}) | |
} | |
}; | |
let proxy = new Proxy(state, handler); | |
view.onmousedown = e => { | |
if (e.target.classList[0] === 'draggable') { | |
proxy.dragging = e.target; | |
} | |
}; | |
view.onmouseup = () => proxy.endDrag; | |
return proxy | |
}; | |
// allow to be used as common js module for browserify, etc. | |
try { | |
module.exports = Drag | |
} catch (e) { | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment