寫在最前
本次分享一下使用canvas實現粒子效果拼出你想要的文字。
歡迎關注我的博客,不定期更新中——
起因
不久之前看到大搜車團隊出品的easy mock產品的界面中有一個使用粒子拼出“mock so easy”的效果,感覺非常有意思,就像下面這樣:
當然了,這個easy mock的界面中還有粒子匯聚、散開、以及緩動等效果,這些在之後的文章中會不定時的更新實現思路。
我當時看到這個效果的時候是一段單一的英文,不知道源碼能不能支持自己配置需要的字符,故想自己實現一個可以配置的版本。
PS:突然想到作者之前也封裝過一個輸入一段英文,輸出一段可表示該字母的“黑魔法代碼”:效果就像下面這樣:
緣由也是網上有人用這種黑魔法代碼拼出了單詞,但是並不是“可配置”的,也就不能想要啥就是啥,故纔有了作者的一版封裝實現,文章如下:(相關代碼在原文中提及
效果圖
你可以任意輸入你能想到的字符,只要打得進去:)
示例:
核心問題:怎麼確定粒子的擺放位置?
emmmm作者目前想到的辦法是:降低像素數
來看下這個“非常粗略”的示意圖:
這是當我在頁面輸入“an”之後展示的隱藏的canvas的截圖,我將其放入到了ps中並放大,我們可以清晰地看到該圖是由一個個很小的像素點通過每個像素點不同的顏色最終繪製出來的。而我們要做的就是用更少的“像素點”來繪製同樣的內容。也就是原來100✖️100像素的圖,我們如果用25✖️25來表示,那麼每個像素點就會粗很多,同時粒度也會更加寬泛,之後我們如果將像素點變爲圓形,最後我們就可以得到如文章開頭提到的那樣,由一個個粒子“拼”出了效果。
總的來說就是通過將輸入的信息轉化爲圖片後,讀取圖片的像素信息,同時粗略的將圖片分塊,遍歷每塊區域中的像素點判斷該塊是否需要畫一個粒子。屆時所有區域遍歷完畢就可以用比像素點少很多的粒子來大體表示每一個輸入的字符。那麼具體實現過程如下:
- 將輸入的文字轉化爲圖片插入到一個隱藏的canvas中
- 按一定比例如(4像素✖️4像素)分割該canvas圖像,形成一個擁有x * y個格子的區域,每個格子中擁有一定像素數(4✖️4 = 16)
- 讀取該canvas中的圖片像素數據
- 獲取在每一個格子中擁有除灰度顏色的像素數(白底或者黑底屬於插入到canvas中的圖片的背景)
- 當一個格子中有顏色的像素數佔所有像素的一定程度後,認定該區域屬於輸入字符的一部分,則在該區域畫一個粒子,否則不畫
實現過程
文字轉化爲圖片插入canvas
function loadCanvas(value) {
var fontSize = 100,
width = calWordWidth(value, fontSize),
canvas = document.createElement('canvas')
canvas.id = 'b_canvas'
canvas.width = width
canvas.height = fontSize
var ctx = canvas.getContext('2d')
ctx.font = fontSize + "px Microsoft YaHei"
ctx.fillStyle = "orange"
ctx.fillText(value, 0, fontSize / 5 * 4) //輕微調整繪製字符位置
getImage(canvas, ctx) //導出爲圖片再導入到canvas獲取圖像數據
}
function getImage(canvas, ctx) {
var image = new Image()
image.src = canvas.toDataURL("image/jpeg") //canvas導出
image.onload = function() {
...
}
}
降低像素數
var imageData = ctx.getImageData(0, 0, this.width, this.height)
var dataLength = imageData.data.length
var diff = 4 //按4✖️4劃分區域,可自行改變嘗試
var newCanvas = document.getElementById('canvas')
var newCtx = newCanvas.getContext('2d')
for (var j = 0; j < this.height; j += diff) { //height爲canvas高
for (var i = 0; i < this.width; i += diff) {//width爲canvas寬
var colorNum = 0
for (var k = 0; k < diff * diff; k++) {
var row = k % diff
var col = ~~(k / diff)
let r = imageData.data[((j + col) * this.width + i + row) * 4 + 0]
let g = imageData.data[((j + col) * this.width + i + row) * 4 + 1]
let b = imageData.data[((j + col) * this.width + i + row) * 4 + 2]
if (r < 10 && g < 10 && b < 10) colorNum++
//如果滿足此條件說明當前爲背景色黑色(canvas轉出來的圖片背景並不是純黑的
}
if (colorNum < diff * diff / 3 * 2) {
//黑色背景佔比小於一定程度說明此處應該畫粒子,佔比度可自行調整
var option = {
x: i,
y: j,
radius: 6,
color: '#fff'
}
var newBubble = new Bubble(option)
newBubble.draw(newCtx) //畫粒子
}
}
}
其他canvas相關文章
最後
源代碼見:https://github.com/Aaaaaaaty/Blog/blob/master/canvas/canvasImitateWord/main.js
本次只實現了可配置拼出字符的功能,粒子動態上沒加入特效,其他效果實現思路之後可能會不定時更新——
慣例po作者的博客,不定時更新中——
有問題歡迎在issues下交流。