html5 canvas 绘制节日礼花效果

一、html5 canvas 绘制节日礼花效果

展示效果:

Video_2025-12-27_145906_converted

 

 

此效果有ai写代码为主,人工辅助修改

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <script type="module">
      document.addEventListener("DOMContentLoaded", () => {
        const insScript = document.createElement("script");
        const date = Date.now();
        insScript.src = "/inscode_devtools_sdk.js?v=" + date;
        insScript.type = "module";
        document.body.appendChild(insScript);
      });
    </script>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>春节礼花动画</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      body {
        background: transparent;
        overflow: hidden;
        font-family: "Arial", sans-serif;
      }

      canvas {
        display: block;
        cursor: crosshair;
      }

      .title {
        position: absolute;
        top: 50px;
        left: 50%;
        transform: translateX(-50%);
        color: #ffd700;
        font-size: 2.5em;
        font-weight: bold;
        text-shadow: 0 0 20px #ffd700, 0 0 40px #ff6b6b;
        z-index: 10;
        animation: glow 2s ease-in-out infinite alternate;
      }

      @keyframes glow {
        from {
          text-shadow: 0 0 20px #ffd700, 0 0 40px #ff6b6b;
        }

        to {
          text-shadow: 0 0 30px #ffd700, 0 0 60px #ff6b6b, 0 0 80px #ff4757;
        }
      }

      .instructions {
        position: absolute;
        bottom: 30px;
        left: 50%;
        transform: translateX(-50%);
        color: #ffffff;
        font-size: 1.2em;
        text-align: center;
        opacity: 0.8;
        z-index: 10;
      }

      #divOne{
        position: relative;
      }
      #imgOne{
        position: absolute;
        width: 100%;
        z-index: 0;
        left: 0;
        top: 0;
      }
      #fireworksCanvas{
        position: relative;
        z-index: 1;
      }
    </style>

  </head>

  <body>
    <div id="divOne">

   
        <img id="imgOne" src="http://www.jnqianle.cn/upload/logo/content/202512/23/2303f83d-bb97-4153-8e0d-bc515722327d.jpg">
    <!-- <div class="title">🎆 春节礼花 🎆</div> -->
    <canvas id="fireworksCanvas"></canvas>
    <!-- <div class="instructions">点击屏幕放礼花 | 自动绽放</div> -->

 </div>
    <script>
      const canvas = document.getElementById("fireworksCanvas");
      const ctx = canvas.getContext("2d");

      // 设置画布大小
      function resizeCanvas() {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
      }
      resizeCanvas();
      window.addEventListener("resize", resizeCanvas);

      // 粒子类
      class Particle {
        constructor(x, y, color, velocity, size = 3) {
          this.x = x;
          this.y = y;
          this.color = color;
          this.velocity = velocity;
          this.size = size;
          this.alpha = 1;
          this.decay = Math.random() * 0.02 + 0.01;
          this.gravity = 0.1;
          this.trail = [];
          this.trailLength = 8;
        }

        update() {
          // 保存轨迹
          this.trail.push({ x: this.x, y: this.y, alpha: this.alpha });
          if (this.trail.length > this.trailLength) {
            this.trail.shift();
          }

          this.velocity.y += this.gravity;
          this.x += this.velocity.x;
          this.y += this.velocity.y;
          this.alpha -= this.decay;
          this.size *= 0.98;
        }

        draw() {
          // 绘制轨迹
          ctx.save();
          for (let i = 0; i < this.trail.length; i++) {
            const point = this.trail[i];
            const trailAlpha = (i / this.trail.length) * point.alpha * 0.5;
            ctx.globalAlpha = trailAlpha;
            ctx.fillStyle = this.color;
            ctx.beginPath();
            ctx.arc(
              point.x,
              point.y,
              this.size * (i / this.trail.length),
              0,
              Math.PI * 2
            );
            ctx.fill();
          }

          // 绘制主粒子
          ctx.globalAlpha = this.alpha;
          ctx.fillStyle = this.color;
          ctx.shadowBlur = 10;
          ctx.shadowColor = this.color;
          ctx.beginPath();
          ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
          ctx.fill();
          ctx.restore();
        }
      }

      // 礼花类
      class Firework {
        constructor(x, y, targetY) {
          this.x = x;
          this.y = y;
          this.targetY = targetY;
          this.particles = [];
          this.exploded = false;
          this.velocity = {
            x: (Math.random() - 0.5) * 2,
            y: -Math.random() * 3 - 8,
          };
          this.color = this.getRandomColor();
          this.trail = [];
        }

        getRandomColor() {
          const colors = [
            "#ff6b6b",
            "#4ecdc4",
            "#45b7d1",
            "#96ceb4",
            "#feca57",
            "#ff9ff3",
            "#54a0ff",
            "#5f27cd",
            "#00d2d3",
            "#ff9f43",
            "#ffd700",
            "#ff4757",
            "#3742fa",
            "#2ed573",
            "#ffa502",
          ];
          return colors[Math.floor(Math.random() * colors.length)];
        }

        update() {
          if (!this.exploded) {
            this.trail.push({ x: this.x, y: this.y });
            if (this.trail.length > 10) {
              this.trail.shift();
            }

            this.velocity.y += 0.2; // 重力
            this.x += this.velocity.x;
            this.y += this.velocity.y;

            if (this.velocity.y >= 0 || this.y <= this.targetY) {
              this.explode();
            }
          } else {
            this.particles = this.particles.filter((particle) => {
              particle.update();
              return particle.alpha > 0 && particle.size > 0.1;
            });
          }
        }

        explode() {
          this.exploded = true;
          const particleCount = Math.random() * 50 + 80;

          for (let i = 0; i < particleCount; i++) {
            const angle = (Math.PI * 2 * i) / particleCount;
            const velocity = Math.random() * 6 + 2;
            const size = Math.random() * 4 + 2;

            this.particles.push(
              new Particle(
                this.x,
                this.y,
                this.color,
                {
                  x: Math.cos(angle) * velocity + (Math.random() - 0.5) * 2,
                  y: Math.sin(angle) * velocity + (Math.random() - 0.5) * 2,
                },
                size
              )
            );
          }

          // 添加一些金色粒子增加节日气氛
          for (let i = 0; i < 20; i++) {
            const angle = Math.random() * Math.PI * 2;
            const velocity = Math.random() * 4 + 1;

            this.particles.push(
              new Particle(
                this.x,
                this.y,
                "#ffd700",
                {
                  x: Math.cos(angle) * velocity,
                  y: Math.sin(angle) * velocity,
                },
                Math.random() * 3 + 1
              )
            );
          }
        }

        draw() {
          if (!this.exploded) {
            // 绘制上升轨迹
            ctx.save();
            for (let i = 0; i < this.trail.length; i++) {
              const point = this.trail[i];
              const alpha = (i / this.trail.length) * 0.8;
              ctx.globalAlpha = alpha;
              ctx.fillStyle = this.color;
              ctx.shadowBlur = 5;
              ctx.shadowColor = this.color;
              ctx.beginPath();
              ctx.arc(point.x, point.y, 3, 0, Math.PI * 2);
              ctx.fill();
            }

            // 绘制礼花主体
            ctx.globalAlpha = 1;
            ctx.fillStyle = this.color;
            ctx.shadowBlur = 15;
            ctx.shadowColor = this.color;
            ctx.beginPath();
            ctx.arc(this.x, this.y, 4, 0, Math.PI * 2);
            ctx.fill();
            ctx.restore();
          } else {
            this.particles.forEach((particle) => particle.draw());
          }
        }
      }

      // 礼花数组
      const fireworks = [];

      // 创建随机礼花
      function createRandomFirework() {
        const x = Math.random() * canvas.width;
        const y = canvas.height;
        const targetY = Math.random() * canvas.height * 0.3 + 50;
        fireworks.push(new Firework(x, y, targetY));
      }

      // 动画循环
      function animate() {
        // 清除画布(透明背景)
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // 更新和绘制所有礼花
        for (let i = fireworks.length - 1; i >= 0; i--) {
          const firework = fireworks[i];
          firework.update();
          firework.draw();

          // 移除已经消失的礼花
          if (firework.exploded && firework.particles.length === 0) {
            fireworks.splice(i, 1);
          }
        }

        requestAnimationFrame(animate);
      }

      // 自动放礼花
      setInterval(() => {
        if (Math.random() < 0.8) {
          createRandomFirework();
        }
      }, 800);

      // 点击放礼花
      canvas.addEventListener("click", (e) => {
        const rect = canvas.getBoundingClientRect();
        const x = e.clientX - rect.left;
        const y = canvas.height;
        const targetY = e.clientY - rect.top;

        fireworks.push(new Firework(x, y, targetY));
      });

      // 开始动画
      animate();

      // 初始礼花
      setTimeout(() => {
        for (let i = 0; i < 3; i++) {
          setTimeout(() => createRandomFirework(), i * 300);
        }
      }, 1000);
    </script>
  </body>
</html>

 

 

 

 

更多:

html5 canvas 路径渲染_画线

html5 canvas 文本渲染

html5 canvas 简介

posted @ 2025-12-27 14:57  天马3798  阅读(1)  评论(0)    收藏  举报