先來看個簡單的demo-> 像素粒子化
demo是基於3d旋轉算法+像素粒子化實現的,尚有一些bug和性能問題,我們不做深究。本篇主要談談如何將文字和圖片的像素粒子化。針對這個demo,也就是如何實現如下兩個圖片的轉換。
無論文字還是圖片,本篇所講都是針對畫布,這點要清楚。如果是文字,用fillText方法將文字寫到畫布上,如果是圖片,則用drawImage方法將圖片畫到畫布上。然后通過getImageData方法獲取像素,進行判斷,從而取得想要的坐標。不了解getImageData的具體可參考:getImageData
如何獲取想要的像素點坐標?一般情況下我們可以根據像素點rgba中的a值(透明度)進行判斷。
法1:
var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var img = document.getElementById('img1'); ctx.drawImage(img, 0, 0); var data = ctx.getImageData(0, 0, canvas.width, canvas.height).data; var length = data.length; var textPoint = []; for (var i = 0, wl = canvas.width * 4; i < length; i += 4) { if (data[i + 3]) { // 根據透明度判斷 var x = (i % wl) / 4; var y = parseInt(i / wl) textPoint.push([x, y]); } }
法2:
var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var img = document.getElementById('img1'); ctx.drawImage(img, 0, 0); var textPoint = []; var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height); for(var i = 0; i < imgData.width; i++) for(var j = 0; j < imgData.height; j++) { var index = (i + j * imgData.width) * 4 + 3; if(imgData.data[index]) { textPoint.push([i, j]); } }
fillText:
ctx.font = "bold 12px serif" ctx.textAlign = "left"; ctx.textBaseline = "top"; ctx.fillStyle = 'red'; ctx.fillText('慧', 0, 0);
1、文字像素粒子化
- 小文字 * textSize 法
這是一種比較常用的方法。首先在畫布上用fillText寫文字,但是寫的文字像素要小,一般選擇筆畫寬2~3個像素,甚至一個像素點。然后通過getImageData獲取的data值再進行判斷計算獲得坐標,其實就是獲得文字所組成像素的相對位置。然后將獲得的坐標乘以一個常數,就是粒子的大小(實際粒子大小可能會小於textSize以產生粒子間的間隙),這里把它稱為textSize,乘以常數后得到一個新的坐標即為粒子化后粒子的坐標。這樣在每幀渲染時只需操作新的坐標即可,得到的是相對來說擴大textSize倍的字。
demo:06wj demo
優點:可任意文字代碼擴展性強
缺點:字體選擇少;效果不直觀,需調整文字大小和textSize值調整效果
總結:適用於粒子大的demo,一般文字寬度1~3個像素
- 大文字 + 舍棄部分像素點法
這種方法也比較常見。首先在畫布上用fillText寫好文字,但是文字一定要大,跟最終出現的效果文字差不多大小,然后也是通過getImageData操作像素點,但是這里要舍棄部分像素點,因為並發的粒子太多進程會卡掉。舍棄多少因情況而異,一般舍棄的數量和粒子的大小成正比,因為舍棄的粒子需要留下的粒子通過擴大來占位。
怎么舍棄?方法參數根據需要的效果隨意,例舉一二:
demo:W·Axes 粒子化Demo2 岑安 demo
優點:可任意文字代碼擴展性強;最終大小效果直觀
缺點:字體選擇少;需要靠舍棄像素的多少調整粒子大小
總結:適用於粒子小的demo
- 其他
直接用大文字,因為像素點太多太密,而且如果不舍棄的話粒子只能以0.5為半徑,體驗十分差,在粒子化中基本不考慮。倒是在別的方面可能有用處,花叢效果文字就用到了,因為每幀不用重繪,所以渲染也不會卡。
直接用小文字那就根本不用考慮了。
2、圖片像素粒子化
demo采用的就是圖片像素粒子化。先把圖片draw到畫布上,接下去的操作就和文字一樣了。這里提一點,在本地操作時,getImageData方法報錯:
提示跨域操作data,實際上就是跨域操作圖片了。解決方法就是把代碼和圖片都放到服務器環境下(相同域名)。因為本地測試用的圖片是文件夾內的,js跨域限制是不能獲取非同一域名下的數據的, 而本地的位置是沒有域名的,所以瀏覽器都認為你是跨域,導致報錯。或者check Javascript - getImageData after fillRect and drawImage
圖片操作的結果其實就和小文字*textSize類似(有人可能會說可以用大圖片,剔除部分像素點,但是大圖片體積大加載不易,並且剔除麻煩,我這里就不考慮了),不同的是圖片能操作各種炫酷的文字,除了文字之外圖片還能操作別的需要的形狀。圖片的像素點也有要求,像素點太多后續渲染壓力會很大瀏覽器會崩潰,最好像素刪減后控制在1000以內,一般圖片20*20可取圖上所有像素點;不考慮直接用大圖片,瀏覽器會崩潰,所以只能小圖片 * size。
demo:岑安 JX官網首頁3D粒子效果
優點:不僅限於文字,適用范圍廣; 文字字體選擇多樣,效果好看
缺點:獲取圖片不方便;可擴展性不強每個demo要重新獲取圖片
3、其他
粒子化除了文字和圖片外,還有很多,比如數組模擬,這里就不加介紹了,具體請check:事情沒有想象中那么難--JX官網首頁3D粒子效果