0

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);
noirsociety
  • 314
  • 1
  • 2
  • 9

1 Answers1

0

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

    const lerp = (min, max, value) => (max - min) * value + min;

function update() {
  startX = lerp(startX,endX,);
  const dist = endX - startX;
  slider.scrollLeft = initLeft - dist;
  requestAnimationFrame(update);
}

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".

  • thanks for the reply. I interpolated the "scrollLeft" property instead of "pageX" which fixed the drag + scroll & easing problem. However, a new problem arises whenever I click on the slider, it would shift forward or backward before returning to the initial click position.[Here is the pen](https://codepen.io/noirsociety/pen/gOjagmJ) – noirsociety Dec 25 '22 at 07:26
  • I do not know the origin of this error however, it is caused the mouse position if it is on the left it will move left and if it is on the right of the center it will come from the right so, one of the mouse values. If you set the "value" value for lerp to something lower like 0.000005 you can see when you click your mouse near the center it will move one directions and it looks to be about half a square.Maybe a problem in subtracting the value between the end of the slider and the mouse position? – Curious Chimpanzee Dec 25 '22 at 17:38