I'm recently learning about "linear interpolation" & its ability to create easing. Nevertheless, the easing part of the draggable slider seem to be working... However, I can't drag the slider past the 3rd slides. There seems to be some kind of inertia prompting the slider to bounce back to the 1st slide.
HTML
<main class='container'>
<div class='slider'>
<div class='slider__slide'>1</div>
<div class='slider__slide'>2</div>
<div class='slider__slide'>3</div>
<div class='slider__slide'>4</div>
<div class='slider__slide'>5</div>
<div class='slider__slide'>6</div>
<div class='slider__slide'>7</div>
<div class='slider__slide'>8</div>
<div class='slider__slide'>9</div>
</div>
</main>
CSS
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,body {
width: 100%;
height: 100%;
font-size: 100%;
}
body {
display: grid;
place-items: center;
}
.container {
width: 90vw;
height: 35vh;
overflow-x: auto;
scrollbar-width: none;
cursor: grab;
}
.container::-webkit-scrollbar { display: none; }
.slider {
height: 100%;
display: flex;
gap: 0.25rem;
}
.slider__slide {
min-width: 30vw;
font: 900 1rem helvetica,sans-serif;
background-color: rgb(65, 61, 70);
color: white;
display: grid;
place-items: center;
}
.slider.active { cursor: grabbing; }
JS
const slider = document.querySelector('.slider');
let active;
let startX = 0;
let endX = 0;
let initLeft;
function start(e) {
active = true;
slider.classList.add('active');
startX = e.pageX - slider.offsetLeft;
initLeft = slider.scrollLeft;
}
function end() {
active = false;
slider.classList.remove('active');
}
function move(e) {
if (!active) return;
e.preventDefault();
endX = e.pageX - slider.offsetLeft;
}
const lerp = (start,end,t) => start * (1-t) + end * t;
function update() {
startX = lerp(startX,endX,0.05);
const dist = endX - startX;
slider.scrollLeft = initLeft - dist;
requestAnimationFrame(update);
}
window.addEventListener('load',update,false);
slider.addEventListener('pointerdown',start,false);
slider.addEventListener('pointermove',move,false);
window.addEventListener('pointerup',end,false);
If I was to take out the following line of code with the "lerp", then the slider will work as intended without the easing.
startX = lerp(startX,endX,0.05);
I can't seem to wrap my head around this problem. Can someone please help point me in the right direction? Any feedback will be greatly appreciated.
UPDATE:
Finally figured it out:
const container = document.querySelector('.container');
const slider = document.querySelector('.slider');
let startX,endX;
let startLeft,endLeft;
let raf;
const lerp = (start,end,t) => start * (1-t) + end * t;
function update() {
startLeft = lerp(startLeft,endLeft,0.03);
const dist = (endX - startX) * 0.05;
container.scrollLeft = startLeft - dist;
raf = requestAnimationFrame(update);
if (startLeft.toFixed(1) === endLeft.toFixed(1)) cancelAnimationFrame(raf);
}
function move(e) {
endX = e.layerX
endLeft = container.scrollLeft
cancelAnimationFrame(raf);
raf = requestAnimationFrame(update);
}
function end() {
slider.classList.remove('active');
container.removeEventListener('pointermove',move);
container.removeEventListener('pointerup',end);
container.removeEventListener('pointerleave',end);
}
function activate(e) {
e.preventDefault();
slider.classList.add('active');
startX = e.layerX;
endX = e.layerX;
startLeft = container.scrollLeft;
endLeft = container.scrollLeft;
container.addEventListener('pointermove',move,false);
container.addEventListener('pointerup',end,false);
container.addEventListener('pointerleave',end,false);
}
container.addEventListener('pointerdown',activate,false);
I believe I found the issue, when any given "value" is given in lerp it will always go from its value and multiply by 0.05 moving to 0. After this happens we need to add the total distance that the slider has moved in one direction
The slider will always default to the start position. Try modifying the lerp constant to add the distance moved into account after multiplying by the "value" which is already defined as "dist".