Created
October 15, 2021 10:14
-
-
Save jesperlandberg/5c4e85fe76a32bf4b67224b16c7ac481 to your computer and use it in GitHub Desktop.
This file contains 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
import VirtualScroll from 'virtual-scroll' | |
import gsap from 'gsap' | |
const bounds = { | |
ww: window.innerWidth, | |
wh: window.innerHeight | |
} | |
export default class { | |
constructor() { | |
this.elems = [...document.querySelectorAll('.js-item')] | |
this.state = { | |
target: 0, | |
current: 0, | |
diff: 0, | |
a: { | |
min: 0, max: 0, | |
current: 0 | |
}, | |
b: { | |
min: 0, max: 0, | |
current: 0, | |
}, | |
movement: 0, | |
resizing: false | |
} | |
this.setCache() | |
this.addEvents() | |
} | |
addEvents() { | |
this.vs = new VirtualScroll() | |
this.vs.on(this.scroll) | |
gsap.ticker.fps(-1) | |
gsap.ticker.add(this.tick) | |
} | |
setCache() { | |
const { wh } = bounds | |
const { a, b } = this.state | |
const last = this.elems.length - 1 | |
this.cache = this.elems.map((el, i) => { | |
el.style.transform = 'translate3d(0, 0, 0)' | |
const { top, bottom } = el.getBoundingClientRect() | |
if (i === last) { | |
const max = bottom - wh | |
a.min = -wh | |
a.max = max | |
b.min = 0 | |
b.max = max + wh | |
} | |
return { | |
el, start, end, | |
current: top < wh ? 'a' : 'b', | |
start: top - wh, | |
end: bottom, | |
out: true | |
} | |
}) | |
} | |
scroll = ({ deltaY }) => { | |
this.state.target -= deltaY | |
} | |
tick = () => { | |
const state = this.state | |
const { a, b, resizing } = state | |
if (!a || !b) return | |
state.movement += 1 | |
state.current += (state.target - state.current) * 0.1 | |
state.current = Math.round(state.current * 100) / 100 | |
state.diff = (state.target - state.current) * 0.01 | |
a.current = gsap.utils.wrap(a.min, a.max, state.current + state.movement) | |
b.current = gsap.utils.wrap(b.min, b.max, state.current + state.movement) | |
!resizing && this.transformElements() | |
} | |
transformElements() { | |
const state = this.state | |
this.cache.length > 0 && | |
this.cache.forEach(c => { | |
const current = state[c.current].current | |
const visible = this.visible(c, current) | |
if (visible || state.resizing) { | |
c.out && (c.out = false) | |
this.transform(c.el, current) | |
} else if (!c.out) { | |
c.out = true | |
this.transform(c.el, current) | |
} | |
}) | |
} | |
visible({ start, end }, current) { | |
return current > start && current < end | |
} | |
transform(el, current) { | |
el.style.transform = `translate3d(0, ${-current}px, 0)` | |
} | |
resize = () => { | |
const state = this.state | |
state.resizing = true | |
this.setCache() | |
state.current = state.target | |
this.transformElements() | |
state.resizing = false | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment