您好,登錄后才能下訂單哦!
小編給大家分享一下利用canvas實(shí)現(xiàn)知乎登錄頁(yè)的案例,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
前言
打開(kāi)知乎的登錄頁(yè),就可以看到其背景有一個(gè)動(dòng)效,看起來(lái)好像蠻不錯(cuò)的樣子:
這個(gè)效果使用canvas是不難實(shí)現(xiàn)的,接下來(lái)就一步一步地講解并實(shí)現(xiàn)這個(gè)效果。
分析
在動(dòng)工之前先分析這個(gè)效果到底是如何運(yùn)動(dòng)的。首先要理解的是雖然看起來(lái)好像所有線和圓都在運(yùn)動(dòng),但實(shí)際上只有圓才是在運(yùn)動(dòng)的,而線只不過(guò)是把滿(mǎn)足一定條件的任意兩個(gè)圓連接在一起。那么接下來(lái)就分析圓是怎么運(yùn)動(dòng)的,從效果看,每個(gè)圓都是在做勻速直線運(yùn)動(dòng),而且運(yùn)動(dòng)方向不一,通過(guò)物理相關(guān)知識(shí)可以得知,每一個(gè)圓在水平方向和垂直方向都有一個(gè)速度。最后是當(dāng)圓運(yùn)動(dòng)出畫(huà)布任一邊界的時(shí)候,這個(gè)圓會(huì)從出邊界的這條邊的對(duì)邊再次進(jìn)入畫(huà)布。把這三個(gè)關(guān)鍵點(diǎn)理解清楚了就清晰很多了。
實(shí)踐
先創(chuàng)建一個(gè)canvas畫(huà)布:
// 這里就簡(jiǎn)單地設(shè)置下背景色 <body style="background:#f7fafc;"> <canvas id="canvas" style="width: 100%; height: 100%;"></canvas> </body>
接著先獲取canvas的上下文環(huán)境并設(shè)置一些共用的屬性
var canvas = document.getElementById("canvas"); var context = canvas.getContext("2d"); canvas.width = document.documentElement.clientWidth; canvas.height = document.documentElement.clientHeight; context.fillStyle = "rgba(0, 0, 0, 0.08)"; context.strokeStyle = "rgba(0, 0, 0, 0.05)"; context.lineWidth = 0.5;
接下來(lái)繪制圓,那么繪制圓需要圓的圓心坐標(biāo),半徑,水平方向的速度,垂直方向的速度,并且這些信息要滿(mǎn)足一定的條件,通過(guò)一個(gè)函數(shù)來(lái)創(chuàng)建:
// 存放所有圓的數(shù)組,這里用balls var balls = []; function createBall() { // x坐標(biāo) var _x = Math.random() * canvas.width; // y坐標(biāo) var _y = Math.random() * canvas.height; // 半徑 [0.01, 15.01] var _r = Math.random() * 15 + 0.01; // 水平速度 [±0.0, ±0.5] var _vx = Math.random() * 0.5 * Math.pow( -1, Math.floor(Math.random() * 2 + 1) ); // 垂直速度 [±0.0, ±0.5] var _vy = Math.random() * 0.5 * Math.pow( -1, Math.floor(Math.random() * 2 + 1) ); // 把每一個(gè)圓的信息存放到數(shù)組中 balls.push({ x: _x, y: _y, r: _r, vx: _vx, vy: _vy }); }
然后根據(jù)自己的情況選擇需要繪制多少個(gè)圓,這里我假設(shè)有20個(gè),看起來(lái)舒服一點(diǎn):
// 圓的數(shù)量 var num = 20; for(var i = 0; i < num; i++) { createBall(); }
現(xiàn)在圓的信息都有了,下一步就是繪制每一幀的圓和線,創(chuàng)建一個(gè)render函數(shù),然后在函數(shù)內(nèi)先繪制所有的圓出來(lái):
for(var k = 0; k < num; k++) { context.save(); context.beginPath(); context.arc( balls[k].x, balls[k].y, balls[k].r, 0, Math.PI*2 ); context.fill(); context.restore(); }
接著要遍歷每?jī)蓚€(gè)圓的圓心之間的距離是否小于某個(gè)臨界值(比如500),滿(mǎn)足則將這兩個(gè)圓的圓心連接起來(lái):
for(var i = 0; i < num; i++) { for(var j = i + 1; j < num; j++) { if( distance( balls[i], balls[j] ) < 500 ) { context.beginPath(); context.moveTo( balls[i].x, balls[i].y ); context.lineTo( balls[j].x, balls[j].y ); context.stroke(); } } }
這里的 distance 函數(shù)就是計(jì)算兩點(diǎn)之間的距離:
function distance(point1, point2) { return Math.sqrt( Math.pow( (point1.x - point2.x), 2 ) + Math.pow( (point1.y - point2.y), 2 ) ); }
還有一步就是判斷圓是否超出了邊界值,若滿(mǎn)足條件則從對(duì)邊再次進(jìn)來(lái):
for(var k = 0; k < num; k++) { balls[k].x += balls[k].vx; balls[k].y += balls[k].vy; if( balls[k].x - balls[k].r > canvas.width ) { balls[k].x = 0 - balls[k].r; } if( balls[k].x + balls[k].r < 0 ) { balls[k].x = canvas.width + balls[k].r; } if( balls[k].y - balls[k].r > canvas.height ) { balls[k].y = 0 - balls[k].r; } if( balls[k].y + balls[k].r < 0 ) { balls[k].y = canvas.height + balls[k].r; } }
當(dāng)然如果想簡(jiǎn)單點(diǎn),只要圓超出就移除并重新生成一個(gè)圓即可:
if( balls[k].x - balls[k].r > canvas.width || balls[k].x + balls[k].r < 0 || balls[k].y - balls[k].r > canvas.height || balls[k].y + balls[k].r < 0) { balls.splice(k, 1); createBall(); }
這樣每一幀繪制的細(xì)節(jié)就完成了,最后一步就是讓圓都運(yùn)動(dòng)起來(lái):
(function loop(){ render(); requestAnimationFrame(loop); })();
以上是利用canvas實(shí)現(xiàn)知乎登錄頁(yè)的案例的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。