0

I have a animation like this in CSS

.outer {
  margin: 50px;
}

.inner{
  border: 1px solid black;
  border-radius: 3px;
  width: 100%;
  height: 30px;
  display: block;
  background: linear-gradient(to right, hotpink 50%, transparent 0);
  background-size: 200% 100%;
  background-position: right;
  animation: makeItfadeIn 3s 1s forwards;
}

@keyframes makeItfadeIn {
  100% {
    background-position: left;
  }
}
<div class="outer">
  <div class="inner">
  </div>
  <input type="range" value="20" min="0" max="100" class="inner"/>
</div>

I need to run a second animation, which I control from JavaScript. I want to animate the thumb of <input type='range' />. It needs to slide from left to right to a certain position. Setting the position of the thumb is only possible from the JS side, thus the animation must be controlled in JS aswell.

This would be easy: But, the positioning must run completly in sync with the animation created in CSS. I can detect when the animation makeItfadeIn starts on the CSS side, however, how to construct a function in Javascript, that mimics the animation: makeItfadeIn 3s 1s forwards;: fast at the beginning, slowing down in the end, ... so that the thumb of the range starts at value=0 and moves in sync with the hotpink bar to value=100?

four-eyes
  • 10,740
  • 29
  • 111
  • 220

1 Answers1

0

That was a wild ride :) There is a cool library at https://github.com/gre/bezier-easing that we can use to calculate the "Y axis" of a cubic bezier - HOWEVER, MASSIVE CAVEAT I didn't figure out how to actually convert named curves like ease-in-out to actual numbers - so this only works for custom curves like I have in my CSS at the moment.

Massive props to Convert CSS cubic bezier easing to Javascript

document.addEventListener("DOMContentLoaded", () => {
    const b = document.querySelector("b")
    const i = document.querySelector("input")
    const e = document.querySelector("span")
    const a = e.getAnimations()[0]
    const d = a.effect.getTiming().duration

    const atf = getComputedStyle(e)["animation-timing-function"].toString()

    console.log("Easing function", atf)
    const curveAsNumbers = atf.match(/[\d]+[.\d]*/g)

    const easing = BezierEasing(...curveAsNumbers);
    setInterval(() => {
        const easingFunctionX = (a.currentTime % d) / d
        const percent = easing(easingFunctionX)
        b.innerText = (percent*100).toFixed(0)
        i.value = Number(percent*100)
    }, 10)
})
span {
    display: inline-block;
    animation: rota 4s infinite cubic-bezier(1, 0.11, 0.95, 0.32);
}
@keyframes rota {
    0% {rotate: 0deg;}
    100% {rotate: 360deg;}
}
<script src="
https://cdn.jsdelivr.net/npm/bezier-easing@2.1.0/dist/bezier-easing.min.js
"></script>
<span>:D</span><input type="range" min="0" max="100">
<br>
Animation is <b></b>% done
Joel Peltonen
  • 13,025
  • 6
  • 64
  • 100
  • Hmmh. Now that I look back I think you mean that the range thing would start slow and end fast as well following the timing function. Damn, the math there is MUCH MUCH MUCH harder, but you can get the values for the math with `e.computedStyleMap().getAll("animation-timing-function")["0"].toString()` where e is the element that is animated – Joel Peltonen Mar 24 '23 at 15:56
  • Perhaps you could actually copy the animation completely from the target element CSS to JS and then to the range. – Joel Peltonen Mar 24 '23 at 15:58
  • Hey, thanks for the effort. That is exactly the problem. The function I am using the CSS side is not linear, making the whole thing really complicated. I thought there might a library or something, copying the behaviour of the availabel CSS functions. – four-eyes Mar 26 '23 at 09:06
  • @four-eyes hooray - I did find a library to do the calculation. Hoooowwwweeever, it's a pain to use and very limited, I cannot figure out how to turn something like `ease-in-out` into actual numbers :( – Joel Peltonen Mar 27 '23 at 08:42
  • I think its very hard. I refrained from doing it and manipulated the opacity. Once the animation is finished, the other object just fades in. I mean, there should be some sort of function used in CSS which might be publicly available. But I have no idea where to look for it. – four-eyes Mar 27 '23 at 09:51