容量 动效 仪表盘 Canvas 2D API

容量动效

html 复制代码
<!DOCTYPE html>
<html lang="zh">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Canvas 内部圆形波浪</title>
    <style>
      canvas {
        border: 5px solid black;
      }
    </style>
  </head>
  <body>
    <canvas id="waveCanvas" width="400" height="400"></canvas>
    <label for="heightPercentageInput">Wave Height:</label>
    <input
      type="range"
      id="heightPercentageInput"
      min="0"
      max="1"
      step="0.01"
      value="0.5"
    />
    <label for="speedInput">Wave Speed:</label>
    <input
      type="range"
      id="speedInput"
      min="0.1"
      max="5"
      step="0.1"
      value="1"
    />
    <label for="opacity1Input">Wave 1 Opacity:</label>
    <input
      type="range"
      id="opacity1Input"
      min="0"
      max="1"
      step="0.01"
      value="0.5"
    />
    <label for="opacity2Input">Wave 2 Opacity:</label>
    <input
      type="range"
      id="opacity2Input"
      min="0"
      max="1"
      step="0.01"
      value="0.2"
    />
    <script>
      const canvas = document.getElementById("waveCanvas");
      const ctx = canvas.getContext("2d");

      let time = 0;

      function drawWave() {
        ctx.clearRect(0, 0, canvas.width, canvas.height); // 清除之前的画面

        const centerX = canvas.width / 2;
        const centerY = canvas.height / 2;
        const radius = 100; // 圆的半径

        // 创建径向渐变
        const gradient = ctx.createRadialGradient(
          centerX,
          centerY,
          radius * 0.9,
          centerX,
          centerY,
          radius
        );
        gradient.addColorStop(0, "rgba(0, 255, 200, 0.1)");
        gradient.addColorStop(1, "rgba(0, 255, 200, 0)");

        ctx.save();
        ctx.scale(0.9, 0.9);
        ctx.translate(20, 20);

        // 设置渐变填充样式并绘制圆
        ctx.beginPath();
        ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
        ctx.fillStyle = gradient; // 使用渐变填充颜色
        ctx.fill(); // 填充圆
        ctx.clip(); // Clip to the circle

        // 获取输入值
        const heightPercentageInput = document.getElementById(
          "heightPercentageInput"
        );
        const speedInput = document.getElementById("speedInput");
        const opacity1Input = document.getElementById("opacity1Input");
        const opacity2Input = document.getElementById("opacity2Input");

        const waveHeight = radius * heightPercentageInput.value; // Control wave height
        const waveSpeed = speedInput.value; // Control wave speed
        const opacity1 = opacity1Input.value; // Control wave 1 opacity
        const opacity2 = opacity2Input.value; // Control wave 2 opacity

        // 画第一条波浪
        ctx.beginPath();
        ctx.moveTo(0, centerY + radius);
        for (let i = 0; i <= canvas.width; i++) {
          const y =
            Math.sin(i * 0.05 + time * waveSpeed) * 10 +
            waveHeight * 0.6 +
            centerY;
          ctx.lineTo(i, Math.min(y, centerY + radius)); // 确保在圆内
        }
        ctx.lineTo(canvas.width, centerY + radius);
        ctx.lineTo(0, centerY + radius);
        ctx.fillStyle = `rgba(0, 255, 200, ${opacity1})`;
        ctx.fill();

        // 画第二条波浪
        ctx.beginPath();
        ctx.moveTo(0, centerY + radius);
        for (let i = 0; i <= canvas.width; i++) {
          const y =
            Math.sin(i * 0.04 + time * (waveSpeed * 1.5) + Math.PI / 2) * 10 +
            waveHeight * 0.55 +
            centerY;
          ctx.lineTo(i, Math.min(y, centerY + radius)); // 确保在圆内
        }
        ctx.lineTo(canvas.width, centerY + radius);
        ctx.lineTo(0, centerY + radius);
        ctx.fillStyle = `rgba(0, 255, 200, ${opacity2})`; // Make it a bit more opaque
        ctx.fill();

        ctx.restore();

        // 绘制带有轨迹的旋转弧线
        const angle = (time / 5) % (Math.PI * 2); // 根据时间计算当前角度
        const trailLength = Math.PI * 0.75; // 弧线的长度
        const segments = 333; // 轨迹的段数

        // 绘制轨迹
        for (let i = 0; i < segments; i++) {
          const alpha = 1 - i / segments; // 渐变透明度
          const startAngle = angle - (i * trailLength) / segments; // 每段的起始角度
          const endAngle = startAngle + trailLength / segments; // 每段的结束角度

          ctx.beginPath();
          ctx.arc(centerX, centerY, radius, startAngle, endAngle); // 绘制每段弧线
          ctx.strokeStyle = `rgba(59, 144, 125, ${alpha})`; // 设置弧线颜色,带透明度
          ctx.lineWidth = 4 - (3 * i) / segments; // 渐变线宽
          ctx.stroke(); // 描绘弧线
        }

        // 设定一个小的偏移角度
        const offsetAngle = 2.31; // 调整这个值可以改变"往前"的距离

        // 绘制位于弧线末尾的点(移前)
        const dotX =
          centerX + radius * Math.cos(angle + trailLength - offsetAngle); // 计算点的X坐标
        const dotY =
          centerY + radius * Math.sin(angle + trailLength - offsetAngle); // 计算点的Y坐标
        ctx.beginPath();
        ctx.arc(dotX, dotY, 4, 0, Math.PI * 2); // 绘制点
        ctx.fillStyle = "#3b907d"; // 点的填充颜色
        ctx.fill(); // 填充点

        // 增加时间以实现动画
        time += 0.1;

        // 递归调用以实现动画效果
        requestAnimationFrame(drawWave);
      }

      drawWave(); // 开始绘制
    </script>
  </body>
</html>
相关推荐
西瓜太郎12344 分钟前
外层模型卡片与分组详情成功率不一致,应该怎么排查?
前端·typescript·go·软件工程·react
GreenTea20 分钟前
vLLM 与 SGLang KV Cache 底层实现机制深度调研报告
前端·后端·算法
几何心凉3 小时前
没有万能模型:我用 AiiOnly Token Plan,把多款大模型的长处拼进同一个项目
前端
kyriewen3 小时前
Claude Code 的额度今天缩水了17%——官方公告上写的是"永久提高25%"
前端·ai编程·claude
雪芽蓝域zzs4 小时前
vue解构平铺VS对象包裹
前端·javascript·vue.js
风骏时光牛马5 小时前
从零到实战,完整AI学习路线
前端
三十而立洋5 小时前
深入理解 Monorepo:子包安装依赖
前端·前端工程化
IT_陈寒5 小时前
Java Stream处理大集合,我的内存怎么就炸了
前端·人工智能·后端
Captaincc6 小时前
AI 用量桌面端-桌面宠物自定义指南
前端·人工智能
OpenTiny社区6 小时前
码力全开,智启前端新生态|OpenTiny 登陆华为全联接大会2026
前端·github