1. 程式人生 > 實用技巧 >JavaScript動畫例項:粒子文字

JavaScript動畫例項:粒子文字

1.粒子文字的實現原理

粒子文字的實現原理是:使用兩張 canvas,一張是使用者看不到的canvas1,用來繪製文字;另一張是使用者看到的canvas2,用來根據canvas1中繪製的文字資料來生成粒子。

先在canvas1中用如下的語句繪製待顯示的文字。

ctx1.font = '100px PingFang SC';

ctx1.textAlign = 'center';

ctx1.baseline = 'middle';

ctx1.fillText('Happy New Year',canvas1.width/2, canvas1.height/2);

然後使用canvas API的getImageData方法,獲取一個ImageData物件,這個物件用來描述 canvas 指定區域內的畫素資料。語句為:

var imgData = ctx1.getImageData(0, 0, canvas1.width, canvas1.height).data;

這樣imgData中儲存了canvas1指定區域內所有畫素點的rgba值,它是一個陣列。由於每個畫素點有 rgba 四個值,所以這個陣列的長度也就是“畫素點數量 * 4”。

最後通過遍歷imgData陣列,可以判斷在canvas1中,哪些點是有色彩的(處於文字中間),哪些點是沒有色彩的(不在文字上),把那些有色彩的畫素位置記下來,然後在使用者可見canvas2上生成粒子並繪製粒子即可。具體程式設計遍歷imgData陣列時,可以根據透明度,也就是 rgba 中的第4個元素是否不為0來判斷該畫素是否在文字中。

為此,建立一個自定義的粒子類Particle,該類中每個粒子物件有座標位置(x,y)、半徑radius和顏色color等4個屬性;有一個方法draw(),用於繪製粒子。

編寫的HTML程式碼如下。

<html>

<head>

<title>普通粒子文字</title>

</head>

<body>

<canvas id="myCanvas1" style="position: absolute; " hidden></canvas>

<canvas id="myCanvas2" style="position: absolute;"></canvas>

<script>

var canvas1=document.getElementById('myCanvas1');

ctx1= canvas1.getContext('2d');

var canvas2=document.getElementById('myCanvas2');

ctx2= canvas2.getContext('2d');

canvas1.width = canvas2.width = window.innerWidth;

canvas1.height = canvas2.height = window.innerHeight;

ctx1.font = '100px PingFang SC';

ctx1.textAlign = 'center';

ctx1.baseline = 'middle';

ctx1.fillText('Happy New Year',canvas1.width/2, canvas1.height/2);

var imgData = ctx1.getImageData(0, 0, canvas1.width, canvas1.height).data;

function Particle(x,y,radius,color)

{

this.x = x;

this.y = y;

this.radius = radius;

this.color = color;

}

Particle.prototype.draw= function()

{

ctx2.beginPath();

ctx2.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false);

ctx2.fillStyle = this.color;

ctx2.fill();

ctx2.closePath();

}

var particles = [];

var skip =1;

for (var y = 0; y < canvas1.height; y +=skip)

{

for (var x = 0; x < canvas1.width; x += skip)

{

var opacityIndex = (x + y * canvas1.width) * 4 + 3;

if (imgData[opacityIndex] > 0)

{

var hue = Math.floor(Math.random() * 360);

var color=`hsl(${hue}, 100%, 50%)`;

particles.push(new Particle(x,y,2,color));

}

}

}

for (var particle of particles)

{

particle.draw();

}

</script>

</body>

</html>

在瀏覽器中開啟包含這段HTML程式碼的html檔案,可以看到在瀏覽器視窗中繪製出如圖1所示的粒子文字。

圖1 skip=1時顯示的粒子文字

由圖1可以看出拼湊文字的粒子非常密集,這是因為程式中遍歷的步長skip=1,這樣掃描了canvas1指定區域內的所有畫素點。實際上在形成粒子文字時,無需所有畫素點一個畫素一個畫素地掃,可以增大skip值,使得最後產生的粒子稀疏些。

例如,將程式中的語句“skip=1”修改為“skip=4”,則在瀏覽器視窗中繪製出如圖2所示的粒子文字。

圖2 skip=4時顯示的粒子文字

2.粒子文字的動態效果

瞭解了普通粒子文字的實現原理後,可以為拼湊文字的粒子新增一些動態動效。從2個方面著手。

(1)給粒子賦予一些隨機的位移,避免看上去過於整齊。

(2)粒子的大小隨機產生,在建立粒子時對粒子初始半徑radius 進行random 取隨機值。另外為了讓粒子半徑動態改變,增加一個屬性dynamicRadius,代表粒子的渲染半徑,它根據粒子的初始半徑radius,採用三角函式進行平滑改變。

編寫如下的HTML程式碼。

<html>

<head>

<title>粒子文字的動態效果</title>

</head>

<body>

<canvas id="myCanvas1" style="position: absolute; " hidden></canvas>

<canvas id="myCanvas2" style="position: absolute;"></canvas>

<script>

var canvas1=document.getElementById('myCanvas1');

ctx1= canvas1.getContext('2d');

var canvas2=document.getElementById('myCanvas2');

ctx2= canvas2.getContext('2d');

canvas1.width = canvas2.width = window.innerWidth;

canvas1.height = canvas2.height = window.innerHeight;

ctx1.font = '120px PingFang SC';

ctx1.textAlign = 'center';

ctx1.baseline = 'middle';

ctx1.fillText('Happy New Year',canvas1.width/2, canvas1.height/2);

var imgData = ctx1.getImageData(0, 0, canvas1.width, canvas1.height).data;

function Particle(x,y,radius,color)

{

this.x = x;

this.y = y;

this.radius = radius;

this.color = color;

this.dynamicRadius = radius;

}

Particle.prototype.draw= function()

{

ctx2.beginPath();

ctx2.arc(this.x, this.y,this.dynamicRadius, 0, 2 * Math.PI, false);

ctx2.fillStyle = this.color;

ctx2.fill();

ctx2.closePath();

}

Particle.prototype.update= function()

{

this.dynamicRadius =3+2*Math.sin(new Date()/1000%1000*this.radius);

}

function random(min,max)

{

return Math.random() * ( max - min ) + min;

}

var particles = [];

var skip =4;

for (var y = 0; y < canvas1.height; y +=skip)

{

for (var x = 0; x < canvas1.width; x += skip)

{

var opacityIndex = (x + y * canvas1.width) * 4 + 3;

if (imgData[opacityIndex] > 0)

{

var hue = Math.floor(Math.random() * 360);

var color=`hsl(${hue}, 100%, 50%)`;

particles.push(new Particle(x+random(1,3),y+random(1,3),random(1,4),color));

}

}

}

for (var particle of particles)

{

particle.draw();

}

function loop()

{

requestAnimationFrame(loop);

ctx2.clearRect(0,0,canvas2.width,canvas2.height);

for (var particle of particles)

{

particle.update();

particle.draw();

}

}

loop();

</script>

</body>

</html>

在瀏覽器中開啟包含這段HTML程式碼的html檔案,可以看到在瀏覽器視窗中呈現出如圖3所示的粒子文字動態效果。

圖3 粒子文字的動態效果