又用 canvas 实现了一个旋转的伪3D球体,来瞧瞧?
前言
在前面一篇文章中,我们通过 canvas
实现了一个多彩的圆环数字时钟,刚好最近又学到了一个关于 canvas
粒子的伪3D效果,今天就分享给大家。老规矩,我们还是先来看一下最终实现的效果,如下图所示:
通过上图可以看到,在初始化的时候会生成很多粒子,这些粒子会按照一定的轨迹形成一个椭圆,最后围着这个椭圆旋转,从而实现我们看到的伪3D效果。
那这个效果是如何实现的呢?接下来我们就一起来看一下吧!
旋转的圆
首先我们先来实现中间的一个圆,只要找到中件的居中线,再向上下方向扩展,就能实现这个伪3D效果了。
基础的 html
和 css
代码这里就不在列出来了,如果还有不了解的童鞋,可以查看前面的文章,里面都有相关的代码。这里我们依旧采用 TS + ES6
的语法来开发这个效果,首先我们还是需要先定义一个 Sphere
类,并且完成初始的 constructor
函数,让我们一起来看一下代码,如下:
class Sphere {
canvas: HTMLCanvasElement;
ctx: CanvasRenderingContext2D;
particles: Particle[];
radius: number;
constructor() {
this.canvas = document.getElementById('canvas') as HTMLCanvasElement;
this.ctx = this.canvas.getContext('2d');
this.canvas.width = innerWidth;
this.canvas.height = innerHeight;
this.particles = [];
this.radius = 280;
}
}
初始化的 constructor
函数准备好后,我们还需要创建一个 Particle
类,它主要用于生成粒子,让我们一起来看一下 Particle
类的相关代码,如下:
class Particle {
x: number;
y: number;
r: number;
d: number;
op: number;
vx: number;
vy: number;
ctx: CanvasRenderingContext2D;
constructor(d: number, x: number, y: number, r: number, canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D) {
// d: 椭圆的角度
// x, y: 圆心
// r: 半径
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.r = r;
this.d = d;
this.op = 1;
// 椭圆圆心坐标
this.vx = x;
this.vy = y;
this.ctx = ctx;
}
update() {
// 弧度
this.d += Math.PI / 360;
// 完整的弧度值是 Math.PI * 2,相当于每次旋转圆周的 1/720
this.x += (this.vx - this.x) / 30;
this.y += (this.vy - this.y) / 30;
}
draw() {
let x = this.r * Math.cos(this.d) + this.x;
let y = this.r / 4 * Math.sin(this.d) + this.y;
this.ctx.beginPath();
this.ctx.arc(x, y, 2, 0, Math.PI * 2);
this.ctx.fillStyle = `rgba(0, 0, 0, ${this.op})`;
this.ctx.fill();
}
}
在 Particle
类中,我们需要从外部传入6个参数,其中前面四个分别是要生成的椭圆的角度、圆心的x坐标和y坐标,以及要生成的椭圆的半径,后面两个参数则是 canvas
和 ctx
对象,通过设置不同的x坐标和y坐标,就能创建不同位置的粒子效果。
有了 Particle
类后,我们需要在 Sphere
类中调用它,并生成一个选择的圆,让我们一起来看一下 Sphere
代码的改造,如下:
class Sphere {
...other code
constructor() {
...other code
this.init();
this.animate();
}
init() {
// 一次生成36个粒子,等角度排列
for (let j = 0; j < Math.PI * 2; j += Math.PI / 18) {
this.particles.push(new Particle(j, this.canvas.width / 2, this.canvas.height / 2, this.radius, this.canvas, this.ctx));
}
}
draw() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
for (const n in this.particles) {
const p = this.particles[n];
p.update();
p.draw();
}
}
animate() {
requestAnimationFrame(() => this.animate());
this.draw();
}
}
new Sphere();
在 Sphere
类中,我们添加一个 init
方法,并格式化要生成粒子的数据,然后添加一个 draw
方法,用于将前面准备的数据转化为页面中的粒子效果,最后不要忘了通过 new
关键词来实例化 Sphere
。
通过上述修改的代码,最终我们可以得到一个旋转的圆环,如下图所示:
我们已经实现了一个圆环的旋转,那么要实现最初的那个伪3D的效果,该如何做呢?
伪3D旋转球体
在前面我们说过,要实现完整的旋转球体,就要找到中间的旋转线,然后再分别向上和向下扩展对应的圆环即可实现这个伪3D的旋转效果了。
让我们一起来修改一下 Sphere
类,只需要再添加一个新的循环,即可获取到更多的点,相关的修改代码如下:
class Sphere {
...other code
init() {
for (let i = 0; i < 5; i++) {
const x = this.radius * Math.cos(-Math.PI / 10 * i);
const y = this.radius * Math.sin(-Math.PI / 10 * i);
// 一次生成36个粒子,等角度排列
for (let j = 0; j < Math.PI * 2; j += Math.PI / 18) {
this.particles.push(new Particle(j, this.canvas.width / 2, this.canvas.height / 2 + y, Math.abs(x), this.canvas, this.ctx));
}
}
}
...other code
}
通过上述代码可以看到,我们只是在 init
方法中添加了一层新的循环,并且根据三角函数相关的计算原理,得到了新的圆环的生成点,最终实现的效果如下图所示:
可以看到当我们在外面又添加了一层循环后,生成了5个旋转的圆环,接下来只需要再向下添加对应的圆环即可,修改 init
方法,代码如下:
class Sphere {
...other code
init() {
for (let i = 0; i < 5; i++) {
const x = this.radius * Math.cos(-Math.PI / 10 * i);
const y = this.radius * Math.sin(-Math.PI / 10 * i);
// 一次生成36个粒子,等角度排列
for (let j = 0; j < Math.PI * 2; j += Math.PI / 18) {
this.particles.push(new Particle(j, this.canvas.width / 2, this.canvas.height / 2 + y, Math.abs(x), this.canvas, this.ctx));
this.particles.push(new Particle(j, this.canvas.width / 2, this.canvas.height / 2, this.radius, this.canvas, this.ctx));
if (i !== 0) {
this.particles.push(new Particle(j, this.canvas.width / 2, this.canvas.height / 2 - y, Math.abs(x), this.canvas, this.ctx));
}
}
}
}
...other code
}
可以看到在第二层的循环中,通过传入 Particle 类中不同的参数,从而生成两个方向的旋转圆环,最后我们再修改一下 Sphere 类中的 draw 方法,让整个旋转的3D圆环有一个拖尾的效果,相信大家对这块的内容已经很熟悉了,一起来看一下修改后代码,如下:
class Sphere {
...other code
draw() {
this.ctx.fillStyle = `rgba(255, 255, 255, 0.3)`;
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
...other code
}
}
修改后的旋转球体就会带上拖尾的效果,最终的完整代码及实现效果可以在这里进行查看:
总结
总的来说,只要掌握了 canvas
中粒子效果的生成以及三角函数的相关玩法,那么就可以实现更多更有趣的效果。
最后,如果这篇文章有帮助到你,❤️关注+点赞❤️鼓励一下作者,谢谢大家
往期回顾
不得不说,这个 canvas 的旋转半圆效果可能会闪瞎你的双眼🐶
转载自:https://juejin.cn/post/7158018321022418975