分享图
A
动画渲染工坊
就绪
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>并行分流式叠加减速箱 · 原理动画</title>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Rajdhani:wght@300;400;600;700&family=Share+Tech+Mono&display=swap" rel="stylesheet">
<style>
  :root {
    --bg: #060a14;
    --surface: #0c1628;
    --border: #1a3050;
    --hs: #ff5722;
    --hs-glow: rgba(255,87,34,0.35);
    --ls: #00e5a0;
    --ls-glow: rgba(0,229,160,0.30);
    --shaft: #b0bec5;
    --sleeve: #607d8b;
    --amber: #ffc107;
    --text: #cfd8dc;
    --text-dim: #607d8b;
    --panel: #0a1220;
  }
  *, *::before, *::after { margin:0; padding:0; box-sizing:border-box; }
  html, body { width:100%; height:100%; overflow:hidden; background:var(--bg); font-family:'Rajdhani',sans-serif; color:var(--text); }
  #app { display:flex; flex-direction:column; height:100vh; width:100vw; }
  #svg-wrap { flex:1; display:flex; align-items:center; justify-content:center; min-height:0; padding:8px; }
  #diagram { width:100%; height:100%; max-width:1400px; max-height:800px; }
  #controls {
    flex-shrink:0; display:flex; flex-wrap:wrap; gap:16px 28px;
    padding:14px 24px 18px; background:var(--panel);
    border-top:1px solid var(--border); align-items:center; justify-content:center;
  }
  .ctrl-group { display:flex; align-items:center; gap:8px; }
  .ctrl-group label { font-size:13px; font-weight:600; letter-spacing:0.5px; white-space:nowrap; }
  .ctrl-group .val { font-family:'Share Tech Mono',monospace; font-size:13px; min-width:52px; text-align:right; }
  .hs-color { color:var(--hs); }
  .ls-color { color:var(--ls); }
  input[type=range] {
    -webkit-appearance:none; width:140px; height:6px; border-radius:3px;
    background:var(--border); outline:none; cursor:pointer;
  }
  input[type=range]::-webkit-slider-thumb {
    -webkit-appearance:none; width:16px; height:16px; border-radius:50%;
    border:2px solid var(--bg); cursor:pointer;
  }
  #hs-rpm::-webkit-slider-thumb { background:var(--hs); }
  #ls-rpm::-webkit-slider-thumb { background:var(--ls); }
  .toggle-btn {
    font-family:'Rajdhani',sans-serif; font-size:12px; font-weight:600;
    padding:5px 14px; border:1px solid var(--border); border-radius:4px;
    background:transparent; color:var(--text-dim); cursor:pointer;
    letter-spacing:0.4px; transition:all .2s;
  }
  .toggle-btn.active { border-color:var(--amber); color:var(--amber); background:rgba(255,193,7,0.08); }
  .toggle-btn:hover { border-color:var(--text); color:var(--text); }
  #pause-btn { border-color:var(--text-dim); color:var(--text-dim); min-width:64px; }
  #pause-btn.paused { border-color:#ef5350; color:#ef5350; }
  @media (max-width:768px) {
    #controls { gap:10px 16px; padding:10px 12px 14px; }
    input[type=range] { width:100px; }
  }
</style>
</head>
<body>
<div id="app">
  <div id="svg-wrap">
    <svg id="diagram" viewBox="0 0 1200 860" xmlns="http://www.w3.org/2000/svg">
      <defs>
        <!-- 网格图案 -->
        <pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
          <path d="M40,0 L0,0 0,40" fill="none" stroke="#0e1a2a" stroke-width="0.5"/>
        </pattern>
        <!-- HS发光 -->
        <filter id="glow-hs" x="-50%" y="-50%" width="200%" height="200%">
          <feGaussianBlur stdDeviation="4" result="b"/>
          <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
        </filter>
        <!-- LS发光 -->
        <filter id="glow-ls" x="-50%" y="-50%" width="200%" height="200%">
          <feGaussianBlur stdDeviation="4" result="b"/>
          <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
        </filter>
        <!-- 通用发光 -->
        <filter id="glow-amber" x="-50%" y="-50%" width="200%" height="200%">
          <feGaussianBlur stdDeviation="6" result="b"/>
          <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
        </filter>
        <!-- 箭头标记 HS -->
        <marker id="arrow-hs" viewBox="0 0 10 6" refX="10" refY="3" markerWidth="8" markerHeight="6" orient="auto">
          <path d="M0,0 L10,3 L0,6 Z" fill="var(--hs)"/>
        </marker>
        <!-- 箭头标记 LS -->
        <marker id="arrow-ls" viewBox="0 0 10 6" refX="10" refY="3" markerWidth="8" markerHeight="6" orient="auto">
          <path d="M0,0 L10,3 L0,6 Z" fill="var(--ls)"/>
        </marker>
        <!-- 渐变:箱体 -->
        <linearGradient id="housing-grad" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stop-color="#132040"/>
          <stop offset="100%" stop-color="#0a1428"/>
        </linearGradient>
        <!-- 渐变:釜体 -->
        <linearGradient id="vessel-grad" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stop-color="#0c1628"/>
          <stop offset="100%" stop-color="#070c18"/>
        </linearGradient>
        <!-- 剖面线图案 -->
        <pattern id="hatch" width="6" height="6" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
          <line x1="0" y1="0" x2="0" y2="6" stroke="#1a3050" stroke-width="0.8"/>
        </pattern>
      </defs>

      <!-- 背景 -->
      <rect width="1200" height="860" fill="var(--bg)"/>
      <rect width="1200" height="860" fill="url(#grid)" opacity="0.6"/>

      <!-- 标题 -->
      <text x="600" y="36" text-anchor="middle" fill="#ffffff" font-family="Orbitron,sans-serif" font-size="20" font-weight="700" letter-spacing="3">PARALLEL SPLIT-FLOW GEARBOX</text>
      <text x="600" y="58" text-anchor="middle" fill="var(--text-dim)" font-family="Rajdhani,sans-serif" font-size="14" font-weight="400" letter-spacing="1">并行分流式叠加减速箱 · 最终理想解原理动画</text>

      <!-- ===== 釜体轮廓 ===== -->
      <path d="M440,640 L440,820 Q440,850 470,850 L730,850 Q760,850 760,820 L760,640" fill="url(#vessel-grad)" stroke="#1a3050" stroke-width="1.5"/>
      <!-- 釜内物料液面 -->
      <path d="M445,720 Q520,710 600,715 Q680,720 755,712" fill="none" stroke="rgba(0,229,160,0.15)" stroke-width="1"/>
      <path d="M445,740 Q530,732 600,736 Q670,740 755,734" fill="none" stroke="rgba(0,229,160,0.08)" stroke-width="1"/>
      <!-- 釜盖法兰 -->
      <rect x="410" y="628" width="380" height="16" rx="3" fill="#0f1c30" stroke="#1e3a5e" stroke-width="1.2"/>
      <text x="400" y="640" text-anchor="end" fill="var(--text-dim)" font-family="Rajdhani,sans-serif" font-size="10">釜盖法兰</text>
      <!-- 法兰螺栓 -->
      <circle cx="425" cy="636" r="4" fill="#0a1220" stroke="#2a4a6a" stroke-width="0.8"/>
      <circle cx="465" cy="636" r="4" fill="#0a1220" stroke="#2a4a6a" stroke-width="0.8"/>
      <circle cx="735" cy="636" r="4" fill="#0a1220" stroke="#2a4a6a" stroke-width="0.8"/>
      <circle cx="775" cy="636" r="4" fill="#0a1220" stroke="#2a4a6a" stroke-width="0.8"/>

      <!-- ===== 减速箱箱体 ===== -->
      <rect x="230" y="248" width="740" height="170" rx="8" fill="url(#housing-grad)" stroke="#1e3a5e" stroke-width="1.8"/>
      <!-- 剖面线(箱体壁) -->
      <rect x="230" y="248" width="740" height="170" rx="8" fill="url(#hatch)" opacity="0.25"/>
      <!-- 箱体标注 -->
      <text x="230" y="242" fill="var(--amber)" font-family="Rajdhani,sans-serif" font-size="11" font-weight="600">扁平共用箱体</text>
      <!-- 高度标注线 -->
      <line x1="210" y1="252" x2="210" y2="414" stroke="var(--amber)" stroke-width="0.8" stroke-dasharray="3,3"/>
      <line x1="205" y1="252" x2="215" y2="252" stroke="var(--amber)" stroke-width="0.8"/>
      <line x1="205" y1="414" x2="215" y2="414" stroke="var(--amber)" stroke-width="0.8"/>
      <text x="207" y="340" text-anchor="middle" fill="var(--amber)" font-family="Share Tech Mono,monospace" font-size="10" transform="rotate(-90,207,340)">紧凑轴向高度</text>

      <!-- ===== 高速电机 (HS) ===== -->
      <g id="hs-motor-group">
        <rect x="62" y="286" width="148" height="76" rx="6" fill="#1a0d05" stroke="var(--hs)" stroke-width="1.5" opacity="0.9"/>
        <!-- 散热片纹理 -->
        <line x1="75" y1="294" x2="75" y2="354" stroke="rgba(255,87,34,0.15)" stroke-width="1"/>
        <line x1="88" y1="294" x2="88" y2="354" stroke="rgba(255,87,34,0.15)" stroke-width="1"/>
        <line x1="101" y1="294" x2="101" y2="354" stroke="rgba(255,87,34,0.15)" stroke-width="1"/>
        <line x1="114" y1="294" x2="114" y2="354" stroke="rgba(255,87,34,0.15)" stroke-width="1"/>
        <text x="136" y="320" text-anchor="middle" fill="var(--hs)" font-family="Rajdhani,sans-serif" font-size="12" font-weight="700">高速电机</text>
        <text x="136" y="336" text-anchor="middle" fill="rgba(255,87,34,0.6)" font-family="Share Tech Mono,monospace" font-size="9">HS MOTOR</text>
        <!-- 转速指示 -->
        <text id="hs-rpm-label" x="136" y="352" text-anchor="middle" fill="var(--hs)" font-family="Share Tech Mono,monospace" font-size="10">1200 RPM</text>
      </g>
      <!-- HS 水平输入轴 -->
      <rect x="210" y="318" width="60" height="12" rx="2" fill="#2a1a10" stroke="var(--hs)" stroke-width="1"/>
      <line x1="270" y1="324" x2="320" y2="324" stroke="var(--hs)" stroke-width="2" stroke-dasharray="0" filter="url(#glow-hs)" opacity="0.7"/>

      <!-- ===== 低速电机 (LS) ===== -->
      <g id="ls-motor-group">
        <rect x="990" y="286" width="148" height="76" rx="6" fill="#051a12" stroke="var(--ls)" stroke-width="1.5" opacity="0.9"/>
        <line x1="1003" y1="294" x2="1003" y2="354" stroke="rgba(0,229,160,0.15)" stroke-width="1"/>
        <line x1="1016" y1="294" x2="1016" y2="354" stroke="rgba(0,229,160,0.15)" stroke-width="1"/>
        <line x1="1029" y1="294" x2="1029" y2="354" stroke="rgba(0,229,160,0.15)" stroke-width="1"/>
        <line x1="1042" y1="294" x2="1042" y2="354" stroke="rgba(0,229,160,0.15)" stroke-width="1"/>
        <text x="1064" y="320" text-anchor="middle" fill="var(--ls)" font-family="Rajdhani,sans-serif" font-size="12" font-weight="700">低速电机</text>
        <text x="1064" y="336" text-anchor="middle" fill="rgba(0,229,160,0.6)" font-family="Share Tech Mono,monospace" font-size="9">LS MOTOR</text>
        <text id="ls-rpm-label" x="1064" y="352" text-anchor="middle" fill="var(--ls)" font-family="Share Tech Mono,monospace" font-size="10">200 RPM</text>
      </g>
      <!-- LS 水平输入轴 -->
      <rect x="930" y="318" width="60" height="12" rx="2" fill="#0a2a1a" stroke="var(--ls)" stroke-width="1"/>
      <line x1="880" y1="324" x2="930" y2="324" stroke="var(--ls)" stroke-width="2" filter="url(#glow-ls)" opacity="0.7"/>

      <!-- ===== 内部齿轮机构 ===== -->
      <!-- HS 伞齿轮对 -->
      <g id="hs-bevel-pair">
        <!-- 水平伞齿轮(小) -->
        <g id="hs-bevel-h" transform="rotate(0,320,324)">
        </g>
        <!-- 垂直伞齿轮(大) -->
        <g id="hs-bevel-v" transform="rotate(0,320,370)">
        </g>
      </g>

      <!-- LS 伞齿轮对 -->
      <g id="ls-bevel-pair">
        <g id="ls-bevel-h" transform="rotate(0,880,324)">
        </g>
        <g id="ls-bevel-v" transform="rotate(0,880,370)">
        </g>
      </g>

      <!-- 中心行星齿轮组 -->
      <g id="planetary-group">
      </g>

      <!-- HS 传动轴(伞齿轮→中心) -->
      <line x1="320" y1="380" x2="320" y2="400" stroke="var(--hs)" stroke-width="2" opacity="0.5"/>
      <line x1="320" y1="400" x2="560" y2="400" stroke="var(--hs)" stroke-width="2" opacity="0.5" stroke-dasharray="6,3"/>
      <line x1="560" y1="400" x2="560" y2="380" stroke="var(--hs)" stroke-width="2" opacity="0.5"/>

      <!-- LS 传动轴(伞齿轮→中心) -->
      <line x1="880" y1="380" x2="880" y2="400" stroke="var(--ls)" stroke-width="2" opacity="0.5"/>
      <line x1="880" y1="400" x2="640" y2="400" stroke="var(--ls)" stroke-width="2" opacity="0.5" stroke-dasharray="6,3"/>
      <line x1="640" y1="400" x2="640" y2="380" stroke="var(--ls)" stroke-width="2" opacity="0.5"/>

      <!-- ===== 同轴输出轴 ===== -->
      <!-- 60mm 空心轴套 -->
      <rect id="sleeve-60" x="578" y="418" width="44" height="210" rx="3" fill="rgba(96,125,139,0.25)" stroke="var(--sleeve)" stroke-width="1.5"/>
      <!-- 轴套旋转标记 -->
      <g id="sleeve-marks">
        <line x1="578" y1="470" x2="582" y2="470" stroke="var(--ls)" stroke-width="1.5" opacity="0.7"/>
        <line x1="578" y1="530" x2="582" y2="530" stroke="var(--ls)" stroke-width="1.5" opacity="0.7"/>
        <line x1="618" y1="500" x2="622" y2="500" stroke="var(--ls)" stroke-width="1.5" opacity="0.7"/>
        <line x1="618" y1="560" x2="622" y2="560" stroke="var(--ls)" stroke-width="1.5" opacity="0.7"/>
      </g>
      <!-- 35mm 实心轴 -->
      <rect id="shaft-35" x="589" y="418" width="22" height="222" rx="2" fill="rgba(176,190,197,0.2)" stroke="var(--shaft)" stroke-width="1.2"/>
      <!-- 实心轴旋转标记 -->
      <g id="shaft-marks">
        <line x1="589" y1="460" x2="593" y2="460" stroke="var(--hs)" stroke-width="1.5" opacity="0.8"/>
        <line x1="607" y1="490" x2="611" y2="490" stroke="var(--hs)" stroke-width="1.5" opacity="0.8"/>
        <line x1="589" y1="540" x2="593" y2="540" stroke="var(--hs)" stroke-width="1.5" opacity="0.8"/>
        <line x1="607" y1="580" x2="611" y2="580" stroke="var(--hs)" stroke-width="1.5" opacity="0.8"/>
      </g>

      <!-- 径向游隙标注 -->
      <g id="clearance-group" visibility="hidden">
        <rect x="585" y="495" width="30" height="30" rx="2" fill="none" stroke="var(--amber)" stroke-width="1.5" stroke-dasharray="3,2" filter="url(#glow-amber)"/>
        <line x1="615" y1="510" x2="660" y2="480" stroke="var(--amber)" stroke-width="0.8"/>
        <rect x="660" y="465" width="120" height="36" rx="4" fill="rgba(255,193,7,0.08)" stroke="var(--amber)" stroke-width="0.8"/>
        <text x="720" y="479" text-anchor="middle" fill="var(--amber)" font-family="Rajdhani,sans-serif" font-size="10" font-weight="600">径向游隙 0.15mm</text>
        <text x="720" y="494" text-anchor="middle" fill="rgba(255,193,7,0.7)" font-family="Share Tech Mono,monospace" font-size="9">Ø60 sleeve / Ø35 shaft</text>
        <!-- 放大视图 -->
        <rect x="660" y="508" width="100" height="50" rx="3" fill="#0a1020" stroke="var(--amber)" stroke-width="0.6"/>
        <text x="710" y="520" text-anchor="middle" fill="rgba(255,193,7,0.5)" font-family="Share Tech Mono,monospace" font-size="7">ZOOM ×50</text>
        <!-- 放大后的轴套截面 -->
        <circle cx="710" cy="538" r="14" fill="none" stroke="var(--sleeve)" stroke-width="1.5"/>
        <circle cx="710" cy="538" r="9" fill="none" stroke="var(--shaft)" stroke-width="1.2"/>
        <!-- 游隙高亮 -->
        <circle cx="710" cy="538" r="11" fill="none" stroke="var(--amber)" stroke-width="0.6" stroke-dasharray="2,2" opacity="0.8"/>
      </g>

      <!-- ===== 输出工具 ===== -->
      <!-- 刮壁框(连接60mm轴套) -->
      <g id="scraper-group">
        <rect x="490" y="625" width="8" height="60" rx="2" fill="rgba(0,229,160,0.15)" stroke="var(--ls)" stroke-width="1"/>
        <rect x="702" y="625" width="8" height="60" rx="2" fill="rgba(0,229,160,0.15)" stroke="var(--ls)" stroke-width="1"/>
        <rect x="490" y="621" width="220" height="8" rx="2" fill="rgba(0,229,160,0.15)" stroke="var(--ls)" stroke-width="1"/>
        <!-- 刮壁桨叶 -->
        <rect x="486" y="680" width="16" height="4" rx="1" fill="var(--ls)" opacity="0.6"/>
        <rect x="698" y="680" width="16" height="4" rx="1" fill="var(--ls)" opacity="0.6"/>
        <text x="478" y="660" text-anchor="end" fill="var(--ls)" font-family="Rajdhani,sans-serif" font-size="9" opacity="0.7">刮壁框</text>
      </g>

      <!-- 分散盘(连接35mm轴) -->
      <g id="disperser-group">
        <rect x="560" y="635" width="80" height="8" rx="3" fill="rgba(255,87,34,0.2)" stroke="var(--hs)" stroke-width="1.2"/>
        <!-- 分散盘齿 -->
        <rect x="558" y="643" width="6" height="6" rx="1" fill="var(--hs)" opacity="0.5"/>
        <rect x="574" y="643" width="6" height="6" rx="1" fill="var(--hs)" opacity="0.5"/>
        <rect x="590" y="643" width="6" height="6" rx="1" fill="var(--hs)" opacity="0.5"/>
        <rect x="606" y="643" width="6" height="6" rx="1" fill="var(--hs)" opacity="0.5"/>
        <rect x="622" y="643" width="6" height="6" rx="1" fill="var(--hs)" opacity="0.5"/>
        <rect x="636" y="643" width="6" height="6" rx="1" fill="var(--hs)" opacity="0.5"/>
        <text x="648" y="648" fill="var(--hs)" font-family="Rajdhani,sans-serif" font-size="9" opacity="0.7">分散盘</text>
      </g>

      <!-- ===== 动力流粒子容器 ===== -->
      <g id="power-flow-hs"></g>
      <g id="power-flow-ls"></g>

      <!-- ===== 偏置距离标注 ===== -->
      <line x1="320" y1="235" x2="600" y2="235" stroke="var(--text-dim)" stroke-width="0.8" marker-end="url(#arrow-hs)" opacity="0.5"/>
      <line x1="880" y1="235" x2="600" y2="235" stroke="var(--text-dim)" stroke-width="0.8" marker-end="url(#arrow-ls)" opacity="0.5"/>
      <line x1="320" y1="228" x2="320" y2="242" stroke="var(--text-dim)" stroke-width="0.8" opacity="0.5"/>
      <line x1="880" y1="228" x2="880" y2="242" stroke="var(--text-dim)" stroke-width="0.8" opacity="0.5"/>
      <text x="440" y="230" fill="var(--text-dim)" font-family="Share Tech Mono,monospace" font-size="9">偏置 120mm</text>
      <text x="700" y="230" fill="var(--text-dim)" font-family="Share Tech Mono,monospace" font-size="9">偏置 120mm</text>

      <!-- 轴径标注 -->
      <text x="570" y="450" text-anchor="end" fill="var(--sleeve)" font-family="Share Tech Mono,monospace" font-size="8">Ø60 空心轴套</text>
      <text x="570" y="462" text-anchor="end" fill="var(--shaft)" font-family="Share Tech Mono,monospace" font-size="8">Ø35 实心轴</text>

      <!-- ===== IFR 理想解标注 ===== -->
      <g id="ifr-badge">
        <rect x="920" y="80" width="240" height="60" rx="6" fill="rgba(255,193,7,0.06)" stroke="var(--amber)" stroke-width="0.8"/>
        <text x="940" y="100" fill="var(--amber)" font-family="Orbitron,sans-serif" font-size="10" font-weight="700">IFR · 最终理想解</text>
        <text x="940" y="116" fill="var(--text-dim)" font-family="Rajdhani,sans-serif" font-size="10">轴向高度↓ 重心↓ 稳定性↑</text>
        <text x="940" y="130" fill="var(--text-dim)" font-family="Rajdhani,sans-serif" font-size="10">双动力解耦 · 同轴汇合输出</text>
      </g>

      <!-- 旋转方向指示弧 -->
      <g id="rotation-indicators">
        <!-- HS 旋转箭头 -->
        <path id="hs-rot-arc" d="" fill="none" stroke="var(--hs)" stroke-width="1.2" opacity="0.6"/>
        <!-- LS 旋转箭头 -->
        <path id="ls-rot-arc" d="" fill="none" stroke="var(--ls)" stroke-width="1.2" opacity="0.6"/>
      </g>

    </svg>
  </div>

  <div id="controls">
    <div class="ctrl-group">
      <label class="hs-color">高速电机</label>
      <input type="range" id="hs-rpm" min="0" max="3000" value="1200" step="50">
      <span class="val hs-color" id="hs-rpm-val">1200</span>
      <span style="font-size:11px;color:var(--text-dim)">RPM</span>
    </div>
    <div class="ctrl-group">
      <label class="ls-color">低速电机</label>
      <input type="range" id="ls-rpm" min="0" max="500" value="200" step="10">
      <span class="val ls-color" id="ls-rpm-val">200</span>
      <span style="font-size:11px;color:var(--text-dim)">RPM</span>
    </div>
    <div class="ctrl-group">
      <button class="toggle-btn active" id="flow-btn">动力流</button>
    </div>
    <div class="ctrl-group">
      <button class="toggle-btn" id="clearance-btn">径向游隙</button>
    </div>
    <div class="ctrl-group">
      <button class="toggle-btn" id="pause-btn">暂停</button>
    </div>
  </div>
</div>

<script>
(function() {
  'use strict';

  const NS = 'http://www.w3.org/2000/svg';
  const svg = document.getElementById('diagram');

  // === 配置 ===
  const CFG = {
    hsRPM: 1200,
    lsRPM: 200,
    showFlow: true,
    showClearance: false,
    paused: false
  };

  // === 动画状态 ===
  let hsAngle = 0, lsAngle = 0;
  let prevTime = 0;
  let globalTime = 0;

  // === 齿轮路径生成 ===
  function gearPath(teeth, outerR, innerR) {
    const pts = [];
    const step = (Math.PI * 2) / teeth;
    for (let i = 0; i < teeth; i++) {
      const a = i * step;
      pts.push([outerR * Math.cos(a - step * 0.18), outerR * Math.sin(a - step * 0.18)]);
      pts.push([outerR * Math.cos(a + step * 0.18), outerR * Math.sin(a + step * 0.18)]);
      pts.push([innerR * Math.cos(a + step * 0.32), innerR * Math.sin(a + step * 0.32)]);
      pts.push([innerR * Math.cos(a + step * 0.68), innerR * Math.sin(a + step * 0.68)]);
    }
    return 'M' + pts.map(p => p[0].toFixed(1) + ',' + p[1].toFixed(1)).join('L') + 'Z';
  }

  // === 创建齿轮SVG元素 ===
  function createGearElement(parentId, cx, cy, teeth, outerR, innerR, holeR, color, strokeColor) {
    const parent = document.getElementById(parentId);
    const g = document.createElementNS(NS, 'g');

    const path = document.createElementNS(NS, 'path');
    path.setAttribute('d', gearPath(teeth, outerR, innerR));
    path.setAttribute('fill', color);
    path.setAttribute('stroke', strokeColor || 'rgba(255,255,255,0.2)');
    path.setAttribute('stroke-width', '0.6');
    path.setAttribute('transform', `translate(${cx},${cy})`);
    g.appendChild(path);

    // 中心孔
    if (holeR > 0) {
      const hole = document.createElementNS(NS, 'circle');
      hole.setAttribute('cx', cx);
      hole.setAttribute('cy', cy);
      hole.setAttribute('r', holeR);
      hole.setAttribute('fill', '#0a1020');
      hole.setAttribute('stroke', strokeColor || 'rgba(255,255,255,0.15)');
      hole.setAttribute('stroke-width', '0.5');
      g.appendChild(hole);
    }

    parent.appendChild(g);
    return { group: g, cx, cy, teeth, path };
  }

  // === 创建伞齿轮截面 ===
  function createBevelGearSection(parentId, cx, cy, isHorizontal, color, size) {
    const parent = document.getElementById(parentId);
    const g = document.createElementNS(NS, 'g');

    if (isHorizontal) {
      // 水平伞齿轮截面 — 梯形
      const w1 = size * 1.2, w2 = size * 0.6, h = size * 0.9;
      const d = `M${cx - w1/2},${cy - h/2} L${cx + w1/2},${cy - h/2} L${cx + w2/2},${cy + h/2} L${cx - w2/2},${cy + h/2} Z`;
      const path = document.createElementNS(NS, 'path');
      path.setAttribute('d', d);
      path.setAttribute('fill', color);
      path.setAttribute('stroke', 'rgba(255,255,255,0.25)');
      path.setAttribute('stroke-width', '0.8');
      g.appendChild(path);

      // 齿纹理线
      for (let i = 0; i < 4; i++) {
        const t = (i + 1) / 5;
        const lw = w1 + (w2 - w1) * t;
        const ly = cy - h/2 + h * t;
        const line = document.createElementNS(NS, 'line');
        line.setAttribute('x1', cx - lw/2);
        line.setAttribute('y1', ly);
        line.setAttribute('x2', cx + lw/2);
        line.setAttribute('y2', ly);
        line.setAttribute('stroke', 'rgba(255,255,255,0.12)');
        line.setAttribute('stroke-width', '0.5');
        g.appendChild(line);
      }
    } else {
      // 垂直伞齿轮截面 — 梯形(竖向)
      const h1 = size * 1.2, h2 = size * 0.6, w = size * 0.9;
      const d = `M${cx - w/2},${cy - h1/2} L${cx + w/2},${cy - h1/2} L${cx + w/2},${cy + h2/2} L${cx - w/2},${cy + h2/2} Z`;
      const path = document.createElementNS(NS, 'path');
      path.setAttribute('d', d);
      path.setAttribute('fill', color);
      path.setAttribute('stroke', 'rgba(255,255,255,0.25)');
      path.setAttribute('stroke-width', '0.8');
      g.appendChild(path);

      for (let i = 0; i < 4; i++) {
        const t = (i + 1) / 5;
        const lh = h1 + (h2 - h1) * t;
        const ly = cy - h1/2 + (h1/2 + h2/2) * t;
        const line = document.createElementNS(NS, 'line');
        line.setAttribute('x1', cx - w/2);
        line.setAttribute('y1', ly);
        line.setAttribute('x2', cx + w/2);
        line.setAttribute('y2', ly);
        line.setAttribute('stroke', 'rgba(255,255,255,0.12)');
        line.setAttribute('stroke-width', '0.5');
        g.appendChild(line);
      }
    }

    parent.appendChild(g);
    return { group: g, cx, cy };
  }

  // === 创建行星齿轮组 ===
  function createPlanetaryGroup() {
    const parent = document.getElementById('planetary-group');
    const cx = 600, cy = 365;

    // 外齿圈(连接低速 → 60mm轴套)
    const ring = document.createElementNS(NS, 'circle');
    ring.setAttribute('cx', cx);
    ring.setAttribute('cy', cy);
    ring.setAttribute('r', 42);
    ring.setAttribute('fill', 'none');
    ring.setAttribute('stroke', 'var(--ls)');
    ring.setAttribute('stroke-width', '3');
    ring.setAttribute('stroke-dasharray', '4,2');
    ring.setAttribute('opacity', '0.6');
    parent.appendChild(ring);

    // 齿圈内齿纹理
    const ringTeeth = document.createElementNS(NS, 'circle');
    ringTeeth.setAttribute('cx', cx);
    ringTeeth.setAttribute('cy', cy);
    ringTeeth.setAttribute('r', 39);
    ringTeeth.setAttribute('fill', 'none');
    ringTeeth.setAttribute('stroke', 'var(--ls)');
    ringTeeth.setAttribute('stroke-width', '0.5');
    ringTeeth.setAttribute('stroke-dasharray', '2,3');
    ringTeeth.setAttribute('opacity', '0.4');
    parent.appendChild(ringTeeth);

    // 行星齿轮(3个)
    const planetPositions = [
      { x: cx + 26, y: cy - 15 },
      { x: cx - 22, y: cy - 10 },
      { x: cx, y: cy + 26 }
    ];
    const planetGears = [];
    planetPositions.forEach(pos => {
      const pg = document.createElementNS(NS, 'g');
      const p = document.createElementNS(NS, 'path');
      p.setAttribute('d', gearPath(8, 11, 8));
      p.setAttribute('transform', `translate(${pos.x},${pos.y})`);
      p.setAttribute('fill', 'rgba(176,190,197,0.2)');
      p.setAttribute('stroke', 'rgba(176,190,197,0.4)');
      p.setAttribute('stroke-width', '0.5');
      pg.appendChild(p);
      const hole = document.createElementNS(NS, 'circle');
      hole.setAttribute('cx', pos.x);
      hole.setAttribute('cy', pos.y);
      hole.setAttribute('r', 3);
      hole.setAttribute('fill', '#0a1020');
      hole.setAttribute('stroke', 'rgba(176,190,197,0.3)');
      hole.setAttribute('stroke-width', '0.4');
      pg.appendChild(hole);
      parent.appendChild(pg);
      planetGears.push({ group: pg, path: p, ...pos });
    });

    // 太阳轮(连接高速 → 35mm轴)
    const sunGear = createGearElement('planetary-group', cx, cy, 10, 16, 12, 4, 'rgba(255,87,34,0.25)', 'var(--hs)');

    // 标注
    const sunLabel = document.createElementNS(NS, 'text');
    sunLabel.setAttribute('x', cx);
    sunLabel.setAttribute('y', cy + 55);
    sunLabel.setAttribute('text-anchor', 'middle');
    sunLabel.setAttribute('fill', 'var(--text-dim)');
    sunLabel.setAttribute('font-family', 'Rajdhani,sans-serif');
    sunLabel.setAttribute('font-size', '9');
    sunLabel.textContent = '行星齿轮同轴汇合';
    parent.appendChild(sunLabel);

    return { planetGears, sunGear, cx, cy };
  }

  // === 动力流粒子系统 ===
  const hsParticles = [];
  const lsParticles = [];

  // HS动力流路径关键点
  const hsPath = [
    { x: 210, y: 324 },  // 电机输出
    { x: 320, y: 324 },  // 伞齿轮
    { x: 320, y: 370 },  // 伞齿轮换向
    { x: 320, y: 400 },  // 传动轴
    { x: 560, y: 400 },  // 传动至中心
    { x: 600, y: 370 },  // 太阳轮
    { x: 600, y: 418 },  // 输出轴起点
    { x: 600, y: 640 }   // 分散盘
  ];

  // LS动力流路径关键点
  const lsPath = [
    { x: 990, y: 324 },  // 电机输出
    { x: 880, y: 324 },  // 伞齿轮
    { x: 880, y: 370 },  // 伞齿轮换向
    { x: 880, y: 400 },  // 传动轴
    { x: 640, y: 400 },  // 传动至中心
    { x: 600, y: 365 },  // 齿圈
    { x: 600, y: 418 },  // 输出轴套起点
    { x: 600, y: 625 }   // 刮壁框
  ];

  // 沿路径插值
  function interpolatePath(pathPoints, t) {
    t = ((t % 1) + 1) % 1;
    const totalSegments = pathPoints.length - 1;
    const segFloat = t * totalSegments;
    const segIndex = Math.min(Math.floor(segFloat), totalSegments - 1);
    const segT = segFloat - segIndex;
    const p1 = pathPoints[segIndex];
    const p2 = pathPoints[segIndex + 1];
    return {
      x: p1.x + (p2.x - p1.x) * segT,
      y: p1.y + (p2.y - p1.y) * segT
    };
  }

  // 创建粒子
  function createParticles(container, pathPoints, color, count) {
    const particles = [];
    const parentEl = document.getElementById(container);
    for (let i = 0; i < count; i++) {
      const circle = document.createElementNS(NS, 'circle');
      circle.setAttribute('r', '2.5');
      circle.setAttribute('fill', color);
      circle.setAttribute('opacity', '0');
      parentEl.appendChild(circle);
      particles.push({
        el: circle,
        t: i / count,
        speed: 0.12 + Math.random() * 0.03
      });
    }
    return particles;
  }

  // === 伞齿轮对 ===
  let hsBevelH, hsBevelV, lsBevelH, lsBevelV;
  let planetaryData;

  // === 初始化 ===
  function init() {
    // HS 伞齿轮
    hsBevelH = createBevelGearSection('hs-bevel-h', 0, 0, true, 'rgba(255,87,34,0.3)', 30);
    hsBevelV = createBevelGearSection('hs-bevel-v', 0, 0, false, 'rgba(255,87,34,0.25)', 26);

    // LS 伞齿轮
    lsBevelH = createBevelGearSection('ls-bevel-h', 0, 0, true, 'rgba(0,229,160,0.3)', 30);
    lsBevelV = createBevelGearSection('ls-bevel-v', 0, 0, false, 'rgba(0,229,160,0.25)', 26);

    // 行星齿轮组
    planetaryData = createPlanetaryGroup();

    // 创建动力流粒子
    const hsP = createParticles('power-flow-hs', hsPath, 'var(--hs)', 14);
    hsParticles.push(...hsP);
    const lsP = createParticles('power-flow-ls', lsPath, 'var(--ls)', 14);
    lsParticles.push(...lsP);

    // 设置控件
    setupControls();

    // 开始动画
    requestAnimationFrame(animate);
  }

  // === 控件设置 ===
  function setupControls() {
    const hsSlider = document.getElementById('hs-rpm');
    const lsSlider = document.getElementById('ls-rpm');
    const hsVal = document.getElementById('hs-rpm-val');
    const lsVal = document.getElementById('ls-rpm-val');
    const hsLabel = document.getElementById('hs-rpm-label');
    const lsLabel = document.getElementById('ls-rpm-label');
    const flowBtn = document.getElementById('flow-btn');
    const clearanceBtn = document.getElementById('clearance-btn');
    const pauseBtn = document.getElementById('pause-btn');

    hsSlider.addEventListener('input', () => {
      CFG.hsRPM = parseInt(hsSlider.value);
      hsVal.textContent = CFG.hsRPM;
      hsLabel.textContent = CFG.hsRPM + ' RPM';
    });

    lsSlider.addEventListener('input', () => {
      CFG.lsRPM = parseInt(lsSlider.value);
      lsVal.textContent = CFG.lsRPM;
      lsLabel.textContent = CFG.lsRPM + ' RPM';
    });

    flowBtn.addEventListener('click', () => {
      CFG.showFlow = !CFG.showFlow;
      flowBtn.classList.toggle('active', CFG.showFlow);
      document.getElementById('power-flow-hs').style.display = CFG.showFlow ? '' : 'none';
      document.getElementById('power-flow-ls').style.display = CFG.showFlow ? '' : 'none';
    });

    clearanceBtn.addEventListener('click', () => {
      CFG.showClearance = !CFG.showClearance;
      clearanceBtn.classList.toggle('active', CFG.showClearance);
      document.getElementById('clearance-group').setAttribute('visibility', CFG.showClearance ? 'visible' : 'hidden');
    });

    pauseBtn.addEventListener('click', () => {
      CFG.paused = !CFG.paused;
      pauseBtn.classList.toggle('paused', CFG.paused);
      pauseBtn.textContent = CFG.paused ? '继续' : '暂停';
    });
  }

  // === 更新旋转标记 ===
  function updateShaftMarks(angle, isHS) {
    const marks = document.getElementById(isHS ? 'shaft-marks' : 'sleeve-marks');
    const lines = marks.querySelectorAll('line');
    const cx = 600;
    const r = isHS ? 11 : 22;
    lines.forEach((line, i) => {
      const baseY = isHS
        ? [460, 490, 540, 580][i]
        : [470, 530, 500, 560][i];
      const dir = (i % 2 === 0) ? -1 : 1;
      const a = angle * (isHS ? 1 : -0.5) + i * 1.2;
      const xOff = Math.sin(a) * r;
      line.setAttribute('x1', cx + xOff - (isHS ? 11 : 22));
      line.setAttribute('x2', cx + xOff - (isHS ? 11 : 22) + 4);
    });
  }

  // === 更新旋转弧线指示器 ===
  function updateRotationArcs() {
    const hsArc = document.getElementById('hs-rot-arc');
    const lsArc = document.getElementById('ls-rot-arc');

    // 分散盘旋转弧
    const hsCx = 600, hsCy = 639, hsR = 52;
    const hsStartAngle = hsAngle * 0.3;
    const hsEndAngle = hsStartAngle + Math.PI * 0.8;
    const x1 = hsCx + hsR * Math.cos(hsStartAngle);
    const y1 = hsCy + hsR * Math.sin(hsStartAngle);
    const x2 = hsCx + hsR * Math.cos(hsEndAngle);
    const y2 = hsCy + hsR * Math.sin(hsEndAngle);
    hsArc.setAttribute('d', `M${x1.toFixed(1)},${y1.toFixed(1)} A${hsR},${hsR} 0 0,1 ${x2.toFixed(1)},${y2.toFixed(1)}`);

    // 刮壁框旋转弧
    const lsCx = 600, lsCy = 625, lsR = 80;
    const lsStartAngle = -lsAngle * 0.15;
    const lsEndAngle = lsStartAngle + Math.PI * 0.6;
    const lx1 = lsCx + lsR * Math.cos(lsStartAngle);
    const ly1 = lsCy + lsR * Math.sin(lsStartAngle);
    const lx2 = lsCx + lsR * Math.cos(lsEndAngle);
    const ly2 = lsCy + lsR * Math.sin(lsEndAngle);
    lsArc.setAttribute('d', `M${lx1.toFixed(1)},${ly1.toFixed(1)} A${lsR},${lsR} 0 0,0 ${lx2.toFixed(1)},${ly2.toFixed(1)}`);
  }

  // === 动画主循环 ===
  function animate(timestamp) {
    if (prevTime === 0) prevTime = timestamp;
    const dt = Math.min((timestamp - prevTime) / 1000, 0.1);
    prevTime = timestamp;

    if (!CFG.paused) {
      globalTime += dt;

      // 更新齿轮角度(按RPM比例缩放,视觉上降速以便观察)
      const visualScale = 0.003;
      hsAngle += (CFG.hsRPM / 60) * dt * Math.PI * 2 * visualScale;
      lsAngle += (CFG.lsRPM / 60) * dt * Math.PI * 2 * visualScale;

      // 更新伞齿轮旋转
      const hsBevelHGroup = document.getElementById('hs-bevel-h');
      const hsBevelVGroup = document.getElementById('hs-bevel-v');
      const lsBevelHGroup = document.getElementById('ls-bevel-h');
      const lsBevelVGroup = document.getElementById('ls-bevel-v');

      hsBevelHGroup.setAttribute('transform', `rotate(${(hsAngle * 180 / Math.PI).toFixed(1)},320,324)`);
      hsBevelVGroup.setAttribute('transform', `rotate(${(hsAngle * 180 / Math.PI * 0.6).toFixed(1)},320,370)`);
      lsBevelHGroup.setAttribute('transform', `rotate(${(lsAngle * 180 / Math.PI).toFixed(1)},880,324)`);
      lsBevelVGroup.setAttribute('transform', `rotate(${(lsAngle * 180 / Math.PI * 0.6).toFixed(1)},880,370)`);

      // 更新太阳轮旋转
      if (planetaryData && planetaryData.sunGear) {
        const sunPath = planetaryData.sunGear.path;
        const sunAngle = (hsAngle * 180 / Math.PI).toFixed(1);
        sunPath.setAttribute('transform', `translate(${planetaryData.sunGear.cx},${planetaryData.sunGear.cy}) rotate(${sunAngle})`);
      }

      // 更新行星齿轮自转
      if (planetaryData && planetaryData.planetGears) {
        planetaryData.planetGears.forEach((pg, i) => {
          const pAngle = (-hsAngle * 0.6 * 180 / Math.PI + i * 120).toFixed(1);
          pg.path.setAttribute('transform', `translate(${pg.x},${pg.y}) rotate(${pAngle})`);
        });
      }

      // 更新输出工具旋转
      const scraperGroup = document.getElementById('scraper-group');
      const disperserGroup = document.getElementById('disperser-group');
      const lsRotDeg = (lsAngle * 180 / Math.PI * -0.5).toFixed(1);
      const hsRotDeg = (hsAngle * 180 / Math.PI).toFixed(1);
      scraperGroup.setAttribute('transform', `rotate(${lsRotDeg},600,625)`);
      disperserGroup.setAttribute('transform', `rotate(${hsRotDeg},600,639)`);

      // 更新旋转弧线
      updateRotationArcs();

      // 更新动力流粒子
      if (CFG.showFlow) {
        const hsSpeed = Math.max(CFG.hsRPM / 1200, 0.1);
        const lsSpeed = Math.max(CFG.lsRPM / 200, 0.1);

        hsParticles.forEach(p => {
          p.t += p.speed * hsSpeed * dt;
          if (p.t > 1) p.t -= 1;
          const pos = interpolatePath(hsPath, p.t);
          p.el.setAttribute('cx', pos.x.toFixed(1));
          p.el.setAttribute('cy', pos.y.toFixed(1));
          // 在路径两端淡入淡出
          const fade = Math.min(p.t * 5, (1 - p.t) * 5, 1);
          p.el.setAttribute('opacity', (fade * 0.85).toFixed(2));
          p.el.setAttribute('r', (2 + fade * 1.2).toFixed(1));
        });

        lsParticles.forEach(p => {
          p.t += p.speed * lsSpeed * dt;
          if (p.t > 1) p.t -= 1;
          const pos = interpolatePath(lsPath, p.t);
          p.el.setAttribute('cx', pos.x.toFixed(1));
          p.el.setAttribute('cy', pos.y.toFixed(1));
          const fade = Math.min(p.t * 5, (1 - p.t) * 5, 1);
          p.el.setAttribute('opacity', (fade * 0.85).toFixed(2));
          p.el.setAttribute('r', (2 + fade * 1.2).toFixed(1));
        });
      }

      // 径向游隙闪烁效果
      if (CFG.showClearance) {
        const pulse = 0.5 + 0.5 * Math.sin(globalTime * 4);
        const clearanceGroup = document.getElementById('clearance-group');
        clearanceGroup.setAttribute('opacity', (0.6 + pulse * 0.4).toFixed(2));
      }
    }

    requestAnimationFrame(animate);
  }

  // 启动
  init();
})();
</script>
</body>
</html>

实现说明:

这是一个基于 SVG + 原生 JavaScript 的交互式原理动画,聚焦展示"并行分流式叠加减速箱"的最终理想解工作原理:

视觉架构:

  • 深色工业蓝图风格背景,带微网格纹理营造工程制图氛围
  • 高速通路(橙色 #ff5722)与低速通路(青绿色 #00e5a0)双色编码,贯穿从电机输入到输出工具的完整路径
  • 扁平箱体剖面采用渐变填充+剖面线纹理,强调"紧凑轴向高度"这一核心 IFR 特征

核心动画:

  1. 伞齿轮对旋转 — 左右两组伞齿轮分别按高速/低速比转动,展示 90° 空间换向
  2. 行星齿轮同轴汇合 — 中心太阳轮(橙色/高速→35mm轴)与外齿圈(青绿色/低速→60mm轴套)可视化分离传动
  3. 输出工具差速旋转 — 分散盘(高速)与刮壁框(低速)独立旋转,旋转弧线指示方向
  4. 动力流粒子 — 14 个粒子沿各自路径流动,速度随 RPM 滑块实时变化,两端自动淡入淡出

交互控件:

  • 高速/低速 RPM 滑块 — 实时调节电机转速,齿轮旋转速度与粒子流速同步响应
  • 动力流按钮 — 切换粒子流可见性
  • 径向游隙按钮 — 激活后高亮 Ø60 轴套与 Ø35 实心轴之间的 0.15mm 游隙区域,含 50× 放大截面图与脉冲动画
  • 暂停/继续 — 冻结/恢复全部动画
积分规则:第一轮对话扣减6分,后续每轮扣4分