花里胡哨的Canvas动画作用
我正在参加「启航方案」
作者的话
最近五一放假,原本方案在家好好科研的,可是的确不是科研的料,就不想科研,然后为了打发时刻做了点前端小Demo,然后看见有码上的竞赛,就选了赛题一方案着手做一个美观的动画作用,花了半天的时刻完结了 。
五一总结,假日的确高产,可能也是由于找到暑期实习了吧,然后也想着放松放松,假日回去后就要开始好好把科研推进一下了,然后就趁假日写了三篇博客(由于找实习找了一个多月,良久没写博客了 ):
- 「启航方案」仿网易云主页获取图片的主题色
- 「启航方案」花了一天完结的简略又风趣的马赛克小工具
- 2024届前端暑期实习总结
作用展示
假如我们看了作用比较喜爱,那作者还有个不情之请,假如喜爱能不能帮助给我的著作点点赞或许点点保藏或许阅读一下,下面附上链接:码上,在玩转动画板块中哦
功用介绍
-
【功用1】:本动画主要运用Canvas完结,动画作用为粒子在页面上首要呈现为乱序的作用,接着在相一起刻内,一切的粒子都运动到指定的方位上,终究拼成方针文字,假如有多行文字,会在指定时刻间隔下相继展示出来。
-
【功用2】:本动画作用能够自适应横屏和竖屏,也便是在PC端阅读该作用文字是横向摆放,假如是在移动端阅读该作用文字是纵向摆放。
-
【功用3】:自适应文字大小,假如设置的文字太大超出屏幕,该作用会自动调整字体至最大占满页面的大小。
完结思路
这儿大致说一下完结的思路吧,由于具体说明比较复杂,就简略介绍一下:
-
正如我们看到的作用相同(能够看封面动图,或许在代码中运转都可),这个动画由许多的点运动组成,因而需求界说一个点类,来操控每一步点的运动轨迹;
-
接着便是如何确认每个点的终究方位,那就需求先把文字写在自己的(不是终究显现的Canvas,自己能够额外创建一个)Canvas上,然后获取当时Canvas的像素信息,判别是否不为透明的像素,然后记载该像素的坐标和色彩;
-
然后操控每个点由随机方位在相一起刻内一起运动到指定的方位上,其实也便是把每一帧的图画出来,鄙人一帧的时候清空画布,再把当时帧的方位画出来,这样就能有一个动画的形式,那么操控画图的函数能够运用
setInterval
或许requestAnimationFrame
,这个看自己的挑选吧
总结一下:其实很简略,便是获得方针文字在Canvas上的坐标和色彩,然后把每个点运动到正确的方位上即可。
界说每个点的类
这个类主要操控点的制作和更新功用,由于每个点需求在每一帧更新当时的坐标,然后制作出来。
由于之前也说过要制作每个点点方位,因而需求知道如下几个参数:
- 开始坐标的X和Y
- 完毕坐标的X和Y
- 每个点在X和Y方向上的移动速度
- 每个点的色彩和半径
下面展示一下具体的类的结构:
class Dot {
constructor(config) {
const { x, y, duration, color, radius } = config
// ...
// 点的色彩
this.color = color;
// 点的半径
this.radius = radius;
// 点的X开始方位
this.startX = Math.random() * width;
// 点的Y开始方位
this.startY = Math.random() * height;
// 点的X结尾方位
this.endX = x;
// 点的Y结尾方位
this.endY = y;
// 每帧动画中点的X方向的速度
this.speedX = (this.endX - this.startX) / duration / 60;
// 每帧动画中点的Y方向的速度
this.speedY = (this.endY - this.startY) / duration / 60;
}
// 画出点的方位
draw() {
// ...
}
// 更新点的方位
updated(flag) {
// ...
}
}
Draw
函数比较简略,便是简略的Canvas画图操作,这儿不再细说,具体代码能够在代码片段里检查;然后便是update
函数,其实只要每次将当时点的X和Y坐标增加在该方向上的移动速度即可,这儿需求留意的是由于计算机存储的原因,可能不能彻底增加到彻底持平,因而需求进行判别,作者这儿就进行了简略的判别:
if (Math.abs(end - start) < Number.EPSILON) {
// ...
}
这儿计算终究方位
end
与当时方位start
的差值,假如小于一个比较小的数字(Number.EPSILON),就认为抵达终究方位了。
科普时刻
这儿插一句,介绍一下Number.EPSILON
,它是 JavaScript 中一个常量,表示浮点数的计算精度。它的值是 2 的负 52 次方,即 2^-52,约等于 0.0000000000000002220446049250313。
在进行浮点数比较时,能够运用 Number.EPSILON
这个极小值来判别两个数是否持平。例如:
function isEqual(a, b) {
return Math.abs(a - b) < Number.EPSILON;
}
console.log(isEqual(0.1 + 0.2, 0.3)); // true
这儿运用 Math.abs()
函数来获取两个数之间的绝对值,然后与 Number.EPSILON
进行比较,假如小于 Number.EPSILON
就认为两个数持平。这是由于在进行浮点数计算时,由于计算精度的限制,可能会出现一些微小的差错,运用 Number.EPSILON
能够消除这种差错的影响。
画图的类
这个类说起来比较费事,这儿就介绍一下大约的履行流程吧,假如想要源码,能够去看代码片段。
履行流程:
flowchart TD
init -->|初始化画布| F
G -->|改动|H
F --> |"有使命 [1]"|M
F --> L
D --> |完结当时使命|N(pop)
subgraph init
H(初始化画布参数)-->I(设置文本渐变)-->J(设置font size)-->K[是否超过画布]
K --> |"是 [2]"|J
K -->|否|L(Canvas制作文本)
end
subgraph run
F[isRunning] --> |无使命|G[文本是否改动]--> |不改动|B(getTextCoordinates) -->|坐标和色彩| C(draw) --> |画出每个点|D(move)
end
subgraph taskQueue
M(push)-->|压入使命|E("task=[]")
N-->|弹出使命|G
end
[1] 这儿运用的是队列的思想,一起也学习了Vue2的异步更新战略
[2] 这儿是调整字体的font size直到最大可能的占满页面,搜索时运用的是二分查找的思想,使得时刻复杂度降至 log2Nlog_2N
自适应屏幕
也便是完结了功用2,能够自适应横屏和竖屏,其实判别横竖屏不难,这个功用比较难的地方是怎么把文字竖着显现,然后获取到转化后的坐标。其实有想过运用ctx.rotate(90deg)
然后再把转化后的坐标的横坐标X再加上Canvas的height
就能够得到竖屏时的坐标。
假如我们有什么更好的主意能够评论区留言,让我学习一下
因而,作者想直接运用公式完结rotate(-90deg)
和translateX(canvas.height)
这两个过程,然后想起了CSS中的matrix
,因而那就用线性代数的矩阵变换来完结。
现在回想一下学过的线性代数,rotate(-90deg)
的变换矩阵如下:
其间xx和yy是每个点的横纵坐标,同理能够得到rotate(-90deg) translateX(canvas.height)
的变换矩阵为:
width为竖屏时的页面宽度
公式推导
假如不想看能够跳过
transform: rotate(-90deg)的推导
至于为什么rotate(-90deg)
的变换矩阵为:
下面进行一下数学公式的简略推导,如下是二维的笛卡尔坐标系,在榜首象限中有原来的点(x,y)(x,y),在第二象限有逆时针旋转变换后的坐标(x′,y′)(x’,y’),在榜首象限与y的正方向的夹角为\alpha,在第二象限与y的正方向的夹角为\beta,且满足+=\alpha+\beta=\theta,具体参数如下图所示:
那么依据简略的三角函数性质能够得到如下等式:
依据+=\alpha+\beta=\theta,能够得到如下等式:
利用三角函数公式将上述等式展开,能够得到:
将上述公式进行化简能够得到:
那么依据上述的公式,能够得到逆时针旋转\theta角度的矩阵计算公式:
因而,rotate(-90deg)
的变换矩阵能够把=90\theta=90\degree 代入能够得到:
这儿为什么把9090\degree带入而不是把−90-90\degree代入,这是由于推导的时候现已默许\theta是正值,然后公式现已默许推导的是逆时针旋转的公式,因而只需求代入9090\degree即可。
transform: translateX(canvas.height)的推导
同理,能够得到translateX(canvas.height)
的变换矩阵如下:
这儿变成width是由于先在横屏中写文字,因而横屏Canvas的height就等于变换后竖屏的width。
transform: rotate(-90deg) translateX(canvas.height)的推导
依据上面的推导我们现已得到了rotate(-90deg)
和translateX(canvas.height)
的变换矩阵,因而transform: rotate(-90deg) translateX(canvas.height)
就等于rotate(-90deg)
的变换矩阵乘translateX(canvas.height)
的变换矩阵,那么:
写在最终
我们有什么问题或许主张能够评论区讨论一下,假如喜爱的话也能够点赞➕保藏 ,感谢我们的支撑。
最终,再求一波点赞或许保藏,给作者的【花里胡哨的散点动画】点个小星星 吧!