<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HTML5 Canvas水波纹特效</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #000;
overflow: hidden;
font-family: Arial, sans-serif;
}
canvas {
display: block;
position: fixed;
top: 0;
left: 0;
z-index: 1;
}
.title {
position: fixed;
top: 20px;
color: rgba(255, 255, 255, 0.8);
font-size: 28px;
text-align: center;
z-index: 2;
text-shadow: 0 0 10px rgba(0, 150, 255, 0.7);
}
.instructions {
position: fixed;
bottom: 60px;
color: rgba(255, 255, 255, 0.6);
font-size: 16px;
text-align: center;
z-index: 2;
}
.credit {
position: fixed;
bottom: 20px;
color: rgba(255, 255, 255, 0.5);
font-size: 14px;
z-index: 2;
}
.credit a {
color: rgba(100, 200, 255, 0.8);
text-decoration: none;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<div class="title">HTML5 Canvas水波纹特效</div>
<div class="instructions">点击或拖动鼠标创建水波纹</div>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// 设置canvas大小为窗口大小
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// 波纹数组
const ripples = [];
const maxRipples = 20;
// 波纹类
class Ripple {
constructor(x, y) {
this.x = x;
this.y = y;
this.radius = 5;
this.maxRadius = Math.random() * 100 + 100;
this.speed = Math.random() * 2 + 1;
this.opacity = 1;
this.color = `rgba(${Math.floor(Math.random() * 100 + 155)},
${Math.floor(Math.random() * 100 + 155)},
255, ${this.opacity})`;
}
update() {
this.radius += this.speed;
this.opacity -= 0.01;
this.color = `rgba(${Math.floor(Math.random() * 100 + 155)},
${Math.floor(Math.random() * 100 + 155)},
255, ${this.opacity})`;
return this.radius < this.maxRadius && this.opacity > 0;
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.strokeStyle = this.color;
ctx.lineWidth = 2;
ctx.stroke();
// 添加内部渐变填充
const gradient = ctx.createRadialGradient(
this.x, this.y, this.radius * 0.3,
this.x, this.y, this.radius
);
gradient.addColorStop(0, `rgba(100, 200, 255, ${this.opacity * 0.3})`);
gradient.addColorStop(1, `rgba(0, 50, 150, ${this.opacity * 0.1})`);
ctx.fillStyle = gradient;
ctx.fill();
}
}
// 鼠标交互
canvas.addEventListener('mousedown', createRipple);
canvas.addEventListener('mousemove', (e) => {
if (e.buttons === 1) { // 检查鼠标左键是否按下
createRipple(e);
}
});
// 触摸屏支持
canvas.addEventListener('touchstart', (e) => {
e.preventDefault();
createRipple(e.touches[0]);
});
canvas.addEventListener('touchmove', (e) => {
e.preventDefault();
createRipple(e.touches[0]);
});
function createRipple(e) {
if (ripples.length < maxRipples) {
ripples.push(new Ripple(e.clientX, e.clientY));
}
}
// 自动生成波纹
function autoGenerateRipple() {
if (Math.random() < 0.03 && ripples.length < maxRipples / 2) {
const x = Math.random() * canvas.width;
const y = Math.random() * canvas.height;
ripples.push(new Ripple(x, y));
}
setTimeout(autoGenerateRipple, 500);
}
// 动画循环
function animate() {
// 半透明背景制造拖尾效果
ctx.fillStyle = 'rgba(0, 0, 10, 0.05)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 更新和绘制所有波纹
for (let i = ripples.length - 1; i >= 0; i--) {
if (!ripples[i].update()) {
ripples.splice(i, 1);
} else {
ripples[i].draw();
}
}
requestAnimationFrame(animate);
}
// 窗口大小改变时重置canvas大小
window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
});
// 启动动画和自动生成波纹
animate();
autoGenerateRipple();
</script>
</body>
</html>