-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcanvas文字粒子效果.html
146 lines (139 loc) · 4.34 KB
/
canvas文字粒子效果.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>canvas文字粒子效果</title>
<style>
#canvas {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div>
<canvas id="canvas"></canvas>
</div>
<script>
let WIDTH, HEIGHT, cxt, raf, points
window.onload = () => {
WIDTH = document.body.clientWidth
HEIGHT = document.body.clientHeight
console.log(WIDTH, HEIGHT)
const canvas = document.getElementById('canvas') //主画布
canvas.width = WIDTH
canvas.height = HEIGHT
ctx = canvas.getContext('2d')
points = createViceCanvas() // 创建副画布,写出想展示的文字,并且获取文字的位置信息。
init()
}
function createViceCanvas() {
const viceCanvas = document.createElement('canvas')
viceCanvas.width = WIDTH
viceCanvas.height = HEIGHT
let viceCxt = viceCanvas.getContext('2d')
initCanvas(viceCxt)
return getFontInfo(viceCxt) // 获取文字粒子的位置信息
}
function initCanvas(ctx) {
//ctx 是副画布
const font = '汤圆最帅!'
ctx.font = '200px Arial'
const measure = ctx.measureText(font)
ctx.fillText(font, (WIDTH - measure.width) / 2, HEIGHT / 2)
}
function getFontInfo(ctx) {
//ctx是副画布,文字取点,获取每个文字在画布中的坐标。
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 fontIndex = (x + y * WIDTH) * 4 + 3
if (imageData[fontIndex] > 0) {
particles.push(
new Particle({
x,
y
})
)
}
}
}
return particles
}
class Particle {
constructor(center) {
this.x = center.x // 记录点位最终应该停留在的x轴位置
this.y = center.y // 记录点位最终应该停留在的y轴位置
this.item = 0 // 贝塞尔曲线系数
this.vx = 20 // 点位在x轴的移动速度
this.vy = 16 // 点位在y轴的移动速度
this.initX = Math.random() * WIDTH // 点位随机在画布中的x坐标
this.initY = Math.random() * HEIGHT // 点位随机在画布中的y坐标
}
draw() {
// 绘制点位
ctx.beginPath()
const { x, y } = threeBezier(
// 贝塞尔曲线,获取每一个tick点位所在位置
this.item,
[this.initX, this.initY],
[this.x, this.y],
[this.x, this.y],
[this.x, this.y]
)
ctx.arc(x, y, 2, 0, 2 * Math.PI, true)
ctx.fillStyle = 'red'
ctx.fill()
ctx.closePath()
this.speed() // 点位下次tick绘制时的坐标
}
speed() {
// 每个点位绘制后的坐标
this.initX += this.vx
this.initY += this.vy
this.item += 0.005
}
}
const threeBezier = (t, p1, p2, cp1, cp2) => {
const [startX, startY] = p1
const [endX, endY] = p2
const [cpX1, cpY1] = cp1
const [cpX2, cpY2] = cp2
let x =
startX * Math.pow(1 - t, 3) +
3 * cpX1 * t * Math.pow(1 - t, 2) +
3 * cpX2 * Math.pow(t, 2) * (1 - t) +
endX * Math.pow(t, 3)
let y =
startY * Math.pow(1 - t, 3) +
3 * cpY1 * Math.pow(1 - t, 2) * t +
3 * cpY2 * (1 - t) * Math.pow(t, 2) +
endY * Math.pow(t, 3)
return {
x,
y
}
}
// particles.push(
// new Particle({
// x,
// y
// })
// )
function init() {
ctx.clearRect(0, 0, WIDTH, HEIGHT)
points.forEach(value => {
//
value.draw()
})
raf = window.requestAnimationFrame(init)
if (points[0].item >= 1) {
window.cancelAnimationFrame(raf)
}
}
</script>
</body>
</html>