Skip to content

Instantly share code, notes, and snippets.

@laphilosophia
Created December 11, 2019 22:13
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 laphilosophia/70d731c098041821e8cc08a2db782354 to your computer and use it in GitHub Desktop.
Save laphilosophia/70d731c098041821e8cc08a2db782354 to your computer and use it in GitHub Desktop.
export default () => {
let docElem = document.documentElement
let active = false
let hasDeactivated = false
let eventsBound = false
let mouseWheelHandler
let scrollHandler
const scrollCallback = (offset, event, callback) => {
if (!active) return true
let delta
let numPixelsPerStep
let change
let newOffset
let docOffset
let scrollWidth
let winWidth
let maxOffset
delta = 0
numPixelsPerStep = 10
docOffset = (docElem ? docElem.offsetWidth : 0) || 0
scrollWidth = document.body.scrollWidth || 0
winWidth = docElem ? docElem.clientWidth : 0
maxOffset = Math.max(docOffset, scrollWidth) - winWidth
if (Math.abs(event.wheelDeltaX) > Math.abs(event.wheelDeltaY)) return true
if (event.detail) {
delta = event.detail * -240
} else if (event.wheelDelta) {
delta = event.wheelDelta * 5
}
change = delta / 120 * numPixelsPerStep
newOffset = offset.x - change
if (newOffset >= 0 && newOffset <= maxOffset) {
offset.x = newOffset
offset.setByScript = true
window.scrollTo(offset.x, offset.y)
} else if (offset.x !== 0 && offset.x !== maxOffset) {
offset.x = newOffset > maxOffset ? maxOffset : 0
offset.setByScript = true
window.scrollTo(offset.x, offset.y)
}
if (typeof callback === "function") {
callback(offset)
}
return false
}
const getOffset = axis => {
axis = axis.toUpperCase()
let pageOffset = "page" + axis + "Offset"
let scrollValue = "scroll" + axis
let scrollDir = "scroll" + (axis === "X" ? "Left" : "Top")
return window[pageOffset] || window[scrollValue] || (function () {
var rootElem = document.documentElement || document.body.parentNode
return ((typeof rootElem[scrollDir] === "number") ? rootElem : document.body)[scrollDir]
}())
}
const bindEvents = (offset, cb) => {
const callback = e => {
e = e || window.event
let shouldPreventDefault = scrollCallback(offset, e, cb) === false
if (shouldPreventDefault) {
if (e.preventDefault && e.stopPropagation) {
e.preventDefault()
e.stopPropagation()
} else {
return false
}
}
}
const updateOffsetOnScroll = () => {
if (!offset.setByScript) {
offset.x = getOffset("x")
offset.y = getOffset("y")
}
offset.setByScript = false
}
mouseWheelHandler = callback
scrollHandler = updateOffsetOnScroll
if (window.addEventListener) {
if ("onmousewheel" in window) {
window.addEventListener("mousewheel", mouseWheelHandler, false)
window.addEventListener("scroll", scrollHandler, false)
} else {
window.addEventListener("DOMMouseScroll", mouseWheelHandler, false)
window.addEventListener("scroll", scrollHandler, false)
}
} else {
document.attachEvent("onmousewheel", mouseWheelHandler)
window.attachEvent("onscroll", scrollHandler)
}
}
const unbindEvents = () => {
if (!mouseWheelHandler && !scrollHandler) return
if (window.removeEventListener) {
if ("onmousewheel" in window) {
window.removeEventListener("mousewheel", mouseWheelHandler, false)
window.removeEventListener("scroll", scrollHandler, false)
} else {
window.removeEventListener("DOMMouseScroll", mouseWheelHandler, false)
window.removeEventListener("scroll", scrollHandler, false)
}
} else {
document.detachEvent("onmousewheel", mouseWheelHandler)
window.detachEvent("onscroll", scrollHandler)
}
}
const deactivateAllScrolling = e => {
e.preventDefault()
e.stopPropagation()
return false
}
return {
activate: callback => {
active = true
if (!eventsBound) {
let offset = {
x: 0,
y: 0
}
bindEvents(offset, callback)
eventsBound = true
}
if (hasDeactivated) {
if (window.addEventListener) {
window.removeEventListener("scroll", deactivateScrolling, true)
} else {
window.detachEvent("onscroll", deactivateScrolling)
}
hasDeactivated = false
}
},
deactivate: () => {
active = false
if (eventsBound) {
unbindEvents()
eventsBound = false
}
},
deactivateAllScrolling: () => {
active = false
hasDeactivated = true
if (window.addEventListener) {
window.addEventListener("scroll", deactivateScrolling, true)
} else {
window.attachEvent("onscroll", deactivateScrolling)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment