canvas 文字粒子特效

轉(zhuǎn)自博客原文連接:https://tong-h.github.io/2019/04/23/canvas-fontparticle/

想要往倉庫多填一些干貨,一個文字粒子效果 點這里看效果

效果圖

隨機初始化部分粒子

1、首先要明白每個粒子都是一個對象,都有自己的移動軌跡,起點,移動速度,終點

2、粒子活動軌跡:初始化 ---- 聚合拼合文字形狀 ---- 散開 ---- 再聚合 ---- 散開...

3、我們需要根據(jù)動畫時間調(diào)整粒子移動的速度來安排他們的位置

    class Point{
        constructor() {
            this.startx = Math.floor(Math.random() * docsize[0]),   // 初始起點
            this.starty = Math.floor(Math.random() * docsize[1]),
            this.speedx = (Math.random() * 2 - 1) * pointspeed,     // 移動速度
            this.speedy = (Math.random() * 2 - 1) * pointspeed, 
            this.endx = 0,                                          // 終點
            this.endy = 0,                    
            this.color = Math.floor(Math.random() * 5)              // 粒子顏色
        }
        endpoint(x, y) {
            this.endx = x
            this.endy = y
        }
        animal() {
            this.startx += this.speedx
            this.starty += this.speedy

            // 到達邊界改變粒子運動方向
            this.speedx *= this.startx > docsize[0] || this.startx < 0 ? -1 : 1
            this.speedy *= this.starty > docsize[1] || this.starty < 0 ? -1 : 1

            // 調(diào)整點的移動速度用以聚和拼合文字
            if(time === 100 || time === 600 || time === 1100) { 
                this.speedx = (this.endx - this.startx) / joinspeed
                this.speedy = (this.endy - this.starty) / joinspeed
            }

            // 到達終點后靜止不動
            if(time === 100 + joinspeed || time === 600 + joinspeed || time === 1100 + joinspeed) {
                this.speedx = 0
                this.speedy = 0
            }

            // 散開
            if(time === 300 || time === 800) {
                this.speedx = (Math.random() * 2 - 1) * pointspeed
                this.speedy = (Math.random() * 2 - 1) * pointspeed
            }

            maincontent.beginPath()
            maincontent.fillStyle = color[this.color]
            maincontent.arc(this.startx, this.starty, 7, 0, Math.PI * 2)
            maincontent.fill()
        }
    }

使用 canvas 畫板生成文字

// 【文字面積,循環(huán)時用于判讀y軸高度,粒子大小間隔, 文字寬度】
let [imgdata, cyclic, size, textwith] = [{}, 1, 16, 0]

textcontext.font = "normal 900 " + fontsize +"px Avenir, Helvetica Neue, Helvetica, Arial, sans-serif"
textwith = Math.floor(textcontext.measureText(text).width)
textcontext.fillStyle = '#ff0000'
textcontext.fillText(text, (docsize[0] - textwith) / 2, (docsize[1]) / 2)
textwith = ~~ (textwith) * size + size

遍歷 imageData 獲取文字區(qū)域的像素坐標

不了解 imagedata 怎么用? 看看這篇文章cannvas的imagedata對象

獲取坐標這里有很多種方法,我看了一些教程好像沒人像我這么寫,要注意的是

  • imageData 4個元素為一個像素,也就是一個R G B A 值,A 是 alpha 透明度
  • 空白的區(qū)域rgba就是 0,0,0,0 , 文字區(qū)域就是有顏色的如果你沒有設(shè)置字體顏色默認是黑色 rgba 就是 0,0,0,255,通過判斷第四個元素可以獲取文字區(qū)域
  • 但是我建議重新設(shè)置一個其他的顏色比如紅色 255,0,0,255,用第1個和2個數(shù)字來判斷這樣字體邊緣會圓滑些,因為在字體邊緣黑色和白色的交界處可能有某幾個像素不是透明的
  • 每個坐標最后都會生成一個圓,所以這里獲取的是圓心的坐標,圓之間還需要留有空隙,所以遍歷的時候你要根據(jù)你的圓的大小掌握好間隔
  • 獲取文字區(qū)域粒子數(shù)量后需要判斷,目前屏幕上現(xiàn)有的粒子是否足夠拼合和文字或者是否還需再添加粒子
  • 確定粒子數(shù)量后再將文字坐標作為粒子移動終點賦值給粒子
// 獲取文字所在區(qū)域,盡可能減小面積
imgdata = textcontext.getImageData(0,0, textwith, fontsize * 2)
textcontext.clearRect(0, 0, docsize[0], docsize[1])

// 粒子圓心坐標,粒子數(shù)組
let [x, y, len] = [0, 0, 0]

// 遍歷data數(shù)據(jù)查找文字所在的坐標
for (var i = 0; i < imgdata.data.length; i += size * 4) {
    if (imgdata.data[i] === 255 && imgdata.data[i+3] === 255) {

        // 判斷當前粒子數(shù)量是否能夠拼合文字
        if (len > pointarr.length - 1) pointarr.push(new Point)

        // 獲取每個粒子聚攏的終點
        pointarr[len].endpoint(i /4 % textwith, cyclic)
        len ++
    }
    if (i/4 == cyclic * textwith) {
        cyclic += size
        i = textwith * (cyclic-1) * 4
    } 
}

pointarr.length - 1 - len > 0 ? pointarr.splice(len, pointarr.length - len) : ''

源碼帶有詳細的注解點這兒

更多效果
開源不易,覺得還不錯點個 start 吧 (′▽`???)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容