废话不多说,先看效果
视频效果
动手体验
实现此功能一共有两个小点需要考虑
- 如何将中文转为点阵
- 如何实现粒子效果
如何将中文转为点阵
粒子效果需要每一个字符都是由点组成的,我们都知道,英文转为点阵或者数组很容易,只有26个字母要区分大小写也不过52个,写一个映射表即可比如A可以写成
但是汉字千千万,穷举当然是不现实的,所以需要另辟蹊径。
正好canvas提供了getImageData
方法,此方法返回 ImageData 对象,该对象拷贝了画布指定矩形的像素数据
对于 ImageData 对象中的每个像素,都存在着四方面的信息,即 RGBA 值:
- R - 红色 (0-255)
- G - 绿色 (0-255)
- B - 蓝色 (0-255)
- A - alpha 通道 (0-255; 0 是透明的,255 是完全可见的)
所以我们可以将画布设置为白色rgb(255,255,255)
,文字设置为红色rgb(255,0,0)
,将imageData以画布宽高为限制,4为间隔进行遍历,如果
imgData.data[i] === 255 && imgData.data[i + 1] === 0 && imgData.data[i + 2] === 0 && imgData.data[i + 3] === 255
就将该点xy坐标存起来。
let dotList = []
dotList.push(new Dot(x,y))
基于画布宽高遍历,300*150的画布就有45000个点。由于我们做的是粒子效果,不需要那么多的点,所以需要设置一个gap。进行跳跃取点。
let dotList = [];
for (let x = 0; x < imgData.width; x += +this.gap) {
for (let y = 0; y < imgData.height; y += +this.gap) {
let i = (y * imgData.width + x) * 4;
// 判断像素点是不是红色
if (
imgData.data[i] === 255 &&
imgData.data[i + 1] === 0 &&
imgData.data[i + 2] === 0 &&
imgData.data[i + 3] === 255
) {
dotList.push({x,y});
}
}
}
这样就取得了所有需要用到的点坐标了,将坐标数组转为阵的方式也很简单,就是创建一个二维数组,长度是画布的高,每一项长度是画布的宽。然后根据xy的值向数组对应位置插入就好,不再赘述。
如何实现粒子效果
有了点数组,已经可以向画布渲染出文字了,为了美观可以再给加点入场动效。这就是纯canvas动画的方面了,我写了一个很简单从四处飞进来的动效。
实现原理是针对每个点,先基于当前xy随机加上一个正负1000以内的数字,作为初始点。结束点就是原本的xy啦。动画部署设定为120帧。然后根据差值算出每一帧需要移动多少距离。在requestAnimationFrame
中循环步数加一即可
class MoveArc{
constructor(position,context2,duration=120) {
this.position = position;
this.context2 = context2;
this.randomX = Math.random()*1000;
this.randomY = Math.random()*1000;
this.startX = this.position.x + this.randomX;
this.startY = this.position.y + this.randomY;
this.duration = duration;
this.gapX = this.randomX/this.duration
this.gapY = this.randomY/this.duration
this.step = 0;
}
draw(){
this.context2.beginPath();
this.context2.arc(this.startX - this.gapX * this.step, this.startY - this.gapY * this.step, 2, 0,2*Math.PI)
this.context2.fill();
this.context2.closePath();
if(this.step !== this.duration){
this.step++
}
}
}
至此所有功能已经实现啦。
拓展设想
1.获取的数组点阵,可以通过svg方式渲染,这样就可以得到任何一个中文字符的矢量图形了,不仅可以用来做无损渲染方面的东西,也可以作出更多炫酷的动效,比如实现按笔划手写的效果。
2.由于本人比较懒,没有对代码进行优化🐶。都是最土最暴力的写法,已知如果将间隔设置为1,动画会稍稍有些卡顿。我大致想了一下有两个思路尝试解决,一是上算法减少复杂度,二是用WebWorker。
代码地址,大佬拍砖
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。