-
Notifications
You must be signed in to change notification settings - Fork 1
/
文字粒子效果.html
121 lines (121 loc) · 3.8 KB
/
文字粒子效果.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>文字粒子效果</title>
<style>
html,
body {
height: 100%;
background-color: #000;
}
#container {
height: 100%;
}
</style>
</head>
<body>
<div id="container">
<canvas id="canvas"></canvas>
</div>
<script>
// 全局配置
const options = {
width: 400,
height: 400,
speed: 10,
};
// 副画布文字配置
const textOptions = {
words: '文字粒子效果',
font: '200px fangsong',
};
// 绘制主画布
function pointCanvas(canvas, { width, height }) {
canvas.width = width;
canvas.height = height;
ctx = canvas.getContext('2d');
return ctx;
}
// 创建副画布
function createVitualCvs({ width, height }) {
const vitualCvs = document.createElement('canvas');
vitualCvs.width = width;
vitualCvs.height = height;
let vitualCtx = vitualCvs.getContext('2d');
initCanvas(vitualCtx, options, textOptions);
return getWordPxInfo(vitualCtx, options);
}
// 初始化副画布,并绘制文字
function initCanvas(ctx, { width, height }, { font, words }) {
ctx.font = font;
const measure = ctx.measureText(words);
ctx.fillText(words, (width - measure.width) / 2, height / 2);
}
// 获取文字像素信息,并生成粒子
function getWordPxInfo(ctx, { width, height, speed }) {
let imageData = ctx.getImageData(0, 0, width, height).data;
const particles = [];
for (let x = 0; x < width; x += 4) {
for (let y = 0; y < height; y += 4) {
// 判断当前像素点是否有文字
const pxAlphaIndex = (x + y * width) * 4 + 3;
if (imageData[pxAlphaIndex] > 0) {
particles.push(
new Particle({
x,
y,
speed,
})
);
}
}
}
return particles;
}
// 入口方法
function init(points, { width, height }) {
ctx.clearRect(0, 0, width, height);
points.forEach((value) => {
value.draw();
});
const timer = window.requestAnimationFrame(function () {
init(points, options);
});
}
// 粒子类
class Particle {
constructor(point) {
this.x = point.x; // 记录点位最终应该停留在的x轴位置
this.y = point.y; // 记录点位最终应该停留在的y轴位置
this.mx = Math.random() * canvas.width;
this.my = Math.random() * canvas.height;
this.radius = Math.random() * 3;
this.speed = Math.random() * 40 + point.speed;
this.color = `rgba(${Math.random() * 255}, ${Math.random() * 255}, ${Math.random() * 255},${Math.random() + 0.2})`;
}
draw() {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.arc(this.mx, this.my, this.radius, 0, Math.PI * 2, false);
ctx.fill();
this.update();
}
// 可以使用更复杂的贝塞尔曲线
update() {
this.mx = this.mx + (this.x - this.mx) / this.speed;
this.my = this.my + (this.y - this.my) / this.speed;
}
}
window.onload = () => {
options.width = document.body.clientWidth;
options.height = document.body.clientHeight;
const canvas = document.getElementById('canvas');
pointCanvas(canvas, options);
const points = createVitualCvs(options);
init(points, options);
};
</script>
</body>
</html>