【前端應該知道的那些事兒】運動學基礎


【寫在前面的話:】
前不久剛看到過一句話:說好的技術文章應該讓讀者感覺增加信心,而不是失去信心。
有感於這句話是因為以前覺得發一些貌似高深的,看起來nb的東西才算一篇好博文,可是多少有點炫技的成分。可是后來越發覺想把一個看起來簡單的問題說通透也着實不易。我希望今后的文章多少能帶給更多的讀者一些幫助吧。 這是我的目標之一。 

web前端,確實算編碼里面的挺特殊的一個職位,不僅僅要理性的編碼,還要感性的接觸UI,通常我都把這種工作叫做需要情商的碼字工作者。

要說前端有多難,我想會被很多做算法或者底層的同學所不齒。確實,前台的工作並不算難,尤其是web端的前台,有困難的部分,那也是少數。所以在互聯網發展初期,都沒有前端這個職位,就算后來有了前端這個職位,也曾被當作是門檻最低的IT類職位之一。很多同學學習前端相關的知識,初衷很簡單,因為好學,包括當年的自己也是一樣 : )

當然,如今隨着交互邏輯的不斷復雜,用戶體驗的不斷提升,外帶很多后端的邏輯也都紛紛轉到前端來實現。前端的工作者們開始有了一些價值。當然,你要擔當的更多,必然需要會的更多。所以如今對於一個優秀的前台編碼工作者來說,要求高了很多。

但是同樣,還是不能算難。因為哪怕前端們開始接觸一些算法,一些數學物理的東西,但常用的,通常也僅限於初衷,高中的程度。所以神馬高等數學,高等物理之類的。咱暫時還用不上,大家完全不用懼。

那么,比如:

【關於緩動】
我相信在DHTML時代,也就是所謂的動態 html 的時候,那時候javascript 腳本除了用來做一些表單驗證和提交之外,開始干起讓頁面動起來的事情。最常見的莫過於什么幻燈片,輪播banner之類的。甚至在當時能夠手寫出一款好的,兼容的輪播插件成了一件非常niu的事兒。那么回想一下,我們最開始學習,嘗試自己寫一個輪播插件的時候,遇到的頭疼的事兒,我想緩動應該算一個了吧。
好吧,咱們就先來說說它。 

緩動難嗎,不難,我們先說一個最簡單的。所謂“緩動”,無非就是運動的越來越緩慢唄。那么怎么讓一個物體運動的越來越緩慢呢。

我們用的計時器,不管你是用setInterval也好,setTimeout也好,或者 requestAnimationFrame也好,思路都一樣。反正把它想象成是單位時間重復調用某個函數就行。那就好,既然單位時間是一樣,那么我們讓單位時間內 物體運行的距離 越來越小不就成了“緩動”了嗎。

ok,咱們可以試試看:

假如我們有一段固定的路程100米,然后讓物體 每個單位時間里面運動的距離都是 它距離目的地剩余距離的1/10, 什么意思呢。 即物體最開始距離目的地100米,那么它第一個單位時間里朝目的地運動 100*1/10 ,即10米, 於是,第二個單位時間里,它距離目的地 就只有90米了,那么第二次運動 90*1/10 ,即9米,... 不斷疊加下去,由於物體總是距離目的地越來越近,那么 它單位時間里運動的距離必然越來越小。 這不就達到了 我們緩動的目的的了么。

(function () {
	var moveDis = 0,
		conEl = document.getElementById('container'),
		maxDis = (conEl.offsetWidth-22) || (800-20), // 總距離
		moveEl = document.getElementById('move');
		
	function step () { 
		var nowLeft = parseInt(moveEl.style['left']),
			leftDis = maxDis - nowLeft, // 獲取距離目的地的距離
			stepDis = Math.ceil(leftDis*.015); // 每次移動 剩余距離的 固定百分比。
			
		nowLeft += stepDis; // 不斷疊加
		moveEl.style['left'] = nowLeft + 'px';

		requestAnimFrame(step); // repeat
	}
	
	step();

})();

Tween Demo 1

 當然,這是最簡單的模式,咱們接着往下看。

那么,那些看起來高深的緩動公式是怎么來的呢??

其實也很簡單,想想我們初中,高中學的數學吧, 二次函數,三角函數之類的。

先看二次函數,也就是我們的拋物線:

為什么我要說先看二次函數或者三角函數呢。他們的軌跡跟 緩動有什么關系?我們接着往下看:

拿上面的那個最簡單的demo舉例,我們把 方塊的運行距離s 和時間 t的運動關系 畫出來,看會是什么樣子的。

看這個demo:
Tween Demo 2

這里面的緩動算法跟上面那個最簡單的模式一模一樣。我們把它的 t-s 路線圖畫出來,可以看出一點端倪了吧。沒看出來的同學,把它旋轉一下,想象成 x軸 時間, y軸位移。那么是不是就跟 我上面畫那個二次函數 的左半部分 的形狀很像。

所以,到此為止,相信不難理解,為什么緩動的公式通常和二次函數或者三角函數有關,直觀一點的話說,就是在某一個區間內 位移的變化率 是隨着時間遞減的。 那么這種 軌跡都可以用作 緩動公式。

那么,

我們怎么用二次函數來做緩動呢?很簡單,大家隨着我的思路來。我們要設計一個緩動的接口api,假如是類似下面這樣,我們先想一個最簡單的方式。

【已知】:一物體要從 0 運行到 400, 運行時間為1秒(1000ms)。
那么我們怎么為它來設計一個二次函數的緩動呢。我們先畫一個示意圖:

那么求的 方程 的系數 a = 0.00005, b = -0.1;

那么方程就出來了 s = 0.00005*t^2 - 0.1*t  (0 < t <=1000);

剩下的就好辦了,把每個時間點的位置渲染出來就好了。
例如,我們做個例子,設計一個api:

// from 表示起始點
// to 表示到達位置
// t 表示運行總時間
tween(from, to, t)

按照上面說的思路,其實就是已知運行距離(from-to)和運行時間t ,求一個二次函數公式而已。  

	// 二次函數 s = a*t^2 + b*t;
	// 頂點: (to-from) = a*t^2 + b*t
	// 右側x軸交點: 0 = a*(2t)^2 + b*2t
	// 得出 a = -(to-from)/t^2; b = 2(to-from)/t;

     var left = a*st*st + b*st;
     o.style['left'] = from + left + 'px';

看demo:
  Tween Demo 3  (demo里面由於用的普通的dom生成的點圖,會占內存,請不要測試過多次 ^^).

原理其實就是那么簡單,其實大家可以自己試一下,熟悉了之后完全可以封裝出自己的好用的,易用的緩動方法。

用這類的二次函數,還有一個很常見的場景,就是“重力系統”。

我們知道,如果忽略所謂的空氣阻力和一些外界干擾因素,重力系統其實就完全可以簡化成 二次函數(拋物線)問題。

比如我們做個小游戲,系統有固定的向下的重力 g ,那么由用戶操作的主角 在像上跳的過程中,就完全可以按 上面說的方式來考慮。

基本思路上面都說了,這次我們換個思路。都說數學和物理是相通的,那么這次已知 在一個重力系統中,跳起初速度和重力大小。那么假設一個物體跳起該怎么運動呢?

S = v0*t + a*t^2
v0 = a*t

這兩個應該是初中的物理公式吧。已知初速度v0 和加速度 a ,求位移還不簡單。
其他的我就不多說了,看一個簡單的demo吧:
彈跳Demo  

 

看完了【二次函數】,咱們再看看【三角函數】,其實在我們常用的特效中,三角函數能做的事情比二次函數多很多。但是今天就只講跟【緩動】相關的。

 前面說了,凡是大家看到類似這種“山坡”形狀的圖,基本都可以做成類似的緩動。那么我們取sin函數的前 PI/2 部分,可以看出他也完全滿足所謂的 緩動的圖形條件。

而且,基於sin函數做的緩動公式 相對於二次函數而言,思路更簡單。因為更容易得出 位移相對時間的公式S-T:

/**
 我們假設 每一幀 間隔時間為 dt, 那么在這個dt時間內 運動的距離為ds
那么,假設一個物體 從 from 移動到 to 所花的時間為t, 則容易得出 在這個時間區間內用sin公式得到 每個dt的位移公式ds
*/
function tween (from, to, t) {
    // sin函數; ds = (to-from)*Math.sin(Math.PI*dt/(2*t));
}

剩下的工作,就是把計算出來的當前位置渲染到頁面即可。我們這里還是以類似的例子為例:
  sin 緩動 demo  

 

【寫在后面的話】
不知不覺也寫了這么多了,所謂“會者不難”,本文說到底其實涉及的技術技巧其實並不多,我花這么大篇幅來說也是希望能給對運動學還不甚了解的同學一點幫助吧。
我希望我能把簡單的東西說明白,至於有沒有達到這個目的我也不得而知。

其實在前端的工作里,還有一些常用的數學和物理知識,但是都不難。說起來都很簡單。比如前一陣的mac QQ瀏覽器的logo 周圍的閃動旋轉的星星。就是用了簡單的橢圓公式。
http://hongru.github.com/test/qqbrowser/index.html 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM