DevStarlight DevStarlight - 5 months ago 19
Javascript Question

animate slide a div when li selected without animate()

I was trying to animate my topbar by adding a

position: absolute
<div>
which
left
style attribute was changing depending of the selected tab.

After so much trying, I don't get the right way for not to start from the beginning if I try to go from the second to the third tab.
The main problem for this case is here:

element.style.left = ((to - last) * 33 * delta) + (last * 33) + '%';


delta
is starting at 0 and ends at the indicated value. It should be starting at the actual position.

As well, I tried to go from the third tab to the second and I didn't get the solution.

Here bellow I paste the plunkr where I've been working.

Could someone help me with this?

Thanks in advice.

Answer

It didn't work because you didn't set last after the animation completes. I added an onComplete callback in your script to handle that. Also, the step function in both directions actually use the same formula:

'use strict';

var last = 0;

function elastic(progress) {
  return Math.pow(2, 10 * (progress - 1)) * Math.cos(20 * Math.PI * 1.5 / 3 * progress);
}

function linear(progress) {
  return progress;
}

function quad(progress) {
  return Math.pow(progress, 2);
}

function quint(progress) {
  return Math.pow(progress, 5);
}

function circ(progress) {
  return 1 - Math.sin(Math.acos(progress));
}

function back(progress) {
  return Math.pow(progress, 2) * ((1.5 + 1) * progress - 1.5);
}

function bounce(progress) {
  var a, b, result;
  
  for (a = 0, b = 1, result; 1; a += b, b /= 2) {
    if (progress >= (7 - 4 * a) / 11) {
      return -Math.pow((11 - 6 * a - 11 * progress) / 4, 2) + Math.pow(b, 2);
    }
  }
}

function makeEaseInOut(delta) {
  return function (progress) {
    if (progress < 0.5) {
      return delta(2 * progress) / 2;
    } else {
      return (2 - delta(2 * (1 - progress))) / 2;
    }
  };
}

function makeEaseOut(delta) {
  return function (progress) {
    return 1 - delta(1 - progress);
  };
}

function animate(opts) {
  
  var start = new Date();
  
  var id = setInterval(function () {
    
    var timePassed = new Date() - start;
    
    var progress = timePassed / opts.duration;
    
    if (progress > 1) {
      progress = 1;
    }
    
    var delta = opts.delta(progress);
    
    opts.step(delta);
    
    if (progress === 1) {
      clearInterval(id);
      opts.onComplete();
    }
    
  }, opts.delay);
}

function move(to) {
  var element = document.getElementById('nb-line');
  var delta = quint;
  var duration = 400;

  animate({
    delay: 10,
    duration: duration || 1000,
    delta: delta,
    step: function (delta) {
        element.style.left = (((to - last) * 33 * delta) + (last * 33)) + '%';
    },
    onComplete: function() {
      last = to;
    }
  });
}
.li-cont {
  width: 100%;
  height: 30px;
  display: flex;
}
li {
  list-style: none;
  width: 33%;
  height: 100%;
}
a {
  text-align: center;
  display: flex;
  align-items: center;
  display: block;
  width: 100%;
  height: 100%;
}
#nb-line {
  width: 33%;
  height: 5px;
  background-color: blue;
  position: absolute;
}
<!DOCTYPE html>
<html>

  <head>
    <link rel="stylesheet" href="style.css">
    <script src="script.js"></script>
  </head>
  
  <body>
    <div class="li-cont">
      <li><a onclick="move(0)">1</a></li>
      <li><a onclick="move(1)">2</a></li>
      <li><a onclick="move(2)">3</a></li>
    </div>
    <div id="nb-line"></div>
  </body>

</html>