canvas动画套路
canvas 本意画布,应该就是画油画的那种,因此一次绘画其实只能画出一副画面。但是动画也只不过是多幅画面的连续而已。如果我们创建出连续打多幅画面,就产生了动画。
但通常我们只创建一个 canvas 来进行整个动画,因此,当后一副画面被绘画的时候,前一副画面是需要被擦除的ctx.clearRect()
。所以我们需要一些对象imgObj
来记录当前画面中一些元素的位置。
所以整的来讲就是
- 擦干净画布 ctx.clearRect()
- 计算当前绘画元素imgObj的位置
- 将元素imgObj画在画布上
- 回到步骤1
1 | let loop = () => { |
使用 requestAnimationFrame 而非 setTimeout 以获得更好的性能。
创建粒子
我们需要一个坐标来表示粒子被画在画布的哪个位置,同时动态的粒子,还需要一个表示其运动的速度。
1 | let particle = { |
这样一个粒子的运动信息就可以被记录下来了。
以上的单个粒子还可以加上例如颜色,半径大小等更多的信息。
初始化一组粒子信息
1 | let particleArr = []; |
绘制粒子
循环调用 canvas API 即可。
粒子更新
如果在绘制粒子前不做更新,那我们每次看到的都是同一幅画面,那整个动画就是静止的。
在这一步,之前创建粒子时保存下来的粒子位置以及速度就用上了。
我们可以简单地通过记录的速度来确定当前粒子应该在的位置。
1 | let calcParticle = (particle) => { |
这样就能使整个画面动起来。
但是如果仅仅这样,在不一会儿之后,我们的画布上就不存在粒子了,因为所有粒子沿着初始化的方向不停运动而“逃”到了画布之外。因此,我们在计算的时候再简单地加上一个碰撞检测 (当粒子半径足够小,运动速度不大的时候) ,当判断粒子位置超出画布的时候将速度反向。
1 | let calcParticle = (particle) => { |
X轴与Y轴各司其职。
绘制网线
逐个判断粒子间的距离,再通过最大距离计算网线的透明度。然后 ctx.lineTo()
两个粒子的中心即可。
END
粒子过多的时候回明显卡顿,而速度过大的时候会感觉动画似乎并不连贯。