Skip to content

Instantly share code, notes, and snippets.

@Dexdot
Created July 16, 2019 10:11
Show Gist options
  • Save Dexdot/f912e3bf4e59171ba187d3bc8ca89f39 to your computer and use it in GitHub Desktop.
Save Dexdot/f912e3bf4e59171ba187d3bc8ca89f39 to your computer and use it in GitHub Desktop.
animations on scroll
const math = {
map: (x, a, b, c, d) => ((x - a) * (d - c)) / (b - a) + c,
lerp: (a, b, n) => (1 - n) * a + n * b
};
const { body } = document;
// Window
let winsize;
const calcWinsize = () => {
winsize = { width: window.innerWidth, height: window.innerHeight };
};
calcWinsize();
window.addEventListener('resize', calcWinsize);
// Scroll
let docScroll = 1;
const getPageYScroll = () => {
docScroll = window.pageYOffset || document.documentElement.scrollTop;
};
window.addEventListener('scroll', getPageYScroll);
function randomIntFromInterval(min, max) {
// min and max included
return Math.floor(Math.random() * (max - min + 1) + min);
}
// Parallax
export default class ParallaxImage {
constructor(el) {
this.DOM = { el };
this.DOM.img = $.qs('img', this.DOM.el);
this.renderedStyles = {
innerTranslationY: {
previous: 0,
current: 0,
ease: 0.075,
maxValue: randomIntFromInterval(15, 30),
setValue: () => {
const { maxValue } = this.renderedStyles.innerTranslationY;
const minValue = -1 * maxValue;
return Math.max(
Math.min(
math.map(
this.props.top - docScroll,
winsize.height,
// -1 * this.props.height,
-1 * this.props.width,
minValue,
maxValue
),
maxValue
),
minValue
);
}
},
scale: {
previous: 0,
current: 0,
ease: 0.1,
minValue: 1,
maxValue: 1.3,
setValue: () => {
const { minValue, maxValue } = this.renderedStyles.scale;
return Math.max(
Math.min(
math.map(
this.props.top - docScroll,
winsize.height,
// -1 * this.props.height,
-1 * this.props.width,
minValue,
maxValue
),
maxValue
),
minValue
);
}
},
rotate: {
previous: 0,
current: 0,
ease: 0.1,
minValue: 0,
maxValue: 350,
setValue: () => {
const { minValue, maxValue } = this.renderedStyles.rotate;
return Math.max(
Math.min(
math.map(
this.props.top - docScroll,
winsize.height,
// -1 * this.props.height,
-1 * this.props.width,
minValue,
maxValue
),
maxValue
),
minValue
);
}
}
};
this.update();
this.observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
this.isVisible = entry.intersectionRatio > 0;
});
});
this.observer.observe(this.DOM.el);
this.initEvents();
}
update() {
this.getSize();
for (const key in this.renderedStyles) {
this.renderedStyles[key].current = this.renderedStyles[
key
].previous = this.renderedStyles[key].setValue();
}
this.layout();
}
getSize() {
const rect = this.DOM.el.getBoundingClientRect();
this.props = {
height: rect.height,
width: rect.width,
top: docScroll + rect.top
};
}
initEvents() {
window.addEventListener('resize', () => this.resize());
}
resize() {
this.update();
}
render() {
for (const key in this.renderedStyles) {
this.renderedStyles[key].current = this.renderedStyles[key].setValue();
this.renderedStyles[key].previous = math.lerp(
this.renderedStyles[key].previous,
this.renderedStyles[key].current,
this.renderedStyles[key].ease
);
}
this.layout();
}
layout() {
this.DOM.img.style.transform = `translate3d(${this.renderedStyles.innerTranslationY.previous}px,0,0)
scale(${this.renderedStyles.scale.previous})
rotate(${this.renderedStyles.rotate.previous}deg)`;
}
}
window.addEventListener('DOMContentLoaded', () => {
const images = [];
$.each('.js-parallax', el => {
images.push(new ParallaxImage(el));
});
function animate() {
images.forEach(img => {
if (img.isVisible) {
img.render();
}
});
requestAnimationFrame(() => animate());
}
requestAnimationFrame(() => animate());
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment