javascript
《JavaScript高效图形编程(修订版)》——第2章 DHTML基础 2.1创建DHTML sprite
本節書摘來自異步社區《JavaScript高效圖形編程(修訂版)》一書中的第2章,第2.1節,作者:【美】Raffaele Cecco著,更多章節內容可以訪問云棲社區“異步社區”公眾號查看
第2章 DHTML基礎
在HTML5 Canvas、SVG和Flash等現代瀏覽器技術的背景下,DHTML今天看起來有點過時。不過,就像龜兔賽跑中的龜,當更令人激動的方法不能保證可用的情況下,DHTML總是那個更可靠的方案。
實際上,很多時候你只需要DHTML就夠了;使用其他方法往往是因為開發者“想要”而不是“需要”。休閑游戲、圖像縮放和許多其他特效都不需要借助其他“強力工具”就能完美實現。jQuery這樣的庫還能使其操作起來更簡單。熟練的DOM操作技術加上一點點想法就能保證DHTML圖形的快速和流暢。
在本章,我們將用vanilla JavaScript和DHTML開發一個快速sprite系統。出于兼容性考慮,我們會避免使用語言的最新特性,而集中于核心JavaScript的有效使用。
2.1 創建DHTML sprite
在計算機圖形學中,sprite是可以用軟件控制移動的二維比特圖對象。在三維多邊形圖形學之前,視頻游戲幾乎無一例外的使用sprite來生成可移動的角色。如今,移動設備上的休閑游戲和其他的用戶界面效果等,引起了sprite圖形的復興。你可以用DHTML來模擬sprite功能。下面章節中,我們將創建一個用于不同應用的DHTMLSprite對象。盡管創建sprite效果有更新、更快的方法,如HTML5 Canvas元素,但普通的DHTML可以提供不錯的瀏覽器兼容性,在許多情況下作為Adobe Flash的替代方案是完全可行的。
提示:
本章中的sprite和CSS sprite是有區別的。CSS sprite是一個流行的Web設計技術,指的是僅通過改變HTML元素的CSS背景位置,使得元素顯示一個大背景圖像的一小部分,一般用于實現動畫效果。在計算機圖形學術語中,這叫做動態紋理坐標。本章提到的sprite,還是取其原意:一個移動的圖形對象。同時我們也將用到CSS sprite技術來改變其圖像。
DHTMLSprite應該足夠靈活以用在不同應用中,并提供下列功能:
- 用一個簡單的函數調用和圖像索引(index)來改變其圖像(動畫)。
- 在內部管理自身的DOM元素。
- 不改變DOM的情況下隱藏和顯示自己。
- 移除其DOM元素并進行必要的清理。
2.1.1 圖像動畫
沒有動畫的sprite很沒勁,因此我們需要一個簡潔的方法來改變sprite中所用的圖像。盡管img元素似乎是一個很明顯的選擇,但它需要對每個動畫幀載入不同的圖像文件。有一個更好的辦法可以使用少量的圖像文件,而處理多個sprite圖像。
CSS的background-position(背景位置)屬性使得HTML元素(如一個div)可以顯示圖像的一小部分。因此一個大圖像可以作為許多小sprite圖像的容器。要使用這些sprite圖像,我們必須定義background-position屬性在div內的水平和垂直位移,以及寬和高。但這種動畫方式并不直接,而需要技巧。最好是通過簡單的索引就能引用到sprite圖像。比如在圖2-1中,組成一個齒輪動畫的5幅圖像可以用索引0、1、2、3和4表示。而第一個正方形用索引5表示,依此類推。
我們需要將索引轉化為容器圖像內的像素位移。一種方法是手動創建一個表格來記錄sprite圖像索引和對應的像素位移。盡管這個方法很有效,但手動輸入和更新這些位移將很枯燥。更好的方法是通過計算得到這些位移。
將索引轉換為水平和垂直像素位移只需要很簡單的算術。在圖2-1中,容器圖像是256像素寬,每個sprite圖像(底層除外)是64像素的正方形。像素位移可以用JavaScript這樣計算:
注意計算出的值是負數。想象div元素是在對準第一個齒輪圖像(索引為0)、寬與高各64像素的正方形。為了顯示索引為1的下一張圖像,容器圖像必須向左移64像素(負水平位移)。如果要顯示索引為4的最后一個齒輪圖像,容器圖像必須向上移64像素(負垂直位移)。
如何處理不同大小的sprite呢?在圖2-1中,在容器圖像底部有一些更小的32像素寬、高的sprite圖像。
決定像素位移的計算和之前一樣,不同的是sprite大小改為32像素:
考慮到現在的sprite大小是32像素,圖2-1中第一個32像素的sprite圖像(底行第一個小黑圈)的索引為32。只要sprite圖像的邊緣坐標是它們大小的倍數,就可以使用索引計算的方式。
提示:
圖2-1中的容器圖像是一個32位PNG文件,支持百萬顏色和一個用于透明度的alpha通道。不過,32位PNG不適用于IE6,因為透明區域會變成不透明的灰色。一個解決方案是將圖像存為8位的調色板PNG。這可以在IE6中正確顯示,不過半透明區域會完全消失并顯示粗糙的邊緣。
2.1.2 封裝和畫圖抽象
將所有DOM操作細節,封裝在DHTMLSprite中,隱藏在使用它的應用之外,會使代碼更簡單更易維護;應用可以集中于應用邏輯而不是畫圖細節。由于應用邏輯和畫圖細節的分離,將應用轉為另一個畫圖方法如HTML5 Canvas元素或SVG變得更簡單,甚至可以使應用程序根據瀏覽器能力選擇合適的畫圖方法。
2.1.3 最小化DOM插入和刪除
重復的增刪和銷毀DOM元素對性能會有不利的影響。為了降低性能影響,可以初始化一個隱藏的sprite列表。當需要sprite時,你可以將其從列表中取出并使其可見,而不是真的在DOM中插入新的東西。當sprite不再需要時,你可以將其隱藏并放回列表中。在DHTMLSprite中提供一個show和hide方法將使應用實現這項技術。
如果要永久地移除一個DHTMLSprite,應移去其DOM元素并進行相關的其他清理工作。
2.1.4 sprite代碼
與其將若干單獨的參數傳給sprite,不如將所有設置參數放入叫做params的對象傳入。除了避免參數次序的麻煩之外,還使從DHTMLSprite繼承的其他對象,可以將它們自己的設置參數加入params中。任何使用params的對象都可以忽略跟它不相關的參數。表2-1顯示了params對象中的參數。
下面,我們將params屬性復制為局部變量。通過局部變量訪問參數比通過params對象的屬性要快。如此定義的局部變量是私有的,只能從DHTMLSprite內的方法訪問。
接下來,我們在params.$drawTaget指定的DOM元素后加上一個sprite div元素。$element保存了一個對sprite div的引用。變量和屬性名前的$符號用做提醒它們指向jQuery對象。elemStyle直接引用了sprite div的style屬性,用于快速更新其CSS屬性。
現在我們要給sprite div元素設置初始CSS屬性。因為我們只進行一次初始化,因此可以使用方便的jQuery css()函數,盡管這也許不是改變屬性最快的方式。
下面我們要在that中創建并保存一個DHTMLSprite對象。它包含了所有的sprite方法,注意that的方法可以訪問前面定義的局部變量。這個that對象創建了一個閉包,它能永久訪問前面DHTMLSprite函數里定義的變量。
draw方法更新sprite div元素的位置:
changeImage()方法改變顯示的sprite圖像。將索引轉為像素位移的方法和前面描述的一樣,但有些小的優化:
- 局部變量mathFloor()指向Math.floor()函數,我們通過前者來調用后者。
- index變量只乘一次。
然后,我們定義隱藏、顯示和移除sprite div元素的方法:
2.1.5 一個簡單的sprite應用程序
下面是一個基本的HTML頁面,它初始化并顯示了兩個sprite。
為了創建sprite,我們需要一個包含初始化參數的對象:
下面創建兩個sprite。因為兩個sprite大小相等并使用同一個DOM畫圖區域,所以不需要改變任何參數。第一個sprite使用默認索引值0,而第二個sprite的圖像索引值為5。
最后畫出這兩個sprite。圖2-2顯示了輸出結果。
這個應用中沒有移動也沒有動畫,讓我們在下一個例子中“動”起來。
2.1.6 一個更動態的sprite應用程序
下面的應用展示了sprite的存在價值:動畫和移動。之前我們畫了兩個sprite,而沒有控制它們移動。這個例子中我們定義一個新對象:bouncySprite,一個會反彈的DHTMLSprite。實現方法之一是在bouncySprite中創建一個DHTMLSprite,并將其作為單獨的實例控制。更簡潔的方法是讓bouncySprite繼承所有DHTMLSprite的能力,并添加自己額外的能力。在JavaScript中這種繼承和增強很簡單:
為了提高速度,我們用局部變量保存設置參數。這里的params對象也包含DHTMLSprite的參數,但這些和bouncySprite無關。表2-2顯示了傳入的參數。
animIndex保存了當前動畫圖像索引:
我們在that中創建和引用一個DHTMLSprite。params對象包含了其設置參數。
接著給that引用的DHTMLSprite實例加一個moveAndDraw方法,實際上就是創建一個bouncySprite實例:
通過增加xDir和yDir變量來移動sprite的x和y位置:
下面的代碼根據xDir方向對animIndex變量進行增或減,接著用取余操作(%)將其維持在?4到+4之間。如果animIndex是負的,糾正到對應的正索引。
接著檢查bouncySprite是否超過了maxX和maxY定義的范圍。如果超過,對移動的方向取負,使bouncySprite彈回。
更新bouncySprite動畫索引,并將其畫到新位置:
返回在that中引用的bouncySprite實例,供應用程序使用:
定義了bouncySprite對象后,我們可以初始一些對象,并在setInterval()或settTimeout()控制下調用它們的 moveAndDraw()方法。更好的方法是創建一個對象可以初始化和處理任意數量的bouncySprite。這個對象可以叫做bouncyBoss。bouncyBoss可以傳入兩個參數,如表2-3所示。
創建指定數目的bouncySprite,并放入bouncys數組中。每個bouncySprite給一個隨機起始位置和移動方向(xDir和yDir),并根據$drawTarget的寬和高計算最大范圍。
現在我們定義moveAll方法,它調用了bouncys數組中每個bouncySprite的moveAndDraw方法。每次移動,它創建一個setTimeOut來調用自己,實現連續的循環。
下面是使用新bouncyBoss對象的頁面布局:
一個bouncyBoss創建了50個bouncySprite對象,并連續調用它們的moveAndDraw方法。圖2-3顯示了輸出結果。
總結
以上是生活随笔為你收集整理的《JavaScript高效图形编程(修订版)》——第2章 DHTML基础 2.1创建DHTML sprite的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《Adobe Photoshop大师班:
- 下一篇: 《CCNA无线640-722认证考试指南