持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第 10 天,点击查看活动详情
前言
大家好,我是爱吃鱼的桶哥Z,在动画效果这方面来看,css
还是比 canvas
要略逊一筹,刚好今天又学到了一个闪瞎眼的效果,分享给大家一起学习一下。老规矩,先来看一下最终实现的效果,如图:
不得不说的是,这个效果真的很解压。虽然一眼看上去完全不知道头绪,但实际开发这个效果很简单,下面就跟着我一起来学习如何开发这么一款炫酷的旋转半圆效果吧!
一个旋转的半圆
首先我们先分析一下这个效果,在上图中可以看到总共是 24个 半圆在旋转,其中内层有8个,外层是双层的 8个 圆,因此总共有 24个 旋转的半圆。那么我们还如何实现这个效果呢?
还记得我们前面文章中做画多个图像时怎么做的吗?我们都是先画出一个图形,然后通过循环的方式就可以实现多个图形了,这里也一样,我们可以先画出一个旋转的半圆,然后再通过循环来创建多个旋转的半圆。
因为是使用的 canvas 绘制,因此还需要相关的 html 和 css 代码,这里不做过多的赘述,可以查看前面的文章,里面都有相关的代码,也可以在文末查看完整的代码。这里我们还是采用 ES6 + TS
的写法来开发这个效果,至于为什么要使用 ES6 + TS
,在前面的文章中也都介绍过,有兴趣的童鞋可以去看一下。
下面我们就先来实现一个旋转的半圆。首先我们还是先定义一个 RotateSemicircle
类,并添加相关的 constructor
函数,代码如下:
class RotateSemicircle {
canvas: HTMLCanvasElement;
ctx: CanvasRenderingContext2D;
size: number;
deg: number;
constructor() {
this.canvas = document.getElementById('canvas') as HTMLCanvasElement;
this.ctx = this.canvas.getContext('2d');
this.size = 800;
this.canvas.width = this.size;
this.canvas.height = this.size;
this.deg = 0;
}
}
初始的 constructor
函数内定义的都是我们需要的数据,内容比较简单。接下来我们就需要绘制出一个旋转的半圆,主要使用到 ctx.arc()
方法,一起来看一下代码,如下:
class RotateSemicircle {
constructor() {
...other code
this.draw()
}
draw() {
this.ctx.clearRect(0, 0, this.size, this.size);
this.ctx.beginPath();
this.ctx.arc(this.size / 2, this.size / 2, this.size / 2, this.deg / 4 * Math.PI, Math.PI + this.deg / 4 * Math.PI, false);
this.ctx.strokeStyle = `hsl(${this.deg * 50}deg, 80%, 50%)`;
this.ctx.lineWidth = 3;
this.ctx.stroke();
this.deg += 0.04;
}
animate() {
requestAnimationFrame(() => this.animate());
this.draw();
}
}
在 RotateSemicircle
类中添加一个 draw
方法,其中主要用到 ctx.arc()
方法来绘制圆,它有 6个 参数,分别是:绘制圆心的x轴坐标、绘制圆心的y轴坐标、绘制圆的半径、绘制圆的开始角度、绘制圆的结束角度以及最后一个可选参数,如果为 true
,则逆时针绘制圆弧,反之,则顺时针绘制。
有了这6个参数后,我们只需要设置到对应的数值,并不断的更新 this.deg
的值,这样就能让这个半圆旋转起来了,当然不要忘了通过 new
关键词来实例化 RotateSemicircle
类。
通过上述代码,我们可以得到如下的效果,一起来看图:
可以看到绘制出来的这个半圆一直在旋转,并且在旋转的过程中不断的变换颜色,因为我们在 draw 方法中添加了 this.ctx.strokeStyle = hsl(${this.deg * 50}deg, 80%, 50%)
这行代码,因此这个半圆在旋转的过程中就会不断的根据当前的 thid.deg
的值进行变换。
我们已经绘制出了一个圆,那么接下来我们就可以通过循环的方式来创建多个旋转的半圆了,一起来看看吧!
N个旋转的半圆
在上面我们通过 ctx.arc()
方法已经绘制出了一个旋转的半圆,那么要实现N个旋转的半圆,其实只需要通过循环来创建N个即可。在最开始已经说过我们这里外层是8个旋转的半圆,因此我们只需要循环8次即可,让我们一起来看代码,如下:
class RotateSemicircle {
...other code
draw() {
this.ctx.clearRect(0, 0, this.size, this.size);
for (let i = 0; i < 8; i++) {
const x1 = this.size / 4 * Math.cos(i / 4 * Math.PI + this.deg / 5) + this.size / 2;
const y1 = this.size / 4 * Math.sin(i / 4 * Math.PI + this.deg / 5) + this.size / 2;
this.ctx.beginPath();
this.ctx.arc(x1, y1, this.size / 4, this.deg + i / 4 * Math.PI, Math.PI + this.deg + i / 4 * Math.PI, false);
this.ctx.strokeStyle = `hsl(${this.deg * 50}deg, 80%, 50%)`;
this.ctx.lineWidth = 3;
this.ctx.stroke();
}
}
...other code
}
我们修改 RotateSemicircle
类中的 draw
方法,在前面我们只创建一个半圆时,只需要执行一次 ctx.arc()
即可,而这里我们要实现的效果是 8个 旋转的半圆,因此循环8次即可。计算的圆心坐标可以随意的更改数值,这里也可以参考上述的代码,最终实现的效果如下所示:
可以看到通过循环8次后,创建了8个旋转的半圆,组合起来的效果还不错。但是还不够精彩,因此我们可以继续添加更多的旋转半圆,让整个 canvas
画面看起来更加的炫酷,修改 draw
方法即可,代码如下:
class RotateSemicircle {
...other code
draw() {
this.ctx.clearRect(0, 0, this.size, this.size);
for (let i = 0; i < 8; i++) {
...other code
const x2 = this.size / 4 * Math.cos(i / 4 * Math.PI + 0.5 - this.deg / 5) + this.size / 2;
const y2 = this.size / 4 * Math.sin(i / 4 * Math.PI + 0.5 - this.deg / 5) + this.size / 2;
this.ctx.beginPath();
this.ctx.arc(x2, y2, this.size / 5, this.deg + i / 4 * Math.PI, Math.PI + this.deg + i / 4 * Math.PI, false);
this.ctx.strokeStyle = `hsl(${this.deg * 100}deg, 80%, 50%)`;
this.ctx.lineWidth = 2;
this.ctx.stroke();
}
}
...other code
}
还是在这个循环中,我们通过三角函数相关的知识,计算出新的圆心坐标点,这样就可以让外层的8个半圆与另外的8个半圆相叠加,最终实现的效果如下:
怎么样,是不是比上面看起来更加的精彩呢?我们还可以给这些旋转的半圆添加上"拖尾"的效果,修改的代码也很简单,如下:
class RotateSemicircle {
...other code
draw() {
this.ctx.fillStyle = `rgba(0,0,0,0.1)`;
this.ctx.fillRect(0, 0, this.size, this.size);
}
...other code
}
只需要将 ctx.clearRect()
方法替换为 ctx.fillRect()
即可,这样就能实现一个渐变的效果了,如下图所示:
你以为到这里就结束了吗?我觉得这个效果还不是特别的完美,因此我又加了最后一层,各位童鞋也可以根据自己的喜好来随意更改代码,我最后添加的代码如下:
class RotateSemicircle {
...other code
draw() {
this.ctx.clearRect(0, 0, this.size, this.size);
for (let i = 0; i < 8; i++) {
...other code
const x3 = this.size / 4 * Math.cos(i / 4 * Math.PI + 0.5 - this.deg / 5) + this.size / 2;
const y3 = this.size / 4 * Math.sin(i / 4 * Math.PI + 0.5 - this.deg / 5) + this.size / 2;
this.ctx.beginPath();
this.ctx.arc(x3, y3, this.size / 6, this.deg + i / 4 * Math.PI, Math.PI + this.deg + i / 4 * Math.PI, false);
this.ctx.strokeStyle = `hsl(${this.deg * 150}deg, 70%, 90%)`;
this.ctx.lineWidth = 1;
this.ctx.stroke();
}
}
...other code
}
可以看到最后添加的一层只是在第一层的基础上修改了一些数据,童鞋们也可以参考我这个方法,自己在这个效果上进行修改,最终实现的完整效果与代码可以在这里进行查看:
总结
总的来说,有时候只需要通过很简单的 API 即可完成非常炫酷的效果,主要还是计算的方法需要多多的了解和学习,这样才能创作出更多天马行空的效果,关于这个旋转的半圆,你学会了吗?
最后,如果这篇文章有帮助到你,❤️关注+点赞❤️鼓励一下作者,谢谢大家