Search code examples
javascripteasinglerp

Lerp from one position to another in a specified duration with javascript


Ok so I am trying to ease a box from one place to another using Linear Interpolation. But It doesn't seem to easing it is just moving without easing. So I have read the post here C# Lerping from position to position and maybe I am misunderstanding the equation. Here is what I have so far.

const lerp = (start, end, speed) => start + (end - start) * speed

const div = document.querySelector('div')
const btn = document.querySelector('button')

let pos = 0
let startTime = 0
const duration = 2000
let aF = null

const animate = () => {
  const elapsed = Date.now() - startTime
  const t = elapsed / duration

  if(elapsed < duration) {
    pos = lerp(0, 300, t)
    aF = requestAnimationFrame(animate)
  } else {
    cancelAnimationFrame(aF)
    aF = null
    pos = 300
  }

  console.log(pos, 300 * t)

  div.style.transform = `translateX(${pos}px)`
}

btn.addEventListener('click', () => {
  pos = 0
  startTime = Date.now()
  aF = requestAnimationFrame(animate)
})
div {
  width: 50px;
  height: 50px;
  background: green;
}

button {
  margin-bottom: 10px; 
}
<button>Run Animation</button>

<div></div>

So in the example you can see the box is just animating without any easing. In the console log you can se the values are the same even though I am lerping on value and not he other.

I know there is something I am not understanding here but I don't know what that is. Any help would be appreciated. Thanks.


Solution

  • Your example is working (a + (a-b) * t). It is just that the interpolation is missing. Interpolation is the art of remapping a value (t in your case) between 0-1 to again 0-1 using a different function (so a + (a-b) * t becomes a + (a-b) * interpolate(t)). There are infinite amount of such functions, I chose some popular ones and included them in your example:

    let interpolators = {
                identity: function(t){
                    t = Math.max(0,Math.min(1,t));
                    return t;
                },
                cubic: function(t){
                    t = Math.max(0,Math.min(1,t));
                    if(2*t<<0){
                        return 4*(t-1)*(t-1)*(t-1)+1;
                    } else {
                        return 4*t*t*t;
                    }
                },
                elastic: function(t){
                    t = Math.max(0,Math.min(1,t));
                    var range = 10.5*Math.PI;
                    return (range - Math.sin(range*t)/t)/(range - 1);
                }
            };
    

    the most important change is:

    const t = interpolators[selected](elapsed / duration);

    https://jsfiddle.net/ibowankenobi/6ctp9a0s/26/