Skip to content

Instantly share code, notes, and snippets.

@abhiomkar
Created March 14, 2018 16:37
Show Gist options
  • Save abhiomkar/e741a0f7aff587090584c770d6f14cfa to your computer and use it in GitHub Desktop.
Save abhiomkar/e741a0f7aff587090584c770d6f14cfa to your computer and use it in GitHub Desktop.
import {
tween,
styler,
decay,
listen,
pointer,
value,
transform,
spring,
physics,
} from 'popmotion';
const {smooth, conditional, nonlinearSpring, snap} = transform;
const PHYSICS_FRICTION = 0.3;
class Portfolio {
constructor(portfolioEl) {
this.portfolioEl = portfolioEl;
this.slider = portfolioEl.querySelector('.slider');
this.debugEl = document.querySelector('#debug');
const divStyler = styler(this.slider);
this.sliderX = value(0, divStyler.set('x'));
this.sliderWidth = this.calcSliderWidth();
this.maxScroll = this.calcMaxScroll();
this.isSpringMotion = false;
this.dragDistance = -1;
this.attachEvents();
}
calcMaxScroll() {
return Math.abs(
this.calcSliderWidth() - this.portfolioEl.getBoundingClientRect().width,
);
}
calcSliderWidth() {
const firstItem = this.slider.querySelector('.item:first-child');
const firstItemRect = firstItem.getBoundingClientRect();
const lastItem = this.slider.querySelector('.item:last-child');
const lastItemRect = lastItem.getBoundingClientRect();
return lastItemRect.x - firstItemRect.x + lastItemRect.width;
}
attachEvents() {
let pointerAction;
let scrollPhysics;
let wheelPhysics;
listen(this.slider, 'wheel').start((event) => {
if (this.isSpringMotion) return;
wheelPhysics && wheelPhysics.stop();
const velocity = 20 * event.deltaX * -1;
wheelPhysics = physics({
from: this.sliderX.get(),
friction: PHYSICS_FRICTION,
velocity: velocity,
})
.pipe(
(x) => x,
conditional((x) => x > 0, nonlinearSpring(0.1, 0)),
conditional(
(x) => x < -1 * this.maxScroll,
nonlinearSpring(0.1, -1 * this.maxScroll),
),
)
.start(this.sliderX);
});
listen(this.slider, 'mousedown touchstart').start(() => {
pointerAction && pointerAction.stop();
scrollPhysics && scrollPhysics.stop();
wheelPhysics && wheelPhysics.stop();
pointerAction = pointer({x: this.sliderX.get()})
.pipe(
({x}) => x,
conditional((x) => x > 0, nonlinearSpring(2, 0)),
conditional(
(x) => x < -1 * this.maxScroll,
nonlinearSpring(2, -1 * this.maxScroll),
),
)
.start({
update: (x) => {
this.dragDistance++;
this.sliderX.update(x);
},
});
this.sliderXOnClick = this.sliderX.get();
});
listen(document, 'mouseup touchend').start((event) => {
pointerAction && pointerAction.stop();
// Scroll to clicked item.
if (this.dragDistance === 0) {
this.scrollToItem(event.target.closest('.item'));
this.dragDistance = -1;
return;
}
this.dragDistance = -1;
if (this.didReachEdge()) {
this.springToEdge();
return;
}
scrollPhysics = physics({
from: this.sliderX.get(),
friction: PHYSICS_FRICTION,
acceleration: 0.8,
velocity: this.sliderX.getVelocity(),
}).start({
update: (x) => {
this.sliderX.update(x);
if (this.didReachEdge()) {
scrollPhysics.stop();
this.springToEdge();
} else {
}
},
});
});
}
springToEdge() {
this.isSpringMotion = true;
spring({
from: this.sliderX.get(),
to: this.didReachLeftEdge() ? 0 : this.maxScroll * -1,
velocity: this.sliderX.getVelocity() * 0.6,
stiffness: 200,
damping: 80,
}).start({
update: (x) => {
this.sliderX.update(x);
this.debugEl.innerHTML = 'Spring: IN_PROGRESS';
},
complete: (x) => {
this.isSpringMotion = false;
this.debugEl.innerHTML = 'Spring: STOPPED';
},
});
}
didReachEdge() {
return this.didReachLeftEdge() || this.didReachRightEdge();
}
didReachRightEdge() {
return this.sliderX.get() < -1 * this.maxScroll;
}
didReachLeftEdge() {
return this.sliderX.get() > 0;
}
scrollToItem(item) {
const rect = item.getBoundingClientRect();
tween({
from: this.sliderX.get(),
to: item.offsetLeft * -1,
})
.pipe(
(x) => x,
conditional((x) => x > 0, nonlinearSpring(0.1, 0)),
conditional(
(x) => x < -1 * this.maxScroll,
nonlinearSpring(0.1, -1 * this.maxScroll),
),
)
.start(this.sliderX);
}
}
export default Portfolio;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment