Skip to content

Instantly share code, notes, and snippets.

@jesperlandberg
Created June 25, 2020 16:22
Show Gist options
  • Select an option

  • Save jesperlandberg/3230e85f2934e3c4ef13980d2b7fd55c to your computer and use it in GitHub Desktop.

Select an option

Save jesperlandberg/3230e85f2934e3c4ef13980d2b7fd55c to your computer and use it in GitHub Desktop.
import gsap from 'gsap'
import { evt, u, store } from '@/app/index'
const { flags, bounds } = store
const { rect, qsa, qs } = u
export default class {
constructor(elems = qsa('[data-smooth-item]')) {
this.elems = elems
this.resizing = false
this.init()
}
init() {
this.getSections()
this.addEvents()
}
addEvents() {
evt.on('scroll', this.scroll)
evt.on('tick', this.run)
evt.on('resize', this.resize)
}
getSections() {
if (!this.elems) return
const last = this.elems.length - 1
const { wh } = bounds
bounds.scroll = rect(this.elems[last]).bottom - wh
this.sections = [...this.elems].map((el, i) => {
el.style.transform = 'translate3d(0, 0, 0)'
const { top, bottom } = rect(el)
return {
el,
current: top < wh ? 'a' : 'b',
start: top - bounds.wh,
end: bottom,
out: true,
}
})
this.state = {
target: 0,
current: 0,
a: {
min: -wh,
max: bounds.scroll,
current: 0
},
b: {
min: 0,
max: bounds.scroll + wh,
current: 0
}
}
}
run = () => {
const state = this.state
if (!state) return
const { a, b } = this.state
state.current += (state.target - state.current) * 0.11
a.current = gsap.utils.wrap(a.min, a.max, state.current)
b.current = gsap.utils.wrap(b.min, b.max, state.current)
!this.resizing && this.transformSections()
}
transformSections() {
if (flags.locked) return
const state = this.state
this.sections.length > 0 &&
this.sections.forEach((s) => {
const current = state[s.current].current
const visible = this.visible(s, current)
if (visible || this.resizing) {
s.out && (s.out = false)
this.transform(s.el, current)
} else if (!s.out) {
s.out = true
this.transform(s.el, current)
}
})
}
scroll = ({ y }) => {
this.state.target += y
}
transform(el, current) {
el.style.transform = `translate3d(0, ${-current}px, 0)`
}
visible({ start, end }, current) {
return current > start && current < end
}
resize = () => {
this.resizing = true
this.getSections()
evt.emit('resize:on-reset')
this.transformSections()
this.resizing = false
}
removeEvents() {
evt.off('scroll', this.scroll)
evt.off('tick', this.run)
evt.off('resize', this.resize)
}
destroy() {
this.removeEvents()
this.sections = this.elems = null
evt.emit('scroll:on-reset')
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment