Canvas實現文字粒子效果
最終實現效果
文字粒子
實現思路:
獲取到canvas繪製後螢幕上畫素點的陣列,在目標畫素點上繪製粒子替換掉原來的內容
- 繪製文字
- 通過API獲取畫布的二進位制陣列
- 設定粒子的填充步長
- 新增粒子
- 迴圈的遍歷粒子,更新粒子的狀態
程式碼實現
繪製文字
context.textAlign = "center"; context.font = this.size + "px arial"; context.fillText(this.text, this.x, this.y);
獲取 二進位制
陣列
let idata = context.getImageData(0, 0, canvas.width, canvas.height); // 獲取 canvas指定範圍內的 畫素陣列 let buffer32 = new Uint32Array(idata.data.buffer); // 轉成32位的陣列
這裡使用的 getImageData()
方法是獲取畫布內所有的畫素點的 二進位制
表示,在JS中使用 Uint32Array
來接收,已陣列形式展現,沒有渲染的地方陣列值是0,有渲染的地方為一個非0的數字
填充粒子
// 遍歷所有的陣列 for (var j = 0; j < canvas.height; j += gridY) {//步長 for (var i = 0; i < canvas.width; i += gridX) {//步長 if (buffer32[j * canvas.width + i]) { // 放入粒子物件 var ball = new Particle(i, j); this.placement.push(ball); } } }
這裡的意思是在二進位制陣列中某一個範圍內的粒子的密度,其中步長越小越密集
更新粒子狀態
(function drawFrame() { window.requestAnimationFrame(drawFrame); context.clearRect(0, 0, canvas.width, canvas.height); for (var i = 0; i < word.placement.length; i++) { //呼叫particle對像的drawParticle方法,開始畫布上畫 word.placement[i].drawParticle(); } }())
this.drawParticle = function () { // 當前粒子變小到一定程度之後,每次將它的半徑+0.1,使其慢慢變大 if (this.radius < this.futurRadius && this.dying === false) { this.radius += durVal; } else { //粒子已經到達最大狀態 this.dying = true; //表示粒子還處於show狀態 } //每次-0.1 if (this.dying) { this.radius -= durVal; } // 畫粒子形狀 context.save(); context.fillStyle = this.color; context.beginPath(); context.fillRect(this.x, this.y, this.futurRadius, this.futurRadius) context.closePath(); context.fill(); context.restore(); //將消失的粒子重置最初的狀態 if (this.y < 0 || this.radius < 1) { this.x = this.base[0]; this.y = this.base[1]; this.dying = false; this.futurRadius = randomInt(1.1, 5.1); } }
完整程式碼
<!DOCTYPE html> <html lang="en"> <head> </head> <body> <canvas id="dir" width="800" height="800" style="border:1px solid #ccc"> </canvas> <script> var canvas = document.getElementById("dir"); var context = canvas.getContext("2d"); var gridY = 10, gridX = 10, colors = ['#f44336', '#e91e63', '#9c27b0', '#673ab7', '#3f51b5', '#2196f3', '#03a9f4', '#00bcd4', '#009688', '#4CAF50', '#8BC34A', '#CDDC39', '#FFEB3B', '#FFC107', '#FF9800', '#FF5722' ], durVal = 0.1; // 粒子 function Particle(x, y) { this.x = x; this.y = y; this.color = colors[Math.floor(Math.random() * colors.length)]; //'bleack'// this.futurRadius = randomInt(1.1, 5.1); this.radius = 1.1; this.dying = false; this.base = [x, y]; this.drawParticle = function () { // 當前粒子變小到一定程度之後,每次將它的半徑+0.1,使其慢慢變大 if (this.radius < this.futurRadius && this.dying === false) { this.radius += durVal; } else { //粒子已經到達最大狀態 this.dying = true; //表示粒子還處於show狀態 } //每次-0.1 if (this.dying) { this.radius -= durVal; } // 畫粒子形狀 context.save(); context.fillStyle = this.color; context.beginPath(); context.fillRect(this.x, this.y, this.futurRadius, this.futurRadius) context.closePath(); context.fill(); context.restore(); //將消失的粒子重置最初的狀態 if (this.y < 0 || this.radius < 1) { this.x = this.base[0]; this.y = this.base[1]; this.dying = false; this.futurRadius = randomInt(1.1, 5.1); } } } function Shape(x, y, texte) { this.x = x; this.y = y; this.size = 200; this.text = texte; this.placement = []; } Shape.prototype.getValue = function () { context.textAlign = "center"; context.font = this.size + "px arial"; context.fillText(this.text, this.x, this.y); let idata = context.getImageData(0, 0, canvas.width, canvas.height); // 獲取 canvas指定範圍內的 畫素陣列 let buffer32 = new Uint32Array(idata.data.buffer); // 轉成32位的陣列 // 遍歷所有的陣列 for (var j = 0; j < canvas.height; j += gridY) { for (var i = 0; i < canvas.width; i += gridX) { if (buffer32[j * canvas.width + i]) { // 放入粒子物件 var ball = new Particle(i, j); this.placement.push(ball); } } } context.clearRect(0, 0, canvas.width, canvas.height); } function randomInt(min, max) { return min + Math.random() * (max - min + 1); } var word = new Shape(canvas.width / 2, canvas.height / 2, '文字粒子') word.getValue (function drawFrame() { window.requestAnimationFrame(drawFrame); context.clearRect(0, 0, canvas.width, canvas.height); for (var i = 0; i < word.placement.length; i++) { //呼叫particle對像的drawParticle方法,開始畫布上畫 word.placement[i].drawParticle(); } }()) </script> </body> </html>