
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数学粒子动画</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #000;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
overflow: hidden;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.container {
position: relative;
width: 100%;
max-width: 900px;
text-align: center;
}
canvas {
background-color: black;
border-radius: 8px;
box-shadow: 0 0 20px rgba(0, 100, 255, 0.3);
}
.title {
color: rgba(255, 255, 255, 0.85);
margin-bottom: 20px;
font-size: 2.2rem;
text-shadow: 0 0 10px rgba(0, 150, 255, 0.8);
letter-spacing: 1.5px;
}
.description {
color: rgba(200, 220, 255, 0.7);
max-width: 600px;
margin: 20px auto;
font-size: 1.1rem;
line-height: 1.6;
}
.controls {
margin: 20px 0;
}
.control-btn {
background: rgba(30, 60, 120, 0.7);
color: white;
border: none;
padding: 10px 20px;
margin: 0 10px;
border-radius: 4px;
cursor: pointer;
font-size: 1rem;
transition: all 0.3s ease;
outline: none;
}
.control-btn:hover {
background: rgba(50, 100, 200, 0.9);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0, 100, 255, 0.4);
}
.footer {
color: rgba(150, 180, 220, 0.6);
margin-top: 25px;
font-size: 0.9rem;
}
</style>
</head>
<body>
<div class="container">
<h1 class="title">数学粒子动画</h1>
<canvas id="particleCanvas" width="900" height="900"></canvas>
<div class="description">
这个动画展示了10,000个粒子按照复杂的数学公式运动。
每个粒子的位置由三角函数的组合计算得出,创造出令人着迷的视觉效果。
</div>
<div class="controls">
<button id="pauseBtn" class="control-btn">暂停</button>
<button id="resetBtn" class="control-btn">重置</button>
<button id="speedUpBtn" class="control-btn">加速</button>
<button id="slowDownBtn" class="control-btn">减速</button>
</div>
<div class="footer">
HTML5 Canvas实现 | 数学公式驱动的艺术
</div>
</div>
<script>
const canvas = document.getElementById('particleCanvas');
const ctx = canvas.getContext('2d');
const particles = [];
const numParticles = 10000;
let t = 0;
let animationSpeed = 1;
let isPaused = false;
function initParticles() {
particles.length = 0;
for (let i = 0; i <= numParticles; i++) {
const x = i % 200;
const y = i / 43;
const k = 5 * Math.cos(x / 14) * Math.cos(y / 30);
const e = y / 8 - 13;
const d = (k * k + e * e) / 59 + 4;
const a = Math.atan2(k, e);
particles.push({
k, e, d, a,
x: 0,
y: 0
});
}
}
function updateParticles() {
t += Math.PI / 20 * animationSpeed;
for (let i = 0; i < particles.length; i++) {
const p = particles[i];
const q = 60 - 3 * Math.sin(p.a * p.e) +
p.k * (3 + 4 / p.d * Math.sin(p.d * p.d - t * 2));
const c = p.d / 2 + p.e / 99 - t / 18;
p.x = q * Math.sin(c) + 200;
p.y = (q + p.d * 9) * Math.cos(c) + 200;
}
}
function drawParticles() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.15)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < particles.length; i++) {
const p = particles[i];
const colorValue = Math.floor(150 + 100 * Math.sin(t/5 + p.x/50));
ctx.fillStyle = `rgba(150, ${colorValue}, 255, 0.4)`;
ctx.beginPath();
ctx.arc(p.x, p.y, 1.2, 0, Math.PI * 2);
ctx.fill();
}
}
function animate() {
if (!isPaused) {
updateParticles();
drawParticles();
}
requestAnimationFrame(animate);
}
document.getElementById('pauseBtn').addEventListener('click', function() {
isPaused = !isPaused;
this.textContent = isPaused ? '继续' : '暂停';
});
document.getElementById('resetBtn').addEventListener('click', function() {
t = 0;
animationSpeed = 1;
initParticles();
});
document.getElementById('speedUpBtn').addEventListener('click', function() {
animationSpeed = Math.min(animationSpeed + 0.5, 5);
});
document.getElementById('slowDownBtn').addEventListener('click', function() {
animationSpeed = Math.max(animationSpeed - 0.5, 0.5);
});
initParticles();
animate();
</script>
</body>
</html>