還在用canvas畫格子嗎?文字煙花效果更不錯噢
大家好,我是小丞同學,一名前端愛好者
歡迎訪問博主的個人網站:一口奶蓋
💞「在人間販賣聲音 等湊夠滿天星辰 放煙花給你看」
上次的煙花有些許平淡,這次來放大招了,讓你的名字在天空綻放!
喜歡的話可以私信源碼去曬狗糧噢~
全程高能,無尿點,有部分內容在上期的文章中噢~
實現效果
你以為僅此而已嗎,後面還有大招噢
實現過程
1. 在畫布上繪製文字
通過ctx.font
設定字體的大小以及字體,再填充顏色,最後通過ctx.fillText
繪製到畫布當中,這裡有幾個需要注意的地方:
注意:
ctx.font
至少需要兩個參數,一個字體大小,一個字體- 這裡的顏色之所以設為
#000001
原因是背景是黑色的,這樣這個字不會被看到,但是它是真實存在的,不然每次點擊時都會有一個字體生成在左上角,影響視覺,當然也可以新建在一個畫布,這裡就簡單處理了 ctx.measureText(text)
:返回一個對象,該對象包含以像素計的指定字體寬度。
// 填充字體樣式
let font = 120
ctx.font = font + "px '微軟雅黑'"
ctx.fillStyle = "#000001"
// 內容
let text = '小丞同學'
// 獲取字體的寬度
let textWidth = ctx.measureText(text).width
// 在左上角填充字體
ctx.fillText(text,0 , font)
2. 獲取像素點
通過ctx.getImageData
可以獲取一個區域內的像素數據,返回的是一個imageData
對象
對於 ImageData 對象中的每個像素,都存在着四方面的信息,即 RGBA 值:
- R – 紅色 (0-255)
- G – 綠色 (0-255)
- B – 藍色 (0-255)
- A – alpha 通道 (0-255; 0 是透明的,255 是完全可見的)
在前面的代碼中我們在 (0,0) 的位置繪製了字體,我們通過getImageData
將這塊區域的像素信息取出來。
let imgData = ctx.getImageData(0, 0, textWidth, font * 1.2)
我們先看看imgData
,可以看到裏面的數據十分龐大,裏面存儲的是像素信息
這樣我們可以通過判斷這些像素點來實現粒子的效果
3. 實現文字粒子化
在上面一步中我們已經將文字的像素信息得到了,也就相當於我們複製了一個文字,我們可以遍歷整個imgData.data
數組就能繪製出原先的文字,那我們要實現粒子化的效果,就需要隔幾個像素格再繪製,這樣繪製處理的圖形就會是一個粒子化的效果,原因就是部分位置的像素,沒有進行渲染
for (let h = 0; h < font * 1.2; h += 6) {
for (let w = 0; w < textWidth; w += 6) {
let position = (textWidth * h + w) * 4;
// 返回的數組是rgba的方式存儲
let r = imgData.data[position],
g = imgData.data[position + 1],
b = imgData.data[position + 2],
a = imgData.data[position + 3];
if (r + g + b == 0) {
continue
}
//煙花代碼
}
}
在上面的代碼塊中,遍歷了從左到右,從上到下,遍歷了整個圖形區域的全部像素信息,r,g,b,a
對應一個某個像素點的顏色,當顏色不為黑色時,我們不對它進行操作,跳過此輪循環,當顏色不為黑色時,利用該點的信息生成一個煙花粒子
let firework = {};
firework.x = x;
firework.y = y;
firework.fx = x + w - textWidth / 2;
firework.fy = y + h - font / 2;
firework.size = Math.floor(Math.random() * 2) + 1;
firework.speed = 1;
setColors(firework);
fireworks.push(firework);
煙花粒子對象存入煙花數組中
4. 設置粒子動畫
現在我們已經得到了一整個即將綻放的煙花數組,我們只需要給他們加上動畫,通過每次渲染時改變當前粒子的坐標,降低透明度實現煙花殆盡的效果,直至煙花粒子透明度降為0
關鍵代碼
firework.x += (firework.fx - firework.x) / 10;
firework.y += (firework.fy - firework.y) / 10 - (firework.alpha - 1) * firework.speed;
firework.alpha -= 0.01;
// 如果透明度小於0就刪除這個粒子
if (firework.alpha <= 0) {
fireworks.splice(i, 1);
// 跳過這次循環,不進行繪製
continue;
}
5. 設置拖尾並渲染更新畫布
拖尾實現的思路是不斷的添加一個半透明的蒙層來實現,使用 requestAnimationFrame
於定時器的區別在上篇文章有講過噢
function tick() {
// // 設置拖影
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = 'rgba(0,0,0,' + 10 / 100 + ')';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = 'lighter';
// 更新畫布
drawFires();
requestAnimationFrame(tick);
}
總結
今天的煙花就到這裡反映結束了,不過癮的話,可以讓我們一起期待下一篇圖片煙花效果噢~摩爾莊園的煙花也很好看噢!