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

到此,整个效果就出来了。固然这里面有不少细节能够本身琢磨琢磨,让这个效果变得更加细腻多彩。但愿对新手有所帮助。

若需转载,请注明出处,谢谢!

相关文章
相关标签/搜索