還在用canvas畫格子嗎?文字煙花效果更不錯噢

小丞同學發表於2021-11-01

大家好,我是小丞同學,一名前端愛好者
歡迎訪問博主的個人網站:一口奶蓋

?“在人間販賣聲音 等湊夠滿天星辰 放煙花給你看

gif4

上次的煙花有些許平淡,這次來放大招了,讓你的名字在天空綻放!

喜歡的話可以私信原始碼去曬狗糧噢~

全程高能,無尿點,有部分內容在上期的文章中噢~

實現效果

name

你以為僅此而已嗎,後面還有大招噢

實現過程

1. 在畫布上繪製文字

通過ctx.font設定字型的大小以及字型,再填充顏色,最後通過ctx.fillText繪製到畫布當中,這裡有幾個需要注意的地方:

注意

  1. ctx.font至少需要兩個引數,一個字型大小,一個字型
  2. 這裡的顏色之所以設為#000001原因是背景是黑色的,這樣這個字不會被看到,但是它是真實存在的,不然每次點選時都會有一個字型生成在左上角,影響視覺,當然也可以新建在一個畫布,這裡就簡單處理了
  3. 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對應一個某個畫素點的顏色,當顏色不為黑色時,我們不對它進行操作,跳過此輪迴圈,當顏色不為黑色時,利用該點的資訊生成一個煙花粒子

image-20210621165731907

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);
}

總結

今天的煙花就到這裡反映結束了,不過癮的話,可以讓我們一起期待下一篇圖片煙花效果噢~摩爾莊園的煙花也很好看噢!

name

相關文章