canvas 绘制特效 小球连接线动画

1,861 阅读1分钟

引言

   一个很经典的特效,花了一点时间自己手动写了一个,先上图:

小球连接线动画

详细代码

html

<canvas id="canvas_bg"></canvas>

css

html, body {
  height: 100%;
  padding: 0;
  margin: 0;
}
#canvas_bg {
  display: block;
}

javascript

class circle {
 constructor(num) {
   this.canvas = document.getElementById('canvas_bg');
   this.canvas.width = document.documentElement.clientWidth;
   this.canvas.height = document.documentElement.clientHeight;
   this.ctx = this.canvas.getContext('2d');

   // 创建随机状态小球
   this.arr = Array.from(new Array(num)).map(item => ({
     x: Math.random() * this.canvas.width,
     y: Math.random() * this.canvas.height,
     speed: Math.random() * 1.5 + 0.5,
     xDir: Math.random() > 0.5 ? -1:1,
     yDir: Math.random() > 0.5 ? -1:1,
     r: 2
   }))
   // 小球连线距离
   this.dist = 100

   this.animation()

   window.onresize = ()=> {
     this.canvas.width = document.documentElement.clientWidth;
     this.canvas.height = document.documentElement.clientHeight;
   }
 }
 // 计算小球位置并判断方向与绘制
 drawCircle() {
   this.arr.forEach(item => {
     item.x += item.xDir * item.speed
     item.y += item.yDir * item.speed

     item.x <= 0 && (item.xDir = 1) 
     item.x > this.canvas.width - 1 && (item.xDir = -1, item.x = this.canvas.width - 1)

     item.y <= 0 && (item.yDir = 1) 
     item.y > this.canvas.height - 1 && (item.yDir = -1, item.y = this.canvas.height - 1)

     this.ctx.beginPath();
     this.ctx.arc(item.x, item.y, item.r, 0, 2 * Math.PI);
     this.ctx.fill();
   })
 }

 // 计算连线距离内的小球
 calcLine() {
   var arr = this.arr.concat()
   this.lineArr = []
   for(var i = 0,len = arr.length; i < len; i++){
     for(let y = i+1; y < len; y++){
       let val = Math.sqrt(Math.pow(arr[i].x - arr[y].x, 2) + Math.pow(arr[i].y - arr[y].y, 2) ,2);
       if(val < this.dist){
         this.lineArr.push({
           start: arr[i],
           end: arr[y],
           val: val,
           ratio: (val / this.dist)
         })
       }
     }
   }
}

// 绘制链接线条
 drawLine() {
   while(this.lineArr.length){
     this.ctx.beginPath()
     let item = this.lineArr.shift();
     let c = 255 * item.ratio

     this.ctx.strokeStyle = `rgb(${c},${c},${c})`
     this.ctx.moveTo(item.start.x, item.start.y)
     this.ctx.lineTo(item.end.x, item.end.y); 
     this.ctx.stroke();
   }
 }

 // 动画过渡
 animation() {
   this.canvas.width = this.canvas.width
   this.drawCircle()
   this.calcLine()
   this.drawLine()
   setTimeout(() => {
     this.animation()
   }, 30)
 }
}

var circleObj = new circle(100);

demo演示

点击进入小球动画演示Demo

解释

这个动画整体效果其实很简单,画布初始化什么的就不说了。

1.首先创建一些随机状态的小球,有位置、移动方向、移动速率等

2.通过双层循环判断每个小球之间的距离(就用初中学的勾股定理,直角三角形两边的平方和等于斜边的平方,斜边就是小球距离),符合条件的(我设置的小于100)都存起来

3.最后绘制小球与线条,加上动画渲染(我这里每隔30毫秒渲染一次,每次渲染都要重新计算上面提到的参数)

结语

详细看看上方的demo中演示与代码,代码量很少,理解起来也不难,只要你有初中知识就能理解。

以上如有问题或疏漏,欢迎指正