왜 애니메이션을 구현하는데 속도와 시간의 관계를 이용할 수 없나요?

WBOY
풀어 주다: 2016-08-20 08:47:48
원래의
990명이 탐색했습니다.

최근 페이지 애니메이션 효과를 만들어 본 경험이 별로 없어서 이번에 작업하면서 몇 가지 문제에 부딪혔습니다. 그리고 애니메이션 블로그 "About Animation, What You Need"에 대한 좋은 소개를 읽었습니다. 오래 전.”이라는 제목의 10년의 흔적을 읽고 이 글과 같은 애니메이션의 기본 원리에 대한 몇 가지 질문을 생각해 보았습니다. 이 질문은 간단할 수도 있고 매우 간단할 수도 있습니다. 예를 들어, 앞서 언급한 블로그에 더 자세한 설명이 있습니다. 도움이 필요한 사람들에게 더 자세한 방법이 제공되기를 바랍니다.

물체의 객관적인 움직임에서 등속선운동을 예로 들면 속도와 시간곡선 또는 변위와 시간곡선을 동시에 사용하여 물체의 움직임을 기술할 수 있습니다.

왜 애니메이션을 구현하는데 속도와 시간의 관계를 이용할 수 없나요?

객체의 직선 운동을 속도와 시간의 관계로 표현하든, 변위와 시간의 관계를 사용하든, 객체의 상태는 항상 일정하기 때문입니다. 인간이 변경할 수 없는 객관적인 경로를 따르며, 시간 축의 어느 지점에서든 그에 상응하는 특정 속도와 변위가 항상 존재합니다.

웹 애니메이션에서는 모션으로도 표현되지만 객관적인 객체의 움직임 규칙을 사용하여 설명할 수 없습니다. 그 주된 이유는 애니메이션의 본질은 움직임이 아니라, 타이머에 따른 요소 상태의 즉각적인 변화 때문이라고 생각합니다. 간단한 요소의 수평 균일 오프셋 애니메이션 효과를 예로 들면, 타이머를 사용하여 고정된 시간 간격으로 요소의 x축 오프셋을 재설정하기만 하면 됩니다.

왜 애니메이션을 구현하는데 속도와 시간의 관계를 이용할 수 없나요?

그림의 T1~t6은 타이머 콜백 함수가 실행되는 시간을 나타냅니다. 이 효과에서는 타이머가 실행될 때마다 요소의 오프셋 위치가 변경되지만 요소의 오프셋 위치는 인접한 두 실행 시간 간에 변경되지 않습니다. 우리가 보는 애니메이션은 타이머 간격이 너무 짧아서 이 기간의 과정을 시각적으로 인식할 수 없기 때문에 발생합니다. 타이머 간격을 충분히 길게 늘리면 간격 동안 요소의 상태를 볼 수 있습니다.

애니메이션은 움직임이 아니기 때문에 일부 애니메이션 프로세스를 이해하려고 하면 움직임 법칙을 고려할 수 없습니다. 예를 들어 애니메이션이 멈추는 순간의 상태를 어떻게 이해해야 할까요? 앞서 언급한 애니메이션 효과를 예로 들면, 타이머가 지워지면 애니메이션이 즉시 중지됩니다. 요소의 경우 애니메이션 속도가 갑자기 0이 됩니다. 이를 객관적 개체의 움직임에 비유하면 총합은 0이 됩니다. 요소의 애니메이션이 멈추기 전에 먼저 감속 과정을 거쳐야 한다는 것은 당연합니다. 이렇게 생각하면 요소의 애니메이션이 멈출 때 갑자기 멈추는 원리를 이해할 수 없습니다. 하지만 이 문제를 애니메이션의 본질에서 생각해보면 이해하기 쉽습니다. 왜냐하면 타이머가 애니메이션 과정에서 요소의 상태를 변경하는 유일한 요소이기 때문입니다. 타이머가 작동하지 않을 때 외부적인 요소가 없기 때문입니다. 힘은 요소의 상태를 변경하는 데 사용됩니다. 어떻게 여전히 움직일 수 있습니까?

애니메이션은 움직임이 아니지만, 보다 부드럽고 객관적인 세계에 가까운 애니메이션 효과를 만들기 위해 애니메이션의 속도를 잘 제어할 수 있는 방법을 찾고자 합니다. 속도를 이야기할 때 속도를 생각하기 쉽습니다. 객관적인 물체의 움직임에 있어서 속도는 이동 속도를 설명하는 데 사용되는 요소이기 때문입니다. 그리고 속도 규칙을 사용하여 애니메이션 속도를 제어하는 ​​것은 이해하고 구현하기 쉬운 것 같습니다. 이전 예를 좀 더 구체적으로 설명하자면, 요소가 1초 내에 일정한 속도로 오른쪽으로 120px 이동하는 애니메이션 효과를 얻으려면 타이머를 사용하여 요소가 고정된 양만큼 이동하도록 제어하기만 하면 됩니다. 여기서는 타이머가 실행될 때마다 요소에 추가되는 오프셋이 애니메이션을 제어하는 ​​데 사용되는 속도입니다. 타이머 간격으로 16ms를 사용하면 이 애니메이션의 속도는 120px / (1000ms / 16ms) (대략 2px와 동일)로 계산할 수 있습니다. 즉, 타이머가 요소를 오른쪽으로 오프셋하는 한 실행될 때마다 2px는 우리가 원하는 효과를 얻을 수 있습니다. 간단한 코드 구현은 다음과 같습니다.

<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>
로그인 후 복사

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

왜 애니메이션을 구현하는데 속도와 시간의 관계를 이용할 수 없나요?

至于为什么不完全等于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>
로그인 후 복사

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

왜 애니메이션을 구현하는데 속도와 시간의 관계를 이용할 수 없나요?

从这个结果可以看出,虽然定时器的间隔设置为了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>
로그인 후 복사

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

왜 애니메이션을 구현하는데 속도와 시간의 관계를 이용할 수 없나요?

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

왜 애니메이션을 구현하는데 속도와 시간의 관계를 이용할 수 없나요?

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

由于有耗时任务的加入,导致动画的实际执行总时间接近于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>
로그인 후 복사

실제 실행 결과는 다음과 같습니다.

왜 애니메이션을 구현하는데 속도와 시간의 관계를 이용할 수 없나요?

다음으로 이를 수행하는 방법을 요약합니다. 우선, 우리가 이 메소드를 사용하는 코드를 볼 수 있습니다

왜 애니메이션을 구현하는데 속도와 시간의 관계를 이용할 수 없나요?

애니메이션 프로세스의 개념을 소개하고 애니메이션 프로세스를 통해 애니메이션의 완성을 제어합니다.

왜 애니메이션을 구현하는데 속도와 시간의 관계를 이용할 수 없나요?

퍼센트 애니메이션 처리는 목표 타임라인을 기반으로 하기 때문에 지정된 시간 내에 애니메이션이 완료될 수 있도록 보장할 수 있으며, 속도 조절 애니메이션 실행 시 애니메이션 실행 시간이 길어지는 문제가 더 이상 발생하지 않습니다. 사용된. . (물론 애니메이션 실행 중에 시간이 많이 걸리는 작업을 추가하면 지정된 시간 내에 애니메이션이 완료되지 않습니다.)

그런 다음 애니메이션의 오프셋을 처리할 때 현재 실행 시간의 오프셋을 얻으려면 전체 오프셋 * 애니메이션 프로세스만 추가하면 됩니다.

마지막으로 애니메이션 진행률이 1이 되면 애니메이션이 종료되고 요소는 애니메이션에서 지정한 전체 오프셋으로 설정됩니다.

일반적으로 이 방법은 변위와 시간의 관계를 오프셋과 애니메이션 프로세스의 관계로 변환하는 것입니다. 애니메이션 프로세스를 통해 애니메이션 지속 시간과 애니메이션 오프셋 완료를 동시에 제어할 수 있습니다.

더 중요한 것은 오프셋과 애니메이션 프로세스 간의 관계를 객관적인 모션 법칙을 통해 추론할 수 있다는 것입니다.

예를 들어 위의 예에서는 등속 애니메이션이므로 규칙은 다음과 같습니다.

애니메이션 프로세스 p = t / T; (t = Date.now() – start_time ; T = 기간)

오프셋 Sp = S * p; (S는 총 오프셋, Sp는 현재 오프셋)

등가속도 애니메이션, 등가속도 애니메이션, 원형 애니메이션 등 다른 애니메이션인 경우에도 비슷한 규칙을 얻을 수 있습니다. 또한 모든 애니메이션 효과에 대한 애니메이션 처리 계산 방법은 오프셋과 애니메이션 처리 간의 관계만 다릅니다.

균일 가속도: Sp=S * P2

균일 감속: Sp=S * P * (2−P)

원주 x축: Sp=S * cos(Ω * P)

원주 y축: Sp=S * sin(Ω * P)

(위 네 가지 관계의 도출을 주의 깊게 공부하지 않았습니다. 이전의 수학적 지식을 많이 잊어버렸습니다. 관심이 있으시면 "애니메이션에 대해 알아야 할 사항"을 공부하시면 됩니다.)

동일한 애니메이션에 대해 위의 다양한 규칙을 적용하면 다양한 속도에서 애니메이션 변경 효과를 볼 수 있으며 최종적으로 애니메이션을 사용하여 현실 세계에서 객체의 움직임을 시뮬레이션하려는 목표를 달성할 수 있습니다.

이러한 오프셋과 애니메이션 프로세스 사이의 관계를 연구한 결과, 총 오프셋 S는 이 관계의 매개변수에 불과하다는 사실을 발견했습니다. S를 제거하면 S와 아무런 관련이 없는 값을 얻게 됩니다. , 방정식 애니메이션 프로세스에만 관련:

균일한 속도: ep = p

등가속도: ep= P2

균등 감속도: ep= P * (2−P)

원주 x축: ep= cos(Ω * P)

원주 y축: ep= sin(Ω * P)

위의 모든 규칙을 함수로 표현하는 방법은 다음과 같습니다. ep = E(P), P∈[0,1], P는 애니메이션 프로세스를 나타냅니다. ep 편향을 나타냅니다. 완료된 움직임의 비율입니다. 추가해야 할 점은 이 관계가 조건을 충족해야 한다는 것입니다. P=0일 때 ep는 0이어야 하고, P=1일 때 ep는 1이어야 합니다. P=0과 P=1, ep=0과 ep=1은 각각 애니메이션의 시작 상태와 끝 상태를 나타내기 때문에 이해하기 쉽습니다. .

즉, 이전 단락과 같이 이전 단락의 조건을 모두 충족하는 함수를 찾는 한 이 함수는 애니메이션 속도를 제어하는 ​​방법으로 사용할 수 있습니다. 이 기능

는 소위 애니메이션 연산자의 용이성입니다. 다음 함수 이미지를 애니메이션 연산자로 사용할 수 있습니다:

왜 애니메이션을 구현하는데 속도와 시간의 관계를 이용할 수 없나요?

有了这个规律,就赋予了动画效果控制无限的可能性,因为能满足前面那些条件的函数是无穷的。而这些看起来无穷尽的函数,我们能够轻松地通过贝塞尔曲线工具绘制出来,并且在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>
로그인 후 복사

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

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

원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿