Author 王平安
E-mail pingan8787@qq.com
博 客 www.pingan8787.com
微 信 pingan8787
每日文章 https://0x9.me/KMrv3

参考文章

单条曲线

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
<!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>12-酷炫Wave动画</title>
<style>
body,
html {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}

canvas {
width: 100%;
height: 100%;
background: #333;
}
</style>
</head>

<body>
</body>
<script>
// 参考文章 https://w3ctrain.com/2018/06/26/wave-step-by-step/#more
const canvas = document.createElement('canvas');
document.body.appendChild(canvas);

const ctx = canvas.getContext('2d');

const width = canvas.width = canvas.offsetWidth;
const height = canvas.height = canvas.offsetHeight;

let xMove = 0;
let xSpeed = -.04

const run = () => {
requestAnimationFrame(run);
ctx.clearRect(0, 0, width, height);
ctx.beginPath();

// 添加样式
const grap = ctx.createLinearGradient(0, 0, width, 0);
grap.addColorStop(0, '#6e45e2');
grap.addColorStop(1, '#88d3ce');

ctx.strokeStyle = grap;
ctx.lineWidth = 1;
ctx.moveTo(0, height * .5);

xMove += xSpeed;

for (let x = 0; x < width; x++) {
// 调整振幅和放大坐标
const scale = (Math.sin(x / width * Math.PI * 2 - Math.PI * .5) + 1) * .5;
const y = Math.sin(x * .02 + xMove) * 50 * scale + height / 2;
ctx.lineTo(x, y);
}
ctx.stroke();
ctx.closePath();
}

run();
</script>

</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
<!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>12-酷炫Wave动画</title>
<style>
body,
html {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}

canvas {
width: 100%;
height: 100%;
background: #333;
}
</style>
</head>

<body>
</body>
<script>
// 参考文章 https://w3ctrain.com/2018/06/26/wave-step-by-step/#more
function valueMapping(x, inMin, inMax, outMin, outMax) {
return (x - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
}

const canvas = {
init() {
this.ele = document.createElement('canvas')
document.body.appendChild(this.ele)
this.resize()
window.addEventListener('resize', () => this.resize(), false)
this.ctx = this.ele.getContext('2d')
return this.ctx
},
onResize(callback) {
this.resizeCallback = callback
},
resize() {
this.width = this.ele.width = this.ele.offsetWidth
this.height = this.ele.height = this.ele.offsetHeight
this.resizeCallback && this.resizeCallback()
},
run(callback) {
requestAnimationFrame(() => {
this.run(callback)
})
callback(this.ctx)
}
}

const ctx = canvas.init()

class Wave {
constructor(cavans, options) {
this.canvas = canvas
this.options = options
this.xMove = this.options.offset
this.xSpeed = this.options.xSpeed
this.resize()
}
resize() {
this.width = canvas.width
this.height = canvas.height
this.amplitude = this.canvas.height * this.options.amplitude
}

draw(ctx) {
ctx.beginPath()
this.xMove += this.xSpeed
ctx.moveTo(0, this.height / 2)
var grad = ctx.createLinearGradient(0, 0, this.width, 0);
grad.addColorStop(0, this.options.start);
grad.addColorStop(1, this.options.stop);
ctx.strokeStyle = grad
ctx.lineWidth = this.options.lineWidth
for (let x = 0; x < this.width; x++) {
const radians = x / this.width * Math.PI * 2
const scale = (Math.sin(radians - Math.PI * 0.5) + 1) * 0.5
const y = Math.sin(x * 0.02 + this.xMove) * this.amplitude * scale + this.height / 2
ctx.lineTo(x, y)
}
ctx.stroke()
ctx.closePath()
}
}

const gradients = [
['#6e45e2', '#88d3ce'],
['#de6262', '#ffb88c'],
['#64b3f4', '#c2e59c'],
['#0fd850', '#f9f047'],
['#007adf', '#00ecbc'],
['#B6CEE8', '#F578DC'],
['#9be15d', '#00e3ae']
]

let waves = []

const init = () => {
waves = []
for (let i = 0; i < 5; i++) {
const [start, stop] = gradients[Math.floor(Math.random() * gradients.length)]
waves.push(new Wave(canvas, {
start,
stop,
lineWidth: 1,
xSpeed: valueMapping(Math.random(), 0, 1, -0.05, -0.08),
amplitude: valueMapping(Math.random(), 0, 1, 0.05, 0.5),
offset: Math.random() * 100
}))
}
}

document.addEventListener('click', () => {
init()
})

init()

canvas.run(ctx => {
ctx.clearRect(0, 0, canvas.width, canvas.height)
waves.forEach(wave => {
wave.draw(ctx)
})
})

canvas.onResize(() => {
init()
})
</script>

</html>