canvas-簡單快速實現知乎登陸頁背景效果

前言

打開知乎的登陸頁,就能夠看到其背景有一個動效,看起來好像蠻不錯的樣子:
知乎登陸頁canvas

這個效果使用canvas是不難實現的,接下來就一步一步地講解並實現這個效果。數組

分析

在動工以前先分析這個效果究竟是如何運動的。首先要理解的是雖然看起來好像全部線和圓都在運動,但實際上只有圓纔是在運動的,而線只不過是把知足必定條件的任意兩個圓鏈接在一塊兒。那麼接下來就分析圓是怎麼運動的,從效果看,每一個圓都是在作勻速直線運動,並且運動方向不一,經過物理相關知識能夠得知,每個圓在水平方向和垂直方向都有一個速度。最後是當圓運動出畫布任一邊界的時候,這個圓會從出邊界的這條邊的對邊再次進入畫布。把這三個關鍵點理解清楚了就清晰不少了。dom

實踐

先建立一個canvas畫布:函數

// 這裏就簡單地設置下背景色
<body style="background:#f7fafc;">
  <canvas id="canvas" style="width: 100%; height: 100%;"></canvas>
</body>

接着先獲取canvas的上下文環境並設置一些共用的屬性oop

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;

接下來繪製圓,那麼繪製圓須要圓的圓心座標,半徑,水平方向的速度,垂直方向的速度,而且這些信息要知足必定的條件,經過一個函數來建立:rest

// 存放全部圓的數組,這裏用balls
var balls = [];
function createBall() {
  // x座標
  var _x = Math.random() * canvas.width;
  // y座標
  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) );
  // 把每個圓的信息存放到數組中
  balls.push({
    x: _x,
    y: _y,
    r: _r,
    vx: _vx,
    vy: _vy
  });
}

而後根據本身的狀況選擇須要繪製多少個圓,這裏我假設有20個,看起來舒服一點:code

// 圓的數量
var num = 20;
for(var i = 0; i < num; i++) {
  createBall();
}

如今圓的信息都有了,下一步就是繪製每一幀的圓和線,建立一個render函數,而後在函數內先繪製全部的圓出來:blog

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();
}

接着要遍歷每兩個圓的圓心之間的距離是否小於某個臨界值(好比500),知足則將這兩個圓的圓心鏈接起來:get

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 函數就是計算兩點之間的距離:io

function distance(point1, point2) {
  return Math.sqrt( Math.pow( (point1.x - point2.x), 2 ) + Math.pow( (point1.y - point2.y), 2 ) );
}

還有一步就是判斷圓是否超出了邊界值,若知足條件則從對邊再次進來:

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;
  }
}

固然若是想簡單點,只要圓超出就移除並從新生成一個圓便可:

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();
}

這樣每一幀繪製的細節就完成了,最後一步就是讓圓都運動起來:

(function loop(){
  render();
  requestAnimationFrame(loop);
})();

到此,整個效果就出來了。固然這裏面有不少細節能夠本身琢磨琢磨,讓這個效果變得更加細膩多彩。但願對新手有所幫助。

若需轉載,請註明出處,謝謝!

相關文章
相關標籤/搜索