Why can't we use the relationship between speed and time to implement animation?

WBOY
Release: 2016-08-20 08:47:48
Original
990 people have browsed it

Since I recently made some animation effects on pages, I didn’t have much experience before. I encountered some problems during the process this time. In addition, I read a very good introduction to animation blog "About Animation, What You Need to Know" a long time ago. ", from Ten Years of Traces, so I thought about some issues about the basic principles of animation, such as this article. This question can be simple or very simple. For example, there is a better explanation in the blog mentioned earlier. This article provides another more detailed method. I hope it will be of value to those in need.

In the objective movement of objects, taking uniform linear motion as an example, we can use speed and time curves or displacement and time curves to describe the movement of objects at the same time:

Why cant we use the relationship between speed and time to implement animation?

Whether it is the relationship between speed and time or displacement To describe the linear motion of an objective object in relation to time, the state of the object is consistent. This is because the motion of the objective object always changes along the objective time axis that humans cannot change. At any point on the time axis, the state of the object is always the same. There are specific speeds and displacements corresponding to them.

In web animation, although it is also presented as motion, we cannot use the movement rules of objective objects to describe it. I think the main reason is that the essence of animation is not movement, but an instantaneous change in the state of an element based on a timer. Take the animation effect of a simple element's horizontal and uniform offset as an example. To achieve this animation, you only need to use a timer to reset the x-axis offset of the element at a fixed time interval. It can be described with a picture. As follows:

Why cant we use the relationship between speed and time to implement animation?T1~t6 in the figure represent the time when the timer callback function is executed. In this effect, the offset position of the element will change every time the timer is executed, but the offset position of the element will not change between two adjacent execution times. The animation we see is only because the timer interval is too short, and we cannot visually perceive the process of this period. If we increase the timer interval to long enough, we can see the status of the element during the interval. .

Because animation is not movement, when we try to understand some animation processes, we cannot think in terms of movement laws. For example, how should we understand the state at the moment when the animation stops? Taking the animation effect mentioned earlier as an example, when the timer is cleared, the animation stops instantly. For the element, its animation speed will suddenly become 0. If we analogize it to the movement of objective objects, the total It is taken for granted that the animation of an element should first decelerate before it can stop. If you think like this, you will not be able to understand the principle of sudden stop when the animation of an element stops. But when we think about this problem from the nature of animation, it is easy to understand, because the timer is the only element that changes the state of the element during the animation process. When the timer does not work, there is no external The power is used to change the state of the elements, how can it still move?

Although animation is not movement, we still hope to find a way to control the speed of animation well in order to create an animation effect that is smoother and closer to the objective world. When talking about speed, it is easy to think of speed, because in the movement of objective objects, speed is the element used to describe the speed of movement. And using speed rules to control the speed of animation seems easy to understand and implement. To make the previous example more specific, if we want to achieve the animation effect of an element shifting 120px to the right at a uniform speed within 1 second, then we only need to use a timer to control the element to shift a fixed amount to the right each time. Here The offset added to the element each time the timer is executed is the speed we use to control the animation. If we use 16ms as the timer interval, then the speed of this animation can be calculated by: 120px / (1000ms / 16ms) (approximately equal to 2px), that is to say, as long as the timer offsets the element to the right each time it is executed 2px can achieve the effect we want. The simple code implementation is as follows:

<span style="color: #0000ff"><span style="color: #ff00ff">doctype html</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"><span style="color: #800000">html </span><span style="color: #ff0000">lang</span><span style="color: #0000ff">="en"</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"><span style="color: #800000">head</span><span style="color: #0000ff">></span>
    <span style="color: #0000ff"><span style="color: #800000">meta </span><span style="color: #ff0000">charset</span><span style="color: #0000ff">="UTF-8"</span><span style="color: #0000ff">></span>
    <span style="color: #0000ff"><span style="color: #800000">title</span><span style="color: #0000ff">></span>Document<span style="color: #0000ff"></span><span style="color: #800000">title</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"></span><span style="color: #800000">head</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"><span style="color: #800000">body</span><span style="color: #0000ff">></span>
    <span style="color: #0000ff"><span style="color: #800000">div </span><span style="color: #ff0000">id</span><span style="color: #0000ff">="box"</span><span style="color: #ff0000"> style</span><span style="color: #0000ff">="width: 100px;height: 100px;background-color: goldenrod"</span><span style="color: #0000ff">></span>
    <span style="color: #0000ff"></span><span style="color: #800000">div</span><span style="color: #0000ff">></span>
    <span style="color: #0000ff"><span style="color: #800000">br</span><span style="color: #0000ff">></span>
    <span style="color: #0000ff"><span style="color: #800000">button </span><span style="color: #ff0000">type</span><span style="color: #0000ff">="button"</span><span style="color: #ff0000"> onclick</span><span style="color: #0000ff">="start()"</span><span style="color: #0000ff">></span>开始<span style="color: #0000ff"></span><span style="color: #800000">button</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"></span><span style="color: #800000">body</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"><span style="color: #800000">script</span><span style="color: #0000ff">></span>
    <span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> box </span><span style="color: #000000; background-color: #f5f5f5">=</span><span style="color: #000000; background-color: #f5f5f5"> document.getElementById(</span><span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">box</span><span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">);
    </span><span style="color: #0000ff; background-color: #f5f5f5">function</span><span style="color: #000000; background-color: #f5f5f5"> start() {
        </span><span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> duration </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #000000; background-color: #f5f5f5">1000</span><span style="color: #000000; background-color: #f5f5f5">;</span><span style="color: #008000; background-color: #f5f5f5">//</span><span style="color: #008000; background-color: #f5f5f5">动画时长</span>
        <span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> s </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #000000; background-color: #f5f5f5">120</span><span style="color: #000000; background-color: #f5f5f5">;</span><span style="color: #008000; background-color: #f5f5f5">//</span><span style="color: #008000; background-color: #f5f5f5">总的偏移量</span>
        <span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> cur_s </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #000000; background-color: #f5f5f5">0</span><span style="color: #000000; background-color: #f5f5f5">;</span><span style="color: #008000; background-color: #f5f5f5">//</span><span style="color: #008000; background-color: #f5f5f5">当前偏移总量</span>
        <span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> p </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #000000; background-color: #f5f5f5">16</span><span style="color: #000000; background-color: #f5f5f5">;</span><span style="color: #008000; background-color: #f5f5f5">//</span><span style="color: #008000; background-color: #f5f5f5">定时器间隔</span>
        <span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> speed </span><span style="color: #000000; background-color: #f5f5f5">=</span><span style="color: #000000; background-color: #f5f5f5"> s </span><span style="color: #000000; background-color: #f5f5f5">/</span><span style="color: #000000; background-color: #f5f5f5"> (duration </span><span style="color: #000000; background-color: #f5f5f5">/</span><span style="color: #000000; background-color: #f5f5f5"> p);</span><span style="color: #008000; background-color: #f5f5f5">//</span><span style="color: #008000; background-color: #f5f5f5">速度</span>
        <span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> count </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #000000; background-color: #f5f5f5">0</span><span style="color: #000000; background-color: #f5f5f5">;
        </span><span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> start_time </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #0000ff; background-color: #f5f5f5">new</span><span style="color: #000000; background-color: #f5f5f5"> Date().getTime();
        </span><span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> timer </span><span style="color: #000000; background-color: #f5f5f5">=</span><span style="color: #000000; background-color: #f5f5f5"> setInterval(</span><span style="color: #0000ff; background-color: #f5f5f5">function</span><span style="color: #000000; background-color: #f5f5f5">(){
            </span><span style="color: #0000ff; background-color: #f5f5f5">if</span><span style="color: #000000; background-color: #f5f5f5">(cur_s </span><span style="color: #000000; background-color: #f5f5f5">>=</span><span style="color: #000000; background-color: #f5f5f5"> s) {
                clearInterval(timer);
                console.log(</span><span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">动画运行时间(ms): </span><span style="color: #000000; background-color: #f5f5f5">'</span> <span style="color: #000000; background-color: #f5f5f5">+</span><span style="color: #000000; background-color: #f5f5f5"> (</span><span style="color: #0000ff; background-color: #f5f5f5">new</span><span style="color: #000000; background-color: #f5f5f5"> Date().getTime() </span><span style="color: #000000; background-color: #f5f5f5">-</span><span style="color: #000000; background-color: #f5f5f5"> start_time));
                </span><span style="color: #0000ff; background-color: #f5f5f5">return</span><span style="color: #000000; background-color: #f5f5f5">;
            }

            count</span><span style="color: #000000; background-color: #f5f5f5">++</span><span style="color: #000000; background-color: #f5f5f5">;
            cur_s </span><span style="color: #000000; background-color: #f5f5f5">=</span><span style="color: #000000; background-color: #f5f5f5"> speed </span><span style="color: #000000; background-color: #f5f5f5">*</span><span style="color: #000000; background-color: #f5f5f5"> count;
            box.style.transform </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">translateX(</span><span style="color: #000000; background-color: #f5f5f5">'</span> <span style="color: #000000; background-color: #f5f5f5">+</span><span style="color: #000000; background-color: #f5f5f5"> cur_s </span><span style="color: #000000; background-color: #f5f5f5">+</span> <span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">px)</span><span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">;
        },p);
    }
</span><span style="color: #0000ff"></span><span style="color: #800000">script</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"></span><span style="color: #800000">html</span><span style="color: #0000ff">></span></span></span></span></span></span></span></span></span></span></span>
Copy after login

在浏览器中运行以上代码,动画效果肯定是跟预期一致的,而且动画的实际执行时间也与规定的时长相差很小:

Why cant we use the relationship between speed and time to implement animation?

至于为什么不完全等于1000ms,那是因为多的那20多毫秒都耗费在了代码执行上。

通过这个例子,看起来,我们用速度去控制动画的思路还比较可行。事实上,这种思路是很有局限性的,我不是说它不行,只是说局限性,就是只能用于小部分的场合,而不能适用更广泛的动画效果中。为什么呢,原因有多个方面。

先从定时器说起。

定时器给了我们一种通过代码的方式来管理时间轴,但是这个时间轴与客观时间轴是有差别的。假如我们把一个动画的定时器间隔放大,放大到1000ms,让这个定时器执行10次,定时器执行的真实时间间隔会等于1000ms吗?

<span style="color: #0000ff"><span style="color: #800000">script</span><span style="color: #0000ff">></span>
    <span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> start </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #0000ff; background-color: #f5f5f5">new</span><span style="color: #000000; background-color: #f5f5f5"> Date().getTime(),count </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #000000; background-color: #f5f5f5">1</span><span style="color: #000000; background-color: #f5f5f5">;
    </span><span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> timer </span><span style="color: #000000; background-color: #f5f5f5">=</span><span style="color: #000000; background-color: #f5f5f5"> setInterval(</span><span style="color: #0000ff; background-color: #f5f5f5">function</span><span style="color: #000000; background-color: #f5f5f5">(){
        </span><span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> end </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #0000ff; background-color: #f5f5f5">new</span><span style="color: #000000; background-color: #f5f5f5"> Date().getTime();
        console.log(</span><span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">第</span><span style="color: #000000; background-color: #f5f5f5">'</span> <span style="color: #000000; background-color: #f5f5f5">+</span><span style="color: #000000; background-color: #f5f5f5"> count</span><span style="color: #000000; background-color: #f5f5f5">++</span> <span style="color: #000000; background-color: #f5f5f5">+</span> <span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">次执行,间隔:</span><span style="color: #000000; background-color: #f5f5f5">'</span> <span style="color: #000000; background-color: #f5f5f5">+</span><span style="color: #000000; background-color: #f5f5f5"> (end </span><span style="color: #000000; background-color: #f5f5f5">-</span><span style="color: #000000; background-color: #f5f5f5"> start));
        start </span><span style="color: #000000; background-color: #f5f5f5">=</span><span style="color: #000000; background-color: #f5f5f5"> end;

        </span><span style="color: #0000ff; background-color: #f5f5f5">if</span><span style="color: #000000; background-color: #f5f5f5">(count </span><span style="color: #000000; background-color: #f5f5f5">==</span> <span style="color: #000000; background-color: #f5f5f5">11</span><span style="color: #000000; background-color: #f5f5f5">) {
            clearInterval(timer);
        }
    },</span><span style="color: #000000; background-color: #f5f5f5">1000</span><span style="color: #000000; background-color: #f5f5f5">);
</span><span style="color: #0000ff"></span><span style="color: #800000">script</span><span style="color: #0000ff">></span></span>
Copy after login

以上代码模拟了一个动画,并且放大了动画的时间间隔,如果把它拿到浏览器中执行,我们会得到下面类似的结果:

Why cant we use the relationship between speed and time to implement animation?

从这个结果可以看出,虽然定时器的间隔设置为了1000ms,但是实际的执行间隔却只能说在1000左右浮动。这是很正常的,假如我们把操作系统的时间看成是客观的时间轴,那么浏览器里面定时器构建的时间轴只能是一个尽可能的接近客观时间轴的模拟时间轴。操作系统的状态,浏览器的状态,定时器内外代码的执行时间都会影响这根时间轴与客观时间轴的差距,只考虑浏览器内部,定时器内外的代码执行时间越长,这其中的差距越大。因为上面的代码是在一个很简单的网页中测试出来的,所以定时器的实际间隔与客观时间的偏差很小,要是一个页面内容比较多的时候,这个偏差一定会比现在的大。

时间轴的不稳定性,会直接导致速度的不稳定性,也就是说匀速运动都无法达到理想状态,更别说其它复杂的变速运动了。

单从这点来说,不管用什么方式控制运动,都会存在这个问题,所以它还并不能完全说明速度控制动画的根本问题所在。这个根本问题在于无法确保动画能够按照规定的时长完成。在上面的例子的基础上,我们想办法把定时器的时间轴与客观时间差的偏差放大,这个不难办到,只要在定时器执行过程中,加入一些耗时任务即可,代码如下:

<span style="color: #0000ff"><span style="color: #800000">script</span><span style="color: #0000ff">></span>
    <span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> start </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #0000ff; background-color: #f5f5f5">new</span><span style="color: #000000; background-color: #f5f5f5"> Date().getTime(), prev </span><span style="color: #000000; background-color: #f5f5f5">=</span><span style="color: #000000; background-color: #f5f5f5"> start, count </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #000000; background-color: #f5f5f5">1</span><span style="color: #000000; background-color: #f5f5f5">;

    </span><span style="color: #008000; background-color: #f5f5f5">//</span><span style="color: #008000; background-color: #f5f5f5">在动画模拟的第2和第3秒之间插入一个耗时任务</span>
<span style="color: #000000; background-color: #f5f5f5">    setTimeout(</span><span style="color: #0000ff; background-color: #f5f5f5">function</span><span style="color: #000000; background-color: #f5f5f5"> () {
        </span><span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> i </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #000000; background-color: #f5f5f5">0</span><span style="color: #000000; background-color: #f5f5f5">;
        </span><span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> cur </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #0000ff; background-color: #f5f5f5">new</span><span style="color: #000000; background-color: #f5f5f5"> Date().getTime();
        console.log(</span><span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">耗时任务开始,距动画开始时间:</span><span style="color: #000000; background-color: #f5f5f5">'</span> <span style="color: #000000; background-color: #f5f5f5">+</span><span style="color: #000000; background-color: #f5f5f5"> (cur</span><span style="color: #000000; background-color: #f5f5f5">-</span><span style="color: #000000; background-color: #f5f5f5">start));
        </span><span style="color: #0000ff; background-color: #f5f5f5">while</span><span style="color: #000000; background-color: #f5f5f5"> (</span><span style="color: #000000; background-color: #f5f5f5">++</span><span style="color: #000000; background-color: #f5f5f5">i </span><span style="color: #000000; background-color: #f5f5f5"> <span style="color: #000000; background-color: #f5f5f5">3000000000</span><span style="color: #000000; background-color: #f5f5f5">);
        </span><span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> cur2 </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #0000ff; background-color: #f5f5f5">new</span><span style="color: #000000; background-color: #f5f5f5"> Date().getTime();
        console.log(</span><span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">耗时任务结束,距动画开始时间:</span><span style="color: #000000; background-color: #f5f5f5">'</span> <span style="color: #000000; background-color: #f5f5f5">+</span><span style="color: #000000; background-color: #f5f5f5"> (cur2</span><span style="color: #000000; background-color: #f5f5f5">-</span><span style="color: #000000; background-color: #f5f5f5">start) </span><span style="color: #000000; background-color: #f5f5f5">+</span> <span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">,耗时:</span><span style="color: #000000; background-color: #f5f5f5">'</span> <span style="color: #000000; background-color: #f5f5f5">+</span><span style="color: #000000; background-color: #f5f5f5"> (cur2</span><span style="color: #000000; background-color: #f5f5f5">-</span><span style="color: #000000; background-color: #f5f5f5">cur));
    }, </span><span style="color: #000000; background-color: #f5f5f5">2400</span><span style="color: #000000; background-color: #f5f5f5">);

    </span><span style="color: #008000; background-color: #f5f5f5">//</span><span style="color: #008000; background-color: #f5f5f5">模拟一个动画</span>
    <span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> timer </span><span style="color: #000000; background-color: #f5f5f5">=</span><span style="color: #000000; background-color: #f5f5f5"> setInterval(</span><span style="color: #0000ff; background-color: #f5f5f5">function</span><span style="color: #000000; background-color: #f5f5f5"> () {
        </span><span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> end </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #0000ff; background-color: #f5f5f5">new</span><span style="color: #000000; background-color: #f5f5f5"> Date().getTime();
        console.log(</span><span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">第</span><span style="color: #000000; background-color: #f5f5f5">'</span> <span style="color: #000000; background-color: #f5f5f5">+</span><span style="color: #000000; background-color: #f5f5f5"> count</span><span style="color: #000000; background-color: #f5f5f5">++</span> <span style="color: #000000; background-color: #f5f5f5">+</span> <span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">次执行,间隔:</span><span style="color: #000000; background-color: #f5f5f5">'</span> <span style="color: #000000; background-color: #f5f5f5">+</span><span style="color: #000000; background-color: #f5f5f5"> (end </span><span style="color: #000000; background-color: #f5f5f5">-</span><span style="color: #000000; background-color: #f5f5f5"> prev));
        prev </span><span style="color: #000000; background-color: #f5f5f5">=</span><span style="color: #000000; background-color: #f5f5f5"> end;

        </span><span style="color: #0000ff; background-color: #f5f5f5">if</span><span style="color: #000000; background-color: #f5f5f5"> (count </span><span style="color: #000000; background-color: #f5f5f5">==</span> <span style="color: #000000; background-color: #f5f5f5">11</span><span style="color: #000000; background-color: #f5f5f5">) {
            clearInterval(timer);
        }
    }, </span><span style="color: #000000; background-color: #f5f5f5">1000</span><span style="color: #000000; background-color: #f5f5f5">);
</span><span style="color: #0000ff"></span><span style="color: #800000">script</span><span style="color: #0000ff">></span></span></span>
Copy after login

把以上代码在浏览器中运行,我们可以得到下面的类似结果:

Why cant we use the relationship between speed and time to implement animation?

根据以上结果中的时间范围,我们把这个例子的整个过程转换为时间轴示意图的话,就能看得更清晰了:

Why cant we use the relationship between speed and time to implement animation?

在这个图中,忽略了临界点之间的微小差距,因为只要观察那些大的差距,就能发现问题。结合前面的代码跟示意图,我们能看出:

由于有耗时任务的加入,导致动画的实际执行总时间接近于12s,比规定的动画时长多出整整2s。

虽然说从上面的图中也能看到另外一个问题,就是动画第三次执行的时间间隔被延长为3.67,而第四次执行的时间间隔被缩短为0.33s,会导致动画在这个时间段左右会看到不连贯不流畅的效果,但是这个问题不管用什么样的方式都会存在,只要有其它耗时任务在处理,动画定时器的回调就必须排队等待耗时任务完成才能执行。

无法控制动画在规定时长内完成,是不能用速度与时间的关系去实现动画的最重要的原因。

综上所述,为什么不用速度去控制动画有两个原因:

一是因为动画的时间轴的不稳定性(耗时任务会加大这种不稳定性),导致速度的变化规律很难把握。即使是匀速动画,我们也要考虑定时器的间隔,动画的偏移量,动画的时长三个参数才能计算出一个平均速度。如果是变速动画呢,比如我们想要一个动画先加速再匀速后减速,这种动画快慢的控制要求显然就无法轻易实现了。

二就是因为无法控制动画时长。

那么用什么样的方式来控制动画,就能够达到我们想要的轻易控制动画速度的目标呢?

用偏移量(位移)跟时间的关系吗?显然也是不行的,因为仅仅是单纯的速度控制改变为位移控制,并不会从根本上解决问题,因为速度与时间的关系还有位移与时间的关系是等价的。

速度无法控制动画时长的原因在于,由于已知的动画偏移量跟动画时长,导致动画定时器的执行次数也是固定的!所以只要某些次数定时器的实际执行时间超过理想的执行间隔,就会拉长动画时间轴跟客观时间轴的差距,就像上面示意图所看到的那样。

真正能解决动画时长的控制问题在于我们一定要用客观时间轴去控制动画。这个能做到吗?当然是可以的,来看看正确实现一个动画的方式,还是以前面那个小方块往右移动的动画为例,代码修改如下:

<span style="color: #0000ff"><span style="color: #ff00ff">doctype html</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"><span style="color: #800000">html </span><span style="color: #ff0000">lang</span><span style="color: #0000ff">="en"</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"><span style="color: #800000">head</span><span style="color: #0000ff">></span>
    <span style="color: #0000ff"><span style="color: #800000">meta </span><span style="color: #ff0000">charset</span><span style="color: #0000ff">="UTF-8"</span><span style="color: #0000ff">></span>
    <span style="color: #0000ff"><span style="color: #800000">title</span><span style="color: #0000ff">></span>Document<span style="color: #0000ff"></span><span style="color: #800000">title</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"></span><span style="color: #800000">head</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"><span style="color: #800000">body</span><span style="color: #0000ff">></span>
    <span style="color: #0000ff"><span style="color: #800000">div </span><span style="color: #ff0000">id</span><span style="color: #0000ff">="box"</span><span style="color: #ff0000"> style</span><span style="color: #0000ff">="width: 100px;height: 100px;background-color: goldenrod"</span><span style="color: #0000ff">></span>
    <span style="color: #0000ff"></span><span style="color: #800000">div</span><span style="color: #0000ff">></span>
    <span style="color: #0000ff"><span style="color: #800000">br</span><span style="color: #0000ff">></span>
    <span style="color: #0000ff"><span style="color: #800000">button </span><span style="color: #ff0000">type</span><span style="color: #0000ff">="button"</span><span style="color: #ff0000"> onclick</span><span style="color: #0000ff">="start()"</span><span style="color: #0000ff">></span>开始<span style="color: #0000ff"></span><span style="color: #800000">button</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"></span><span style="color: #800000">body</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"><span style="color: #800000">script</span><span style="color: #0000ff">></span>
    <span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> box </span><span style="color: #000000; background-color: #f5f5f5">=</span><span style="color: #000000; background-color: #f5f5f5"> document.getElementById(</span><span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">box</span><span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">);
    </span><span style="color: #0000ff; background-color: #f5f5f5">function</span><span style="color: #000000; background-color: #f5f5f5"> start() {
        </span><span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> duration </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #000000; background-color: #f5f5f5">1000</span><span style="color: #000000; background-color: #f5f5f5">;</span><span style="color: #008000; background-color: #f5f5f5">//</span><span style="color: #008000; background-color: #f5f5f5">动画时长</span>
        <span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> s </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #000000; background-color: #f5f5f5">120</span><span style="color: #000000; background-color: #f5f5f5">;</span><span style="color: #008000; background-color: #f5f5f5">//</span><span style="color: #008000; background-color: #f5f5f5">总的偏移量</span>
        <span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> start_time </span><span style="color: #000000; background-color: #f5f5f5">=</span><span style="color: #000000; background-color: #f5f5f5"> Date.now();
        </span><span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> timer </span><span style="color: #000000; background-color: #f5f5f5">=</span><span style="color: #000000; background-color: #f5f5f5"> setInterval(</span><span style="color: #0000ff; background-color: #f5f5f5">function</span><span style="color: #000000; background-color: #f5f5f5">(){

            </span><span style="color: #008000; background-color: #f5f5f5">//</span><span style="color: #008000; background-color: #f5f5f5">percent表示动画的进程</span>
            <span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> percent </span><span style="color: #000000; background-color: #f5f5f5">=</span><span style="color: #000000; background-color: #f5f5f5"> (Date.now() </span><span style="color: #000000; background-color: #f5f5f5">-</span><span style="color: #000000; background-color: #f5f5f5"> start_time) </span><span style="color: #000000; background-color: #f5f5f5">/</span><span style="color: #000000; background-color: #f5f5f5"> duration;

            </span><span style="color: #0000ff; background-color: #f5f5f5">if</span><span style="color: #000000; background-color: #f5f5f5">(percent </span><span style="color: #000000; background-color: #f5f5f5">>=</span> <span style="color: #000000; background-color: #f5f5f5">1.0</span><span style="color: #000000; background-color: #f5f5f5">) {
                percent </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #000000; background-color: #f5f5f5">1</span><span style="color: #000000; background-color: #f5f5f5">;
                clearInterval(timer);
                console.log(</span><span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">动画运行时间(ms): </span><span style="color: #000000; background-color: #f5f5f5">'</span> <span style="color: #000000; background-color: #f5f5f5">+</span><span style="color: #000000; background-color: #f5f5f5"> (</span><span style="color: #0000ff; background-color: #f5f5f5">new</span><span style="color: #000000; background-color: #f5f5f5"> Date().getTime() </span><span style="color: #000000; background-color: #f5f5f5">-</span><span style="color: #000000; background-color: #f5f5f5"> start_time));
            }

            box.style.transform </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">translateX(</span><span style="color: #000000; background-color: #f5f5f5">'</span> <span style="color: #000000; background-color: #f5f5f5">+</span><span style="color: #000000; background-color: #f5f5f5"> (Math.floor(s </span><span style="color: #000000; background-color: #f5f5f5">*</span><span style="color: #000000; background-color: #f5f5f5"> percent)) </span><span style="color: #000000; background-color: #f5f5f5">+</span> <span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">px)</span><span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">;
        },</span><span style="color: #000000; background-color: #f5f5f5">16</span><span style="color: #000000; background-color: #f5f5f5">);
    }
</span><span style="color: #0000ff"></span><span style="color: #800000">script</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"></span><span style="color: #800000">html</span><span style="color: #0000ff">></span></span></span></span></span></span></span></span></span></span></span>
Copy after login

The actual execution results are as follows:

Why cant we use the relationship between speed and time to implement animation?

Next, let’s summarize how to do this. First of all, you can see in the code that we use this method

Why cant we use the relationship between speed and time to implement animation?

Introduces the concept of animation process, and controls the completion of animation through animation process:

Why cant we use the relationship between speed and time to implement animation?

Since the percent animation process is based on the objective timeline, we can ensure that the animation can be completed within the specified time, and there will no longer be the problem that the animation execution time is extended when the speed control animation is used. (Of course, if we add a very time-consuming task during the animation execution, no animation can be completed within the specified time).

Then when we deal with the offset of the animation, we only need to add the total offset * animation process to get the offset at the current execution time.

Finally, when the animation progress is 1, the animation ends and the element is set to the total offset specified by the animation.

In general, this method converts the relationship between displacement and time into the relationship between offset and animation process. Through the animation process, you can simultaneously control the animation duration and the completion of the animation offset.

More importantly, the relationship between offset and animation process can be deduced through objective motion laws:

For example, in the above example, since it is a constant speed animation, its rule is:

Animation process p = t / T; (t = Date.now() – start_time ; T = duration)

Offset Sp = S * p; (S is the total offset; Sp is the current offset)

If it is other animations, such as uniform acceleration animation, uniform deceleration animation, and circular animation, we can also get similar rules. And the animation process calculation method for all animation effects is the same. The only difference is the relationship between the offset and the animation process:

Uniform acceleration: Sp=S * P2

Uniform deceleration: Sp=S * P * (2−P)

Circumferential x-axis: Sp=S * cos(ω * P)

Circumference y-axis: Sp=S * sin(ω * P)

(I have not studied the derivation of the above four relationships carefully. I have forgotten a lot of my previous mathematical knowledge. If you are interested, you can study "What You Need to Know About Animation")

For the same animation, applying the above different rules, you can see the animation change effects at different speeds, and finally achieve our goal of using animation to simulate the movement of objects in the real world.

Researching the relationship between these offsets and the animation process, we found that the total offset S is just a parameter in this relationship. When S is removed, we get a completely unrelated to S, just Equations related to the animation process:

Uniform speed: ep = p

Uniform acceleration: ep= P2

Uniform deceleration: ep= P * (2−P)

Circumference x-axis: ep= cos(ω * P)

Circumference y-axis: ep= sin(ω * P)

Using a function to represent all the above rules is: ep = E(P), P∈[0,1], P represents the animation process, and ep represents the completion percentage of the offset. What needs to be added is that this relationship must also meet a condition that when P=0, ep must be 0; when P=1, ep must be 1. This should be easy to understand, because P=0 and P=1, as well as ep=0 and ep=1 represent the start and end states of the animation respectively.

In other words, as long as we find a function that meets all the conditions of the previous paragraph, such as the previous ones, then this function can be used as a method for us to control the speed of animation. This function

It is the so-called animation operator ease. The following function Why cant we use the relationship between speed and time to implement animation?s can be used as animation operators:

Why cant we use the relationship between speed and time to implement animation?

有了这个规律,就赋予了动画效果控制无限的可能性,因为能满足前面那些条件的函数是无穷的。而这些看起来无穷尽的函数,我们能够轻松地通过贝塞尔曲线工具绘制出来,并且在css里面我们可以直接把这个工具的参数直接应用于transition跟animation里面。js里面也有bezier-easing 库可以使用这个工具的参数,然后应用到我们用js写的动画里面。比如:

<span style="color: #0000ff"><span style="color: #800000">script</span><span style="color: #0000ff">></span>
    <span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> box </span><span style="color: #000000; background-color: #f5f5f5">=</span><span style="color: #000000; background-color: #f5f5f5"> document.getElementById(</span><span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">box</span><span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">);
    </span><span style="color: #0000ff; background-color: #f5f5f5">function</span><span style="color: #000000; background-color: #f5f5f5"> start() {
        </span><span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> duration </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #000000; background-color: #f5f5f5">1000</span><span style="color: #000000; background-color: #f5f5f5">;</span><span style="color: #008000; background-color: #f5f5f5">//</span><span style="color: #008000; background-color: #f5f5f5">动画时长</span>
        <span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> s </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #000000; background-color: #f5f5f5">120</span><span style="color: #000000; background-color: #f5f5f5">;</span><span style="color: #008000; background-color: #f5f5f5">//</span><span style="color: #008000; background-color: #f5f5f5">总的偏移量</span>
        <span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> start_time </span><span style="color: #000000; background-color: #f5f5f5">=</span><span style="color: #000000; background-color: #f5f5f5"> Date.now();

        </span><span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> easing </span><span style="color: #000000; background-color: #f5f5f5">=</span><span style="color: #000000; background-color: #f5f5f5"> BezierEasing(</span><span style="color: #000000; background-color: #f5f5f5">0.86</span><span style="color: #000000; background-color: #f5f5f5">, </span><span style="color: #000000; background-color: #f5f5f5">0</span><span style="color: #000000; background-color: #f5f5f5">, </span><span style="color: #000000; background-color: #f5f5f5">0.07</span><span style="color: #000000; background-color: #f5f5f5">, </span><span style="color: #000000; background-color: #f5f5f5">1</span><span style="color: #000000; background-color: #f5f5f5">);

        </span><span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> timer </span><span style="color: #000000; background-color: #f5f5f5">=</span><span style="color: #000000; background-color: #f5f5f5"> setInterval(</span><span style="color: #0000ff; background-color: #f5f5f5">function</span><span style="color: #000000; background-color: #f5f5f5">(){

            </span><span style="color: #008000; background-color: #f5f5f5">//</span><span style="color: #008000; background-color: #f5f5f5">percent表示动画的进程</span>
            <span style="color: #0000ff; background-color: #f5f5f5">var</span><span style="color: #000000; background-color: #f5f5f5"> percent </span><span style="color: #000000; background-color: #f5f5f5">=</span><span style="color: #000000; background-color: #f5f5f5"> (Date.now() </span><span style="color: #000000; background-color: #f5f5f5">-</span><span style="color: #000000; background-color: #f5f5f5"> start_time) </span><span style="color: #000000; background-color: #f5f5f5">/</span><span style="color: #000000; background-color: #f5f5f5"> duration;

            </span><span style="color: #0000ff; background-color: #f5f5f5">if</span><span style="color: #000000; background-color: #f5f5f5">(percent </span><span style="color: #000000; background-color: #f5f5f5">>=</span> <span style="color: #000000; background-color: #f5f5f5">1.0</span><span style="color: #000000; background-color: #f5f5f5">) {
                percent </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #000000; background-color: #f5f5f5">1</span><span style="color: #000000; background-color: #f5f5f5">;
                clearInterval(timer);
                console.log(</span><span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">动画运行时间(ms): </span><span style="color: #000000; background-color: #f5f5f5">'</span> <span style="color: #000000; background-color: #f5f5f5">+</span><span style="color: #000000; background-color: #f5f5f5"> (</span><span style="color: #0000ff; background-color: #f5f5f5">new</span><span style="color: #000000; background-color: #f5f5f5"> Date().getTime() </span><span style="color: #000000; background-color: #f5f5f5">-</span><span style="color: #000000; background-color: #f5f5f5"> start_time));
            }

            box.style.transform </span><span style="color: #000000; background-color: #f5f5f5">=</span> <span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">translateX(</span><span style="color: #000000; background-color: #f5f5f5">'</span> <span style="color: #000000; background-color: #f5f5f5">+</span><span style="color: #000000; background-color: #f5f5f5"> (Math.floor(s </span><span style="color: #000000; background-color: #f5f5f5">*</span><span style="color: #000000; background-color: #f5f5f5"> easing(percent))) </span><span style="color: #000000; background-color: #f5f5f5">+</span> <span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">px)</span><span style="color: #000000; background-color: #f5f5f5">'</span><span style="color: #000000; background-color: #f5f5f5">;
        },</span><span style="color: #000000; background-color: #f5f5f5">16</span><span style="color: #000000; background-color: #f5f5f5">);
    }
</span><span style="color: #0000ff"></span><span style="color: #800000">script</span><span style="color: #0000ff">></span></span>
Copy after login

总之,有了ease跟贝塞尔曲线工具,要实现不同的动画速度控制效果,就变成一件特别容易的事情了。

最后,希望这篇文章能帮助到一些朋友更好理解动画的原理以及动画速度控制的正确方式。

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template