Skip to content

Instantly share code, notes, and snippets.

@jesperlandberg
Last active April 30, 2020 07:13
Show Gist options
  • Select an option

  • Save jesperlandberg/8592188b8b4ffb7662d600d45fdefa3b to your computer and use it in GitHub Desktop.

Select an option

Save jesperlandberg/8592188b8b4ffb7662d600d45fdefa3b to your computer and use it in GitHub Desktop.
import gsap from 'gsap'
import store from '@/store'
import Events from './Events'
import { lerp } from '@/utils'
const { isDevice, isDesktop } = store.flags
export default new (class {
constructor() {
this.target = 0
this.current = 0
this.rounded = 0
this.ease = 0.115
this.init()
}
tick = () => {
if (store.flags.locked) return
if (isDevice) { // Mobile devices
this.target = window.scrollY
Events.emit('tick', {
target: this.target,
current: this.target,
})
} else { // Desktop devices
this.current = lerp(this.current, this.target, this.ease)
this.rounded = Math.round(this.current * 100) / 100
this.diff = (this.target - this.current) * 0.0005
Events.emit('tick', {
target: this.target,
current: this.rounded,
})
}
}
clamp() {
this.target = gsap.utils.clamp(0, store.bounds.scroll, this.target)
}
onScroll = ({ y }) => {
this.target += y
this.clamp()
}
reset() {
this.target = this.current = this.rounded = 0
}
resize = () => {
this.clamp()
this.rounded = this.current = this.target
}
init() {
gsap.ticker.fps(-1)
gsap.ticker.add(this.tick)
if (isDesktop) {
Events.on('scroll', this.onScroll)
Events.on('resize:on-reset', this.resize)
}
}
})()
import debounce from 'lodash.debounce'
import store from '@/store'
import Events from './Events'
export default new (class {
constructor() {
const { dom, bounds } = store
this.setOrientation(dom, bounds)
Events.on('resize', window, debounce(this.resize, 200))
Events.on('orientationchange', window, this.resize)
}
resize = () => {
const { dom, bounds, flags } = store
const ww = window.innerWidth
if (flags.isDevice && ww === bounds.ww) return
bounds.ww = ww
bounds.wh = window.innerHeight
this.setOrientation(dom, bounds)
Events.emit('resize')
}
setOrientation({ body }, { wh, ww }) {
ww < wh
? body.classList.add('is-portrait')
: body.classList.remove('is-portrait')
}
})()
import VirtualScroll from 'virtual-scroll'
import store from '@/store'
import Events from './Events'
import Pointer from './Pointer'
export default new (class {
constructor() {
const { windows, isDesktop } = store.flags
if (isDesktop) {
this.vs = new VirtualScroll({
mouseMultiplier: windows ? 1.1 : 0.45,
touchMultiplier: 2.75,
firefoxMultiplier: windows ? 40 : 90,
}).on(this.onVS)
}
}
onVS = ({ deltaY }) => {
if (store.flags.locked) return
Pointer.run()
Events.emit('scroll', { y: deltaY * -1 })
}
})()
import store from '@/store'
import { Events, GlobalRaf } from '@/events'
import { qs, qsa, rect } from '@/utils'
export default new (class {
constructor() {
this.el = store.dom.scroll || qs('[data-smooth]')
this.elems = null
this.current = 0
this.last = null
this.resizing = false
this.sections = null
this.initial = false
}
init(elems) {
this.elems = elems
this.getSections()
this.addEvents()
}
addEvents() {
Events.on('tick', this.run)
Events.on('resize', this.resize)
}
update(elems) {
this.elems = elems
this.getSections()
}
go(elems = qsa('[data-smooth-item]')) {
if (!elems) {
GlobalRaf.reset()
} else if (!this.initial) {
this.init(elems)
this.initial = true
} else {
this.update(elems)
GlobalRaf.reset()
}
}
getSections() {
if (!this.elems) return
const { bounds } = store
const last = this.elems[this.elems.length - 1]
this.sections = [...this.elems].map((el) => {
el.style.transform = 'translate3d(0, 0, 0)'
const { top, bottom } = rect(el)
el === last && (bounds.scroll = bottom - bounds.wh)
return {
el,
start: top - bounds.wh,
end: bottom,
out: true,
}
})
}
run = ({ current }) => {
this.current = current
if (Math.abs(this.last - this.current) <= 0.001) return
!this.resizing && this.transformSections()
this.last = this.current
}
transformSections() {
if (store.flags.locked) return
this.sections.length > 0 &&
this.sections.forEach((s) => {
const visible = this.visible(s)
if (visible || this.resizing) {
s.out && (s.out = false)
this.transform(s.el)
} else if (!s.out) {
s.out = true
this.transform(s.el)
}
})
}
transform(el) {
el.style.transform = `translate3d(0, ${-this.current}px, 0)`
}
visible({ start, end }) {
return this.current > start && this.current < end
}
resize = () => {
this.resizing = true
this.getSections()
Events.emit('resize:on-reset')
this.transformSections()
this.resizing = false
}
clean() {
this.elems = this.sections = null
}
removeEvents() {
Events.off('tick', this.run)
Events.off('resize', this.resize)
}
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment