下面是在网页中利用JavaScript实现绘制2023新年烟花的完整攻略。
在开始编写代码之前,我们需要准备以下工具和环境:
首先,我们需要在HTML文件中添加一个canvas标签,并设置宽高,代码如下:
<canvas id="fireworks"></canvas>
为了让烟花能够在页面中居中并占据整个窗口,我们需要为 canvas 标签添加一些样式:
canvas {
display: block;
margin: auto;
}
接下来,我们就可以编写 JavaScript 代码来实现绘制烟花的功能了。
我们需要创建一个画布,获取画布对象,并将其设置为全屏,并且设置画布的宽高为窗口的宽高,不过需要注意, HTML元素的宽高如果通过css设置,那么实际上元素的宽高仍旧是计算机能识别的默认值:
const canvas = document.getElementById('fireworks');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
创建一个 Firework 对象,用于描述烟花的基本属性,例如位置、颜色、运动轨迹等,代码如下:
class Firework {
constructor(x, y) {
this.x = x;
this.y = y;
this.color = `hsl(${Math.random() * 360}, 100%, 50%)`;
this.target = {
x: Math.random() * canvas.width,
y: Math.random() * canvas.height
}
this.speed = 10;
this.angle = Math.atan2(this.target.y - this.y, this.target.x - this.x);
this.gravity = 0.2;
this.vx = Math.cos(this.angle) * this.speed;
this.vy = Math.sin(this.angle) * this.speed;
this.opacity = 1;
this.trail = [];
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, 5, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
// Draw trail
ctx.globalAlpha = this.opacity;
for (let i = 0; i < this.trail.length; i++) {
ctx.beginPath();
ctx.arc(this.trail[i].x, this.trail[i].y, i * Math.random() * 2, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
}
}
update() {
// Update position
this.x += this.vx;
this.y += this.vy;
// Update velocity
this.vy += this.gravity;
// Update opacity
this.opacity -= 0.1;
// Update trail
this.trail.push({x: this.x, y: this.y});
if (this.trail.length > 10) {
this.trail.shift();
}
}
}
创建一个 Explosion 对象,用于描述烟花爆炸的基本属性,例如位置、颜色、大小等,代码如下:
class Explosion {
constructor(x, y, color) {
this.x = x;
this.y = y;
this.color = color;
this.particles = [];
for (let i = 0; i < 30; i++) {
this.particles.push(new Particle(this.x, this.y, this.color));
}
}
draw() {
for (let i = 0; i < this.particles.length; i++) {
this.particles[i].draw();
}
}
update() {
for (let i = 0; i < this.particles.length; i++) {
this.particles[i].update();
}
}
}
创建一个 Particle 对象,用于描述烟花中的粒子,例如位置、大小、速度等,代码如下:
class Particle {
constructor(x, y, color) {
this.x = x;
this.y = y;
this.color = color;
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
this.size = Math.random() * 3;
this.gravity = 0.2;
this.opacity = 1;
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
}
update() {
this.x += this.vx;
this.y += this.vy;
this.vy += this.gravity;
this.opacity -= 0.05;
this.size -= 0.05;
}
}
现在,我们需要创建一个动画,用于在画布上不断绘制烟花,代码如下:
let fireworks = [];
function loop() {
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw fireworks
for (let i = 0; i < fireworks.length; i++) {
fireworks[i].draw();
fireworks[i].update();
// Explode when reach the target
if (fireworks[i].y - fireworks[i].target.y > 0) {
let explosion = new Explosion(fireworks[i].x, fireworks[i].y, fireworks[i].color);
fireworks.splice(i, 1);
i--;
for (let j = 0; j < 10; j++) {
fireworks.push(new Firework(explosion.x, explosion.y));
}
}
}
// Generate new firework
if (Math.random() < 0.2) {
fireworks.push(new Firework(canvas.width/2, canvas.height));
}
requestAnimationFrame(loop);
}
loop();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>2023 New Year Fireworks</title>
<style>
canvas {
display: block;
margin: auto;
}
</style>
</head>
<body>
<canvas id="fireworks"></canvas>
<script>
const canvas = document.getElementById('fireworks');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
class Firework {
constructor(x, y) {
this.x = x;
this.y = y;
this.color = `hsl(${Math.random() * 360}, 100%, 50%)`;
this.target = {
x: Math.random() * canvas.width,
y: Math.random() * canvas.height
}
this.speed = 10;
this.angle = Math.atan2(this.target.y - this.y, this.target.x - this.x);
this.gravity = 0.2;
this.vx = Math.cos(this.angle) * this.speed;
this.vy = Math.sin(this.angle) * this.speed;
this.opacity = 1;
this.trail = [];
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, 5, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
// Draw trail
ctx.globalAlpha = this.opacity;
for (let i = 0; i < this.trail.length; i++) {
ctx.beginPath();
ctx.arc(this.trail[i].x, this.trail[i].y, i * Math.random() * 2, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
}
}
update() {
// Update position
this.x += this.vx;
this.y += this.vy;
// Update velocity
this.vy += this.gravity;
// Update opacity
this.opacity -= 0.1;
// Update trail
this.trail.push({x: this.x, y: this.y});
if (this.trail.length > 10) {
this.trail.shift();
}
}
}
class Explosion {
constructor(x, y, color) {
this.x = x;
this.y = y;
this.color = color;
this.particles = [];
for (let i = 0; i < 30; i++) {
this.particles.push(new Particle(this.x, this.y, this.color));
}
}
draw() {
for (let i = 0; i < this.particles.length; i++) {
this.particles[i].draw();
}
}
update() {
for (let i = 0; i < this.particles.length; i++) {
this.particles[i].update();
}
}
}
class Particle {
constructor(x, y, color) {
this.x = x;
this.y = y;
this.color = color;
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
this.size = Math.random() * 3;
this.gravity = 0.2;
this.opacity = 1;
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
}
update() {
this.x += this.vx;
this.y += this.vy;
this.vy += this.gravity;
this.opacity -= 0.05;
this.size -= 0.05;
}
}
let fireworks = [];
function loop() {
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw fireworks
for (let i = 0; i < fireworks.length; i++) {
fireworks[i].draw();
fireworks[i].update();
// Explode when reach the target
if (fireworks[i].y - fireworks[i].target.y > 0) {
let explosion = new Explosion(fireworks[i].x, fireworks[i].y, fireworks[i].color);
fireworks.splice(i, 1);
i--;
for (let j = 0; j < 10; j++) {
fireworks.push(new Firework(explosion.x, explosion.y));
}
}
}
// Generate new firework
if (Math.random() < 0.2) {
fireworks.push(new Firework(canvas.width/2, canvas.height));
}
requestAnimationFrame(loop);
}
loop();
</script>
</body>
</html>
这样,当我们在浏览器中打开该 HTML 文件时,就能看到一个基于 JavaScript 实现的烟花动画效果了。
修改烟花绘制的速度:将代码中的 speed
值调大或调小即可,例如将 speed
调整为 5,表示烟花的速度变慢了,可以让动画变得更加缓慢。
修改烟花交互方式:在 Demo 中实现的是以随机方式自动弹出一些烟火, 如果希望增加交互性,可以在页面上添加按钮等交互元素,当用户点击按钮时,触发 JavaScript 代码,从而实现相应的动画效果。
本文链接:http://task.lmcjl.com/news/1220.html