容量 动效 仪表盘 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>
相关推荐
子兮曰5 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰5 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万5 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝5 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋5 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁5 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95275 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大5 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师5 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学5 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端