JavaScript動(dòng)畫實(shí)例之粒子文本的實(shí)現(xiàn)方法詳解
1.粒子文本的實(shí)現(xiàn)原理
粒子文本的實(shí)現(xiàn)原理是:使用兩張 canvas,一張是用戶看不到的canvas1,用來繪制文本;另一張是用戶看到的canvas2,用來根據(jù)canvas1中繪制的文本數(shù)據(jù)來生成粒子。
先在canvas1中用如下的語句繪制待顯示的文本。
ctx1.font = '100px PingFang SC'; ctx1.textAlign = 'center'; ctx1.baseline = 'middle'; ctx1.fillText('Happy New Year',canvas1.width/2, canvas1.height/2);
然后使用canvas API的getImageData方法,獲取一個(gè)ImageData對(duì)象,這個(gè)對(duì)象用來描述 canvas 指定區(qū)域內(nèi)的像素?cái)?shù)據(jù)。語句為:var imgData = ctx1.getImageData(0, 0, canvas1.width, canvas1.height).data;
這樣imgData中保存了canvas1指定區(qū)域內(nèi)所有像素點(diǎn)的rgba值,它是一個(gè)數(shù)組。由于每個(gè)像素點(diǎn)有 rgba 四個(gè)值,所以這個(gè)數(shù)組的長度也就是“像素點(diǎn)數(shù)量 * 4”。
最后通過遍歷imgData數(shù)組,可以判斷在canvas1中,哪些點(diǎn)是有色彩的(處于文本中間),哪些點(diǎn)是沒有色彩的(不在文本上),把那些有色彩的像素位置記下來,然后在用戶可見canvas2上生成粒子并繪制粒子即可。具體編程遍歷imgData數(shù)組時(shí),可以根據(jù)透明度,也就是 rgba 中的第4個(gè)元素是否不為0來判斷該像素是否在文本中。
為此,創(chuàng)建一個(gè)自定義的粒子類Particle,該類中每個(gè)粒子對(duì)象有坐標(biāo)位置(x,y)、半徑radius和顏色color等4個(gè)屬性;有一個(gè)方法draw(),用于繪制粒子。
編寫的HTML代碼如下。
<html> <head> <title>普通粒子文本</title> </head> <body> <canvas hidden></canvas> <canvas></canvas> <script> var canvas1=document.getElementById('myCanvas1'); ctx1= canvas1.getContext('2d'); var canvas2=document.getElementById('myCanvas2'); ctx2= canvas2.getContext('2d'); canvas1.width = canvas2.width = window.innerWidth; canvas1.height = canvas2.height = window.innerHeight; ctx1.font = '100px PingFang SC'; ctx1.textAlign = 'center'; ctx1.baseline = 'middle'; ctx1.fillText('Happy New Year',canvas1.width/2, canvas1.height/2); var imgData = ctx1.getImageData(0, 0, canvas1.width, canvas1.height).data; function Particle(x,y,radius,color) { this.x = x; this.y = y; this.radius = radius; this.color = color; } Particle.prototype.draw= function() { ctx2.beginPath(); ctx2.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false); ctx2.fillStyle = this.color; ctx2.fill(); ctx2.closePath(); } var particles = []; var skip =1; for (var y = 0; y < canvas1.height; y +=skip) { for (var x = 0; x < canvas1.width; x += skip) { var opacityIndex = (x + y * canvas1.width) * 4 + 3; if (imgData[opacityIndex] > 0) { var hue = Math.floor(Math.random() * 360); var color=`hsl(${hue}, 100%, 50%)`; particles.push(new Particle(x,y,2,color)); } } } for (var particle of particles) { particle.draw(); } </script> </body> </html>
在瀏覽器中打開包含這段HTML代碼的html文件,可以看到在瀏覽器窗口中繪制出如圖1所示的粒子文本。
圖1 skip=1時(shí)顯示的粒子文本
由圖1可以看出拼湊文本的粒子非常密集,這是因?yàn)槌绦蛑斜闅v的步長skip=1,這樣掃描了canvas1指定區(qū)域內(nèi)的所有像素點(diǎn)。實(shí)際上在形成粒子文本時(shí),無需所有像素點(diǎn)一個(gè)像素一個(gè)像素地掃,可以增大skip值,使得最后產(chǎn)生的粒子稀疏些。
例如,將程序中的語句“skip=1”修改為“skip=4”,則在瀏覽器窗口中繪制出如圖2所示的粒子文本。
圖2 skip=4時(shí)顯示的粒子文本
2.粒子文本的動(dòng)態(tài)效果
了解了普通粒子文本的實(shí)現(xiàn)原理后,可以為拼湊文本的粒子添加一些動(dòng)態(tài)動(dòng)效。從2個(gè)方面著手。
(1)給粒子賦予一些隨機(jī)的位移,避免看上去過于整齊。
(2)粒子的大小隨機(jī)產(chǎn)生,在創(chuàng)建粒子時(shí)對(duì)粒子初始半徑radius 進(jìn)行random 取隨機(jī)值。另外為了讓粒子半徑動(dòng)態(tài)改變,增加一個(gè)屬性dynamicRadius,代表粒子的渲染半徑,它根據(jù)粒子的初始半徑radius,采用三角函數(shù)進(jìn)行平滑改變。
編寫如下的HTML代碼。
<html> <head> <title>粒子文本的動(dòng)態(tài)效果</title> </head> <body> <canvas hidden></canvas> <canvas></canvas> <script> var canvas1=document.getElementById('myCanvas1'); ctx1= canvas1.getContext('2d'); var canvas2=document.getElementById('myCanvas2'); ctx2= canvas2.getContext('2d'); canvas1.width = canvas2.width = window.innerWidth; canvas1.height = canvas2.height = window.innerHeight; ctx1.font = '120px PingFang SC'; ctx1.textAlign = 'center'; ctx1.baseline = 'middle'; ctx1.fillText('Happy New Year',canvas1.width/2, canvas1.height/2); var imgData = ctx1.getImageData(0, 0, canvas1.width, canvas1.height).data; function Particle(x,y,radius,color) { this.x = x; this.y = y; this.radius = radius; this.color = color; this.dynamicRadius = radius; } Particle.prototype.draw= function() { ctx2.beginPath(); ctx2.arc(this.x, this.y,this.dynamicRadius, 0, 2 * Math.PI, false); ctx2.fillStyle = this.color; ctx2.fill(); ctx2.closePath(); } Particle.prototype.update= function() { this.dynamicRadius =3+2*Math.sin(new Date()/1000%1000*this.radius); } function random(min,max) { return Math.random() * ( max - min ) + min; } var particles = []; var skip =4; for (var y = 0; y < canvas1.height; y +=skip) { for (var x = 0; x < canvas1.width; x += skip) { var opacityIndex = (x + y * canvas1.width) * 4 + 3; if (imgData[opacityIndex] > 0) { var hue = Math.floor(Math.random() * 360); var color=`hsl(${hue}, 100%, 50%)`; particles.push(new Particle(x+random(1,3),y+random(1,3),random(1,4),color)); } } } for (var particle of particles) { particle.draw(); } function loop() { requestAnimationFrame(loop); ctx2.clearRect(0,0,canvas2.width,canvas2.height); for (var particle of particles) { particle.update(); particle.draw(); } } loop(); </script> </body> </html>
在瀏覽器中打開包含這段HTML代碼的html文件,可以看到在瀏覽器窗口中呈現(xiàn)出如圖3所示的粒子文本動(dòng)態(tài)效果。
圖3 粒子文本的動(dòng)態(tài)效果
到此這篇關(guān)于JavaScript動(dòng)畫實(shí)例之粒子文本的實(shí)現(xiàn)方法詳解的文章就介紹到這了,更多相關(guān)JavaScript動(dòng)畫實(shí)例之粒子文本內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- js canvas實(shí)現(xiàn)隨機(jī)粒子特效
- js實(shí)現(xiàn)三角形粒子運(yùn)動(dòng)
- js實(shí)現(xiàn)3D粒子酷炫動(dòng)態(tài)旋轉(zhuǎn)特效
- JS實(shí)現(xiàn)躲避粒子小游戲
- javascript Canvas動(dòng)態(tài)粒子連線
- JavaScript實(shí)現(xiàn)鼠標(biāo)移動(dòng)粒子跟隨效果
- 基于three.js實(shí)現(xiàn)的3D粒子動(dòng)效實(shí)例代碼
- 原生JS+HTML5實(shí)現(xiàn)跟隨鼠標(biāo)一起流動(dòng)的粒子動(dòng)畫效果
- 使用3D引擎threeJS實(shí)現(xiàn)星空粒子移動(dòng)效果
- ThingJS粒子特效一鍵實(shí)現(xiàn)雨雪效果
相關(guān)文章
webpack-dev-server 的 host 配置 0.0.0.0的方法
這篇文章主要介紹了webpack-dev-server 的 host 配置 0.0.0.0的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,,需要的朋友可以參考下2024-01-01js實(shí)現(xiàn)溫度計(jì)時(shí)間樣式代碼分享
本文主要介紹了javascript實(shí)現(xiàn)溫度計(jì)時(shí)間樣式,推薦給大家,有需要的小伙伴可以參考下。2015-08-08iphone safari不支持position fixed的解決方法
最近一直在做移動(dòng)web開發(fā),開發(fā)過程中遇到了許多問題,mobile safari不支持position: fixed就是一件很頭疼的事情2012-05-05Echarts圖表如何利用formatter自定義tooltip的內(nèi)容和樣式
這篇文章主要給大家介紹了關(guān)于Echarts圖表如何利用formatter自定義tooltip的內(nèi)容和樣式的相關(guān)資料,echarts的圖表配置非常的靈活自由,但是不熟悉的時(shí)候容易不知道怎么配置,需要的朋友可以參考下2023-06-06Javascript在IE下設(shè)置innerHTML時(shí)出現(xiàn)未知的運(yùn)行時(shí)錯(cuò)誤的解決方法
程序代碼思路大致如下,想動(dòng)態(tài)的改變tr標(biāo)簽的innerHTML內(nèi)容,但是IE卻報(bào)未知的運(yùn)行時(shí)錯(cuò)誤2011-01-01For循環(huán)中分號(hào)隔開的3部分的執(zhí)行順序探討
這篇文章主要探討了For循環(huán)中分號(hào)隔開的3部分的執(zhí)行順序,需要的朋友可以參考下2014-05-05