摘要:動(dòng)畫原文通常,框架會(huì)為你處理動(dòng)畫。整個(gè)的動(dòng)畫過(guò)程被分成了很小的步驟,每一個(gè)步驟被定時(shí)器調(diào)用。因?yàn)槎〞r(shí)器的周期非常短,所以動(dòng)畫看起來(lái)是連續(xù)的。已經(jīng)過(guò)去的動(dòng)畫時(shí)間作為分子,計(jì)算每一幀通過(guò)公式。線性的使動(dòng)畫以固定的速度進(jìn)行。
動(dòng)畫
原文:http://javascript.info/tutori...
通常,框架會(huì)為你處理動(dòng)畫。但是,你可能想知道僅僅用javascript怎么來(lái)實(shí)現(xiàn)動(dòng)畫,和可能出現(xiàn)的一些問(wèn)題。理解這項(xiàng)技術(shù)對(duì)于創(chuàng)建復(fù)雜的動(dòng)畫是很有幫助的,即使在框架的幫助下。
動(dòng)畫基礎(chǔ)javascript的動(dòng)畫是通過(guò)周期性的改變DOM元素的style 或者 canvas 的對(duì)象。
整個(gè)的動(dòng)畫過(guò)程被分成了很小的步驟(step),每一個(gè)步驟被定時(shí)器調(diào)用。因?yàn)槎〞r(shí)器的周期非常短,所以動(dòng)畫看起來(lái)是連續(xù)的。
偽代碼:
var id = setInterval(function(){ /*當(dāng)前顯示幀*/ if(/*完成*/) clearInterval(id) }, 10)
上面代碼每一幀的間隔是 10ms ,意味著每秒鐘有100幀。
在大多數(shù)的javascript框架中 10-15ms的delay是默認(rèn)的。越短的延時(shí)讓動(dòng)畫看起來(lái)更加流暢,但是只有在瀏覽器足夠快的時(shí)候,每一步的動(dòng)畫才會(huì)準(zhǔn)時(shí)運(yùn)行。
如果動(dòng)畫需要許多計(jì)算,CPU可能會(huì)100%的負(fù)載,動(dòng)畫就會(huì)變得遲緩。這種情況下,delay就應(yīng)該被增加。例如,delay 40ms 就是每秒25幀,接近24幀的電影標(biāo)準(zhǔn)。
setInterval 而不是用 setTimout(其實(shí)在現(xiàn)代瀏覽器中大多使用requestAnimationFrame)例子我們使用setInterval,而不是遞歸的使用setTimeout,是因?yàn)槲覀兿胍粠粋€(gè)delay,而不是所有幀之間有一個(gè)固定的delay.查閱Understanding timers: setTimeout and setInterval來(lái)了解setInterval和遞歸的setTimeout之間到底有什么不同。(譯者:經(jīng)測(cè)試最新的chrome > 56中,setInterval的行為跟本文中描述的不同。當(dāng)函數(shù)執(zhí)行時(shí)間超過(guò)了delay時(shí)間,下一個(gè)函數(shù)不會(huì)馬上運(yùn)行,仍然會(huì)等一個(gè)delay的間隔,再執(zhí)行。但本文仍有參考價(jià)值)
例如,一個(gè)元素移動(dòng)通過(guò)改變element.stye.left從0到100px。每10ms改變1px。
在新的窗口打開(kāi)
動(dòng)畫重構(gòu)為了讓動(dòng)畫更加通用,我們介紹下面的一些參數(shù):
delay
??每一幀之間的間隔(ms).例如,10ms
duration
??整個(gè)動(dòng)畫完成需要的時(shí)間(ms)。例如:1000ms
當(dāng)動(dòng)畫開(kāi)始的時(shí)候,我們也可以用:
start ??動(dòng)畫開(kāi)始的時(shí)間,start = new Date
動(dòng)畫過(guò)程的核心,每一幀我們需要計(jì)算:
timePassed
??從動(dòng)畫開(kāi)始所經(jīng)過(guò)的時(shí)間(ms)。
??從0到動(dòng)畫(duration)結(jié)束.但是偶爾可能會(huì)超過(guò)結(jié)束時(shí)間,因?yàn)闉g覽器的計(jì)時(shí)器并不準(zhǔn)確。
progress
已經(jīng)過(guò)去的動(dòng)畫時(shí)間作為分子,計(jì)算每一幀通過(guò)公式timePassed/duration。值得范圍通常是0到1。
例如,progress的值為0.5就是說(shuō)動(dòng)畫時(shí)間(duration)已經(jīng)過(guò)去了一半。
delta(progress)
一個(gè)返回當(dāng)前動(dòng)畫進(jìn)度的函數(shù)。
例如,我們讓高度屬性從0%變化到100%。
我們可以讓動(dòng)畫均勻的顯示,這樣動(dòng)畫進(jìn)度看起來(lái)就是線性的。
Mapping:
->progress = 0 -> height = 0%
->progress = 0.2 -> height = 20%
->progress = 0.5->height = 50%
->progress = 0.8 -> height = 80%
->progress = 1 -> height = 100%
但是我們可能想讓動(dòng)畫緩慢的開(kāi)始然后再加速。這樣的話經(jīng)過(guò)一半的動(dòng)畫時(shí)間高度可能只有25%
,然后逐漸加速到100%。
Mapping:
->progress = 0 -> height = 0%
->progress = 0.2 -> height = 4%
->progress = 0.5->height = 25%
->progress = 0.8 -> height = 64%
->progress = 1 -> height = 100%
delta(progress) 是一個(gè)映射動(dòng)畫進(jìn)度增量的函數(shù),
動(dòng)畫進(jìn)度通常是0到1之間的一個(gè)數(shù)字。
這篇文章會(huì)用一些例子進(jìn)一步討論幾種增量函數(shù)
step(delta)
這個(gè)函數(shù)是實(shí)際上用來(lái)做這件事的函數(shù)。
它計(jì)算出增量的結(jié)果并且應(yīng)用它。
對(duì)于這個(gè)高度的例子,他們可能是:
function state(delta) { elem.style.height = 100*delta + "%" }
到現(xiàn)在為止幾個(gè)重要的參數(shù)是:
->?delay是setInterval的第二個(gè)參數(shù)。
->?duration是動(dòng)畫完成需要的時(shí)間。
->?progress是動(dòng)畫已經(jīng)經(jīng)過(guò)的時(shí)間,除以duration使它的值在0到1之間。
->?delta通過(guò)當(dāng)前的時(shí)間,計(jì)算當(dāng)前的動(dòng)畫進(jìn)度。
->?step做了視覺(jué)上(?)的工作。它獲得當(dāng)前的動(dòng)畫進(jìn)度,并且把它應(yīng)用在元素上。
讓我們把上面討論的簡(jiǎn)單的寫成一個(gè)可擴(kuò)展的動(dòng)畫核心。
下面的動(dòng)畫函數(shù)執(zhí)行時(shí)間管理并且把工作分配給delta和step:
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.delay || 10) }
參數(shù)對(duì)象應(yīng)該包含以下的一些動(dòng)畫屬性:
->?delay
->?duration
->?function delta
->?function step
這個(gè)算法完全遵循上面的描述
讓我們基于這個(gè)來(lái)創(chuàng)建一個(gè)移動(dòng)的動(dòng)畫
function move(element, delta, duration){ var to = 500; animate({ delay: 10, duration: duration || 1000, delta: delta, step: function(delta){ element.style.left = to * delta + "px" } }) }
它把工作指派給animate,給animate傳入了delay,用戶提供的duration, delta, 和 step。
delta = function(p) { return p}
??意味著動(dòng)畫進(jìn)程一直是均勻的
step
??用一個(gè)簡(jiǎn)單的公式映射0..1,delta返回一個(gè)進(jìn)度值 0..to。把這些結(jié)果應(yīng)用到element.style.left。
用法:
數(shù)學(xué),進(jìn)度增量函數(shù)
動(dòng)畫就是是根據(jù)給定的規(guī)則,一直改變屬性。在javascript動(dòng)畫中,這個(gè)規(guī)則就是delta函數(shù)來(lái)實(shí)現(xiàn)的。
不同的delta使動(dòng)畫的速度,加速度和其他的參數(shù)表現(xiàn)出各種各樣的形式。
數(shù)學(xué)公式通常被用在這里。但是它們對(duì)于只做web編程和忘記學(xué)校里的數(shù)學(xué)的人來(lái)說(shuō),可能很陌生。在這個(gè)章節(jié),我們將瀏覽很多的受歡迎的公式并看一下它們是如何工作的。
動(dòng)畫運(yùn)動(dòng)的例子,提供不同的delta.
線性 delta
function linear(progress){ return progress; }
水平方向指的是時(shí)間進(jìn)度,垂直方向指的是動(dòng)畫進(jìn)程。
我們已經(jīng)能看見(jiàn)了。線性的delta使動(dòng)畫以固定的速度進(jìn)行。
Power of n
也是一個(gè)簡(jiǎn)單的例子。delta是progress的n次方。例如2次,3次方等。
例如2次方
function quad(progress) { return Math.pow(progress, 2) }
增加加速度的影響。例如,下面這個(gè)圖片是5次方。
Circ: 圓的一部分
function circ(progress) { return 1 - Math.sin(Math.acos(progress)) }
Back: the bow function
這個(gè)函數(shù)向弓一樣工作:首先我們"拉開(kāi)工,然后發(fā)射出去"。
不像先前的函數(shù),它會(huì)依賴于一個(gè)附加的參數(shù)x,這就是“彈性系數(shù)”。
它定義了“拉弓”的距離。
代碼是:
function back(progress, x) { return Math.pow(progress, 2) * ((x + 1) * progress - x) }
圖像x=1.5
bounce(彈跳)
想象一下我們釋放一個(gè)球,它掉在地上,然后彈跳幾次,最后停止。
bounce事實(shí)上做了相反的事情。屬性將會(huì)一直改變知道它達(dá)到目標(biāo)點(diǎn)。
這個(gè)函數(shù)比之前要復(fù)雜一些,也沒(méi)有簡(jiǎn)單的數(shù)學(xué)公式。
function bounce(progress) { for(var 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) } } }
*這段代碼曲子 MooTools.FX.Transitions.據(jù)我所知,仍然有其他實(shí)現(xiàn)bounce的算法。
Elastic 彈性
這個(gè)函數(shù)也依賴于額外的參數(shù)x,x定義了初始范圍。
function elastic(progress, x){ return Math.pow(2, 10 * (progress - 1)) * Math.cos(20 * Math.PI * x/3 *progress) }
圖像 x=1.5
在這個(gè)例子中,為了讓動(dòng)畫更加平滑,時(shí)間是2s.
反向函數(shù)(Reverse functions)
一個(gè)javascript框架經(jīng)常會(huì)提供的一種delta函數(shù)。
它們的直接使用被稱作 easeIn.
偶爾的時(shí)候,需要以時(shí)間倒退的方式來(lái)展示動(dòng)畫。這就叫做easeout 被"time-reversing"delta來(lái)實(shí)現(xiàn)。
未完待續(xù)
第一次翻譯點(diǎn)東西,質(zhì)量不好,主要是做記錄用。里面有很多比較"術(shù)語(yǔ)"的,不好翻,最好看原文。后面我也會(huì)繼續(xù)修改。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/81899.html
摘要:前端日?qǐng)?bào)精選如何優(yōu)雅的編寫代碼深入理解內(nèi)部機(jī)制專題之函數(shù)組合年月個(gè)有趣的和庫(kù)最經(jīng)典的前端面試題之一,你能答出什么幺蛾子中文翻譯深入理解響應(yīng)式原理掘金譯與和交互掘金箭頭函數(shù)使用禁忌技術(shù)棧耕耘助力美團(tuán)點(diǎn)評(píng)前端進(jìn)階之路前端模塊 2017-09-01 前端日?qǐng)?bào) 精選 如何優(yōu)雅的編寫 JavaScript 代碼深入理解 Node.js Stream 內(nèi)部機(jī)制JavaScript專題之函數(shù)組合20...
摘要:巧前端基礎(chǔ)進(jìn)階全方位解讀前端掘金我們?cè)趯W(xué)習(xí)的過(guò)程中,由于對(duì)一些概念理解得不是很清楚,但是又想要通過(guò)一些方式把它記下來(lái),于是就很容易草率的給這些概念定下一些方便自己記憶的有偏差的結(jié)論。 計(jì)算機(jī)程序的思維邏輯 (83) - 并發(fā)總結(jié) - 掘金從65節(jié)到82節(jié),我們用了18篇文章討論并發(fā),本節(jié)進(jìn)行簡(jiǎn)要總結(jié)。 多線程開(kāi)發(fā)有兩個(gè)核心問(wèn)題,一個(gè)是競(jìng)爭(zhēng),另一個(gè)是協(xié)作。競(jìng)爭(zhēng)會(huì)出現(xiàn)線程安全問(wèn)題,所以,本...
摘要:巧前端基礎(chǔ)進(jìn)階全方位解讀前端掘金我們?cè)趯W(xué)習(xí)的過(guò)程中,由于對(duì)一些概念理解得不是很清楚,但是又想要通過(guò)一些方式把它記下來(lái),于是就很容易草率的給這些概念定下一些方便自己記憶的有偏差的結(jié)論。 計(jì)算機(jī)程序的思維邏輯 (83) - 并發(fā)總結(jié) - 掘金從65節(jié)到82節(jié),我們用了18篇文章討論并發(fā),本節(jié)進(jìn)行簡(jiǎn)要總結(jié)。 多線程開(kāi)發(fā)有兩個(gè)核心問(wèn)題,一個(gè)是競(jìng)爭(zhēng),另一個(gè)是協(xié)作。競(jìng)爭(zhēng)會(huì)出現(xiàn)線程安全問(wèn)題,所以,本...
摘要:前端日?qǐng)?bào)精選譯發(fā)布了王躍關(guān)于微信小程序的技術(shù),也許你想錯(cuò)了細(xì)說(shuō)中的瀏覽器頁(yè)面渲染工作原理淺析騰訊前端團(tuán)隊(duì)社區(qū)中文第期安息吧,長(zhǎng)存譯借助函數(shù)完成可組合的數(shù)據(jù)類型軟件編寫第十部分掘金對(duì)象與原型掘金技術(shù)周刊期知乎專欄是真正的語(yǔ)言 2017-10-16 前端日?qǐng)?bào) 精選 [譯]Vue 2.5 發(fā)布了王躍:關(guān)于微信小程序的技術(shù),也許你想錯(cuò)了細(xì)說(shuō)Web API中的Blobchrome瀏覽器頁(yè)面渲染工...
閱讀 1374·2021-10-09 09:44
閱讀 1451·2021-09-28 09:36
閱讀 16028·2021-09-22 15:55
閱讀 1254·2021-09-22 15:45
閱讀 2210·2021-09-02 09:48
閱讀 2794·2019-08-29 17:19
閱讀 2308·2019-08-29 10:54
閱讀 922·2019-08-23 18:40