容量 动效 仪表盘 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>
相关推荐
谙忆10241 小时前
前端图片直传对象存储:OSS/S3 预签名 URL、STS 临时凭证与回调校验
前端
CHNE_TAO_EMSM2 小时前
Android studio 打开文件时自动下载源码
前端·javascript·android studio
一孤程3 小时前
Airtest自动化测试第五篇:小程序与Web测试——跨平台自动化全覆盖
前端·自动化测试·小程序·自动化·测试·airtest
IT_陈寒3 小时前
SpringBoot自动配置不是你以为的那样的智能
前端·人工智能·后端
yume_sibai4 小时前
大屏数据可视化 - 边框红绿呼吸灯实现详解
前端·信息可视化·typescript
Hyyy4 小时前
很多Desktop都在上的Computer Use是什么
前端·llm
慢功夫4 小时前
开篇:VS Code 为什么不是一个普通 React App
前端·visual studio code
你挚爱的强哥4 小时前
Vue2 实现 1.5s 十连击监听(连续点击若干次),封装通用可复用点击检测工具,不用 data!Vue 封装通用连击监听方法,支持自定义时长与点击次数
前端·javascript·vue.js
huashengzsj5 小时前
Shopify个人建站如何搭建独立站:从零开始的完整指南
前端·网络·人工智能
程序猿小泓5 小时前
从 Claude Code 学 Agent Harness:一个前端工程师的 AI Agent 学习笔记
前端·人工智能·学习