分享图
动画工坊
引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>多腔体挤压铝型材电池包边框 · IFR原理动画</title>
<link href="https://fonts.googleapis.com/css2?family=Rajdhani:wght@300;500;700&family=Share+Tech+Mono&display=swap" rel="stylesheet">
<style>
*{margin:0;padding:0;box-sizing:border-box}
:root{
  --bg:#060a12;--grid:#0c1422;--accent:#00e5ff;--gold:#ffd740;
  --hv:#ff4455;--lv:#3399ff;--struct:#c8d4e4;--text:#d8e0f0;
  --dim:#3a4a60;--al-light:#d0d8e8;--al-mid:#9aa8bc;--al-dark:#6a7888;
}
body{background:var(--bg);color:var(--text);font-family:'Rajdhani',sans-serif;
  min-height:100vh;display:flex;flex-direction:column;align-items:center;
  justify-content:center;overflow:hidden;position:relative}
#wrap{width:100vw;height:100vh;position:relative}
svg#scene{width:100%;height:100%;display:block}
.phase-bar{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);
  display:flex;gap:6px;z-index:10}
.phase-dot{width:48px;height:4px;border-radius:2px;background:var(--dim);
  transition:background .4s,box-shadow .4s}
.phase-dot.active{background:var(--accent);box-shadow:0 0 8px var(--accent)}
.phase-dot.done{background:rgba(0,229,255,.35)}
.ctrl-bar{position:fixed;top:20px;right:24px;display:flex;gap:12px;
  align-items:center;z-index:10;font-family:'Share Tech Mono',monospace;font-size:13px}
.ctrl-bar label{color:var(--dim)}
.ctrl-bar input[type=range]{width:80px;accent-color:var(--accent)}
.ctrl-bar button{background:rgba(0,229,255,.1);border:1px solid rgba(0,229,255,.3);
  color:var(--accent);padding:4px 12px;border-radius:4px;cursor:pointer;
  font-family:'Share Tech Mono',monospace;font-size:12px;transition:all .2s}
.ctrl-bar button:hover{background:rgba(0,229,255,.2);border-color:var(--accent)}
.info-tag{position:fixed;top:20px;left:24px;z-index:10;
  font-family:'Share Tech Mono',monospace;font-size:12px;color:var(--dim);
  letter-spacing:.5px}
@keyframes pulseGlow{0%,100%{opacity:.3}50%{opacity:.8}}
@keyframes dashFlow{to{stroke-dashoffset:-24}}
</style>
</head>
<body>
<div id="wrap">
<svg id="scene" viewBox="0 0 1400 900" preserveAspectRatio="xMidYMid meet">
<defs>
  <!-- 网格图案 -->
  <pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
    <path d="M40 0L0 0 0 40" fill="none" stroke="#0e1828" stroke-width=".5"/>
  </pattern>
  <!-- 铝合金渐变 -->
  <linearGradient id="alGrad" x1="0" y1="0" x2=".8" y2="1">
    <stop offset="0%" stop-color="#d4dce8"/><stop offset="35%" stop-color="#b0b8c8"/>
    <stop offset="55%" stop-color="#c4ccd8"/><stop offset="80%" stop-color="#96a0b2"/>
    <stop offset="100%" stop-color="#b8c2d0"/>
  </linearGradient>
  <linearGradient id="alGradV" x1="0" y1="0" x2="0" y2="1">
    <stop offset="0%" stop-color="#c8d0dc"/><stop offset="50%" stop-color="#a8b0c0"/>
    <stop offset="100%" stop-color="#bcc4d2"/>
  </linearGradient>
  <!-- 腔室填充渐变 -->
  <linearGradient id="hvFill" x1="0" y1="0" x2="0" y2="1">
    <stop offset="0%" stop-color="rgba(255,68,85,.22)"/><stop offset="100%" stop-color="rgba(255,68,85,.08)"/>
  </linearGradient>
  <linearGradient id="lvFill" x1="0" y1="0" x2="0" y2="1">
    <stop offset="0%" stop-color="rgba(51,153,255,.22)"/><stop offset="100%" stop-color="rgba(51,153,255,.08)"/>
  </linearGradient>
  <linearGradient id="mainFill" x1="0" y1="0" x2="0" y2="1">
    <stop offset="0%" stop-color="rgba(200,212,228,.1)"/><stop offset="100%" stop-color="rgba(200,212,228,.04)"/>
  </linearGradient>
  <!-- 发光滤镜 -->
  <filter id="glowCyan" x="-50%" y="-50%" width="200%" height="200%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="4" result="b"/>
    <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
  </filter>
  <filter id="glowRed" x="-50%" y="-50%" width="200%" height="200%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="6" result="b"/>
    <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
  </filter>
  <filter id="glowBlue" x="-50%" y="-50%" width="200%" height="200%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="6" result="b"/>
    <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
  </filter>
  <filter id="glowGold" x="-50%" y="-50%" width="200%" height="200%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="5" result="b"/>
    <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
  </filter>
  <filter id="shadowSm">
    <feDropShadow dx="0" dy="2" stdDeviation="3" flood-color="#000" flood-opacity=".4"/>
  </filter>
  <!-- 线束流动标记 -->
  <marker id="arrowCyan" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto">
    <path d="M0,0 L8,3 L0,6" fill="none" stroke="var(--accent)" stroke-width="1"/>
  </marker>
</defs>

<!-- 背景 -->
<rect width="1400" height="900" fill="var(--bg)"/>
<rect width="1400" height="900" fill="url(#grid)"/>

<!-- ====== 标题 ====== -->
<text x="700" y="52" text-anchor="middle" font-family="Rajdhani,sans-serif"
  font-weight="700" font-size="28" fill="var(--text)" letter-spacing="3"
  opacity="0" id="mainTitle">多腔体挤压铝型材 · 三合一电池包边框</text>
<text x="700" y="78" text-anchor="middle" font-family="Share Tech Mono,monospace"
  font-size="13" fill="var(--dim)" letter-spacing="1" opacity="0" id="subTitle">
  IFR: 一材承结构 · 走线 · 吊装 —— 消除独立框架/吊耳/线槽的冗余</text>

<!-- ====== 截面视图 ====== -->
<g id="xsectGroup" transform="translate(330,470)" opacity="0">
  <!-- 型材主体 -->
  <rect x="-250" y="-160" width="500" height="320" rx="2"
    fill="url(#alGrad)" stroke="#7a8a9e" stroke-width="1.2" id="profileBody"/>

  <!-- 低压信号线束腔 -->
  <rect id="lvChamber" x="-236" y="-146" width="130" height="292" rx="1"
    fill="url(#lvFill)" opacity="0"/>
  <!-- 主承重腔 -->
  <rect id="mainChamber" x="-90" y="-146" width="180" height="292" rx="1"
    fill="url(#mainFill)" opacity="0"/>
  <!-- 高压线束腔 -->
  <rect id="hvChamber" x="106" y="-146" width="130" height="292" rx="1"
    fill="url(#hvFill)" opacity="0"/>

  <!-- 内部隔墙 -->
  <rect x="-106" y="-160" width="16" height="320" fill="url(#alGradV)"
    stroke="#7a8a9e" stroke-width=".6" id="partition1" opacity="0"/>
  <rect x="90" y="-160" width="16" height="320" fill="url(#alGradV)"
    stroke="#7a8a9e" stroke-width=".6" id="partition2" opacity="0"/>

  <!-- T型槽 (外左侧壁) -->
  <g id="tSlotGroup" opacity="0">
    <rect x="-250" y="-22" width="18" height="44" fill="var(--bg)"/>
    <rect x="-250" y="-14" width="10" height="28" fill="#0a1020"/>
    <rect x="-250" y="-10" width="26" height="20" rx="1" fill="#0a1020"/>
    <line x1="-250" y1="-22" x2="-250" y2="22" stroke="#5a6a80" stroke-width=".8"/>
    <text x="-268" y="4" text-anchor="end" font-family="Share Tech Mono,monospace"
      font-size="11" fill="var(--accent)">T型槽</text>
    <text x="-268" y="18" text-anchor="end" font-family="Share Tech Mono,monospace"
      font-size="9" fill="var(--dim)">8mm</text>
  </g>

  <!-- 吊装孔 (顶部) -->
  <g id="liftHoleGroup" opacity="0">
    <circle cx="0" cy="-153" r="12" fill="var(--bg)"/>
    <circle cx="0" cy="-160" r="16" fill="#0a1020" stroke="#5a6a80" stroke-width=".6"/>
    <circle cx="0" cy="-153" r="12" fill="none" stroke="#5a6a80" stroke-width=".6"/>
    <!-- 防脱挡圈 -->
    <path d="M-14,-160 A16,16 0 0,1 14,-160" fill="none" stroke="var(--gold)"
      stroke-width="1.5" stroke-dasharray="3,2"/>
    <text x="0" y="-176" text-anchor="middle" font-family="Share Tech Mono,monospace"
      font-size="11" fill="var(--gold)">吊装孔</text>
    <text x="0" y="-190" text-anchor="middle" font-family="Share Tech Mono,monospace"
      font-size="9" fill="var(--dim)">间距 300mm</text>
  </g>

  <!-- 腔室标签 -->
  <g id="chamberLabels" opacity="0">
    <text x="-171" y="-6" text-anchor="middle" font-family="Rajdhani,sans-serif"
      font-weight="500" font-size="14" fill="var(--lv)">低压信号</text>
    <text x="-171" y="12" text-anchor="middle" font-family="Rajdhani,sans-serif"
      font-weight="300" font-size="11" fill="rgba(51,153,255,.6)">线束腔</text>
    <text x="0" y="-6" text-anchor="middle" font-family="Rajdhani,sans-serif"
      font-weight="500" font-size="14" fill="var(--struct)">主承重</text>
    <text x="0" y="12" text-anchor="middle" font-family="Rajdhani,sans-serif"
      font-weight="300" font-size="11" fill="rgba(200,212,228,.5)">结构腔</text>
    <text x="171" y="-6" text-anchor="middle" font-family="Rajdhani,sans-serif"
      font-weight="500" font-size="14" fill="var(--hv)">高压线束</text>
    <text x="171" y="12" text-anchor="middle" font-family="Rajdhani,sans-serif"
      font-weight="300" font-size="11" fill="rgba(255,68,85,.6)">走线腔</text>
  </g>

  <!-- 尺寸标注 -->
  <g id="dimLines" opacity="0">
    <!-- 壁厚标注 -->
    <line x1="252" y1="-160" x2="252" y2="-146" stroke="var(--dim)" stroke-width=".5"/>
    <line x1="248" y1="-160" x2="256" y2="-160" stroke="var(--dim)" stroke-width=".5"/>
    <line x1="248" y1="-146" x2="256" y2="-146" stroke="var(--dim)" stroke-width=".5"/>
    <text x="260" y="-149" font-family="Share Tech Mono,monospace" font-size="9"
      fill="var(--dim)">2.5mm</text>
    <!-- 隔离壁厚 -->
    <line x1="-98" y1="168" x2="-82" y2="168" stroke="var(--dim)" stroke-width=".5"/>
    <line x1="-98" y1="164" x2="-98" y2="172" stroke="var(--dim)" stroke-width=".5"/>
    <line x1="-82" y1="164" x2="-82" y2="172" stroke="var(--dim)" stroke-width=".5"/>
    <text x="-90" y="182" text-anchor="middle" font-family="Share Tech Mono,monospace"
      font-size="9" fill="var(--dim)">3mm</text>
  </g>

  <!-- ====== 线束走线动画路径 ====== -->
  <!-- 高压线束路径 (红色) -->
  <path id="hvWire" d="M236,0 L106,0 C80,0 60,-20 60,-60 L60,-120 C60,-140 40,-146 20,-146 L-200,-146"
    fill="none" stroke="var(--hv)" stroke-width="3" stroke-linecap="round"
    stroke-dasharray="8,16" opacity="0" filter="url(#glowRed)"/>
  <!-- 低压信号线束路径 (蓝色) -->
  <path id="lvWire" d="M-236,20 L-236,80 C-236,100 -220,120 -200,120 L100,120 C120,120 130,110 130,90"
    fill="none" stroke="var(--lv)" stroke-width="2.5" stroke-linecap="round"
    stroke-dasharray="6,12" opacity="0" filter="url(#glowBlue)"/>

  <!-- ====== 吊装钩动画 ====== -->
  <g id="liftHook" transform="translate(0,-160)" opacity="0">
    <line x1="0" y1="-60" x2="0" y2="-20" stroke="#8899aa" stroke-width="2.5"/>
    <path d="M-8,-20 C-8,-6 8,-6 8,-20" fill="none" stroke="var(--gold)"
      stroke-width="3" stroke-linecap="round"/>
    <circle cx="0" cy="-60" r="5" fill="none" stroke="#8899aa" stroke-width="1.5"/>
  </g>

  <!-- ====== T型槽滑块螺母 ====== -->
  <g id="tSlider" opacity="0">
    <rect x="-236" y="-10" width="20" height="20" rx="2" fill="var(--gold)"
      stroke="#b8960a" stroke-width=".8"/>
    <line x1="-226" y1="-4" x2="-226" y2="4" stroke="#8a7000" stroke-width="1.5"/>
    <!-- 螺栓 -->
    <rect x="-230" y="10" width="8" height="18" rx="1" fill="#998866"
      stroke="#776644" stroke-width=".5"/>
    <line x1="-226" y1="10" x2="-226" y2="28" stroke="#665533" stroke-width="1"/>
  </g>
</g>

<!-- ====== 等轴测框架视图 ====== -->
<g id="isoGroup" opacity="0">
  <!-- 由JS动态生成 -->
</g>

<!-- ====== 阶段标签 ====== -->
<text id="phaseLabel" x="700" y="860" text-anchor="middle"
  font-family="Rajdhani,sans-serif" font-weight="700" font-size="20"
  fill="var(--accent)" opacity="0" letter-spacing="2"></text>

<!-- ====== IFR 总结文字 ====== -->
<g id="ifrSummary" opacity="0">
  <text x="700" y="830" text-anchor="middle" font-family="Rajdhani,sans-serif"
    font-weight="700" font-size="22" fill="var(--accent)" letter-spacing="4">
    最终理想解:一材三用 · 消除冗余</text>
  <text x="700" y="856" text-anchor="middle" font-family="Share Tech Mono,monospace"
    font-size="12" fill="var(--dim)" letter-spacing="1">
    结构骨架 ═ 走线通道 ═ 吊装支点 — 零附加零件</text>
</g>

<!-- ====== 力流指示箭头 ====== -->
<g id="forceArrows" opacity="0">
  <!-- 由JS动态生成 -->
</g>

<!-- ====== 高低压隔离指示 ====== -->
<g id="isolationIndicator" opacity="0">
  <rect x="-106" y="-160" width="16" height="320" fill="none"
    stroke="var(--accent)" stroke-width="2" stroke-dasharray="4,4"
    filter="url(#glowCyan)" transform="translate(330,470)"/>
  <rect x="90" y="-160" width="16" height="320" fill="none"
    stroke="var(--accent)" stroke-width="2" stroke-dasharray="4,4"
    filter="url(#glowCyan)" transform="translate(330,470)"/>
  <text x="330" y="290" text-anchor="middle" font-family="Share Tech Mono,monospace"
    font-size="11" fill="var(--accent)" letter-spacing="1">高低压隔离壁</text>
</g>

</svg>
</div>

<!-- 阶段指示条 -->
<div class="phase-bar" id="phaseBar"></div>

<!-- 控制栏 -->
<div class="ctrl-bar">
  <label>速度</label>
  <input type="range" id="speedSlider" min="0.3" max="2" step="0.1" value="1">
  <span id="speedVal" style="color:var(--accent);min-width:32px">1.0x</span>
  <button id="pauseBtn">暂停</button>
  <button id="resetBtn">重置</button>
</div>

<!-- 信息标签 -->
<div class="info-tag" id="infoTag">IFR PRINCIPLE ANIMATION</div>

<script>
(function(){
  /* ===== 常量与配置 ===== */
  const TOTAL = 26000; // 总周期 26s
  const PHASES = [
    {id:'structure', start:0,    end:4500,  label:'型材截面解剖'},
    {id:'chambers',  start:4500, end:9000,  label:'三腔室功能集成'},
    {id:'wiring',    start:9000, end:14500, label:'高低压线束走线'},
    {id:'lifting',   start:14500,end:19500, label:'集成吊装受力'},
    {id:'mounting',  start:19500,end:23500, label:'T型槽滑块固定'},
    {id:'summary',   start:23500,end:26000, label:'最终理想解'}
  ];

  /* ===== DOM引用 ===== */
  const $ = id => document.getElementById(id);
  const svg = $('scene');
  const xsectGroup = $('xsectGroup');
  const isoGroup = $('isoGroup');
  const phaseLabel = $('phaseLabel');
  const ifrSummary = $('ifrSummary');
  const forceArrows = $('forceArrows');
  const isolationIndicator = $('isolationIndicator');

  /* ===== 等轴测投影函数 ===== */
  const ISO_CX = 1080, ISO_CY = 460, ISO_SCALE = 0.75;
  function iso(x, y, z) {
    const px = ISO_CX + (x - y) * 0.866 * ISO_SCALE;
    const py = ISO_CY + (x + y) * 0.5 * ISO_SCALE - z * ISO_SCALE;
    return [px, py];
  }
  function pts(arr){ return arr.map(p => p[0]+','+p[1]).join(' '); }

  /* ===== 构建等轴测框架 ===== */
  function buildIsoFrame(){
    const ns = 'http://www.w3.org/2000/svg';
    // 框架尺寸
    const FW=220, FD=160, FH=55, PT=18;
    // 四根型材梁
    const beams = [
      // 前梁 (沿x)
      {x:0,y:0,w:FW,d:PT,h:FH,color:'url(#alGrad)'},
      // 后梁
      {x:0,y:FD-PT,w:FW,d:PT,h:FH,color:'url(#alGrad)'},
      // 左梁 (沿y)
      {x:0,y:0,w:PT,d:FD,h:FH,color:'url(#alGradV)'},
      // 右梁
      {x:FW-PT,y:0,w:PT,d:FD,h:FH,color:'url(#alGradV)'}
    ];
    const modules = [
      {x:PT+6,y:PT+6,w:FW-2*PT-12,d:FD-2*PT-12,h:FH-10,
        color:'#1a2236',stroke:'#2a3a56'}
    ];

    // 绘制模块(先画,在梁下面)
    modules.forEach(m => {
      const b0=iso(m.x,m.y,m.h), b1=iso(m.x+m.w,m.y,m.h),
            b2=iso(m.x+m.w,m.y+m.d,m.h), b3=iso(m.x,m.y+m.d,m.h);
      const t0=iso(m.x,m.y,0), t1=iso(m.x+m.w,m.y,0),
            t2=iso(m.x+m.w,m.y+m.d,0), t3=iso(m.x,m.y+m.d,0);
      // 顶面
      const topFace = document.createElementNS(ns,'polygon');
      topFace.setAttribute('points',pts([b0,b1,b2,b3]));
      topFace.setAttribute('fill',m.color);
      topFace.setAttribute('stroke',m.stroke);
      topFace.setAttribute('stroke-width','1');
      topFace.setAttribute('opacity','0.6');
      isoGroup.appendChild(topFace);
      // 前面
      const frontFace = document.createElementNS(ns,'polygon');
      frontFace.setAttribute('points',pts([b0,b1,t1,t0]));
      frontFace.setAttribute('fill','#141e30');
      frontFace.setAttribute('stroke',m.stroke);
      frontFace.setAttribute('stroke-width','.8');
      frontFace.setAttribute('opacity','0.7');
      isoGroup.appendChild(frontFace);
      // 右面
      const rightFace = document.createElementNS(ns,'polygon');
      rightFace.setAttribute('points',pts([b1,b2,t2,t1]));
      rightFace.setAttribute('fill','#101828');
      rightFace.setAttribute('stroke',m.stroke);
      rightFace.setAttribute('stroke-width','.8');
      rightFace.setAttribute('opacity','0.5');
      isoGroup.appendChild(rightFace);
      // 模组标签
      const cx = (b0[0]+b2[0])/2, cy = (b0[1]+b2[1])/2;
      const label = document.createElementNS(ns,'text');
      label.setAttribute('x', cx);
      label.setAttribute('y', cy+4);
      label.setAttribute('text-anchor','middle');
      label.setAttribute('font-family','Rajdhani,sans-serif');
      label.setAttribute('font-size','13');
      label.setAttribute('fill','rgba(200,212,228,.5)');
      label.setAttribute('font-weight','500');
      label.textContent = '电芯模组';
      isoGroup.appendChild(label);
    });

    // 绘制梁
    beams.forEach((b,i) => {
      const corners = [
        iso(b.x,b.y,b.h), iso(b.x+b.w,b.y,b.h),
        iso(b.x+b.w,b.y+b.d,b.h), iso(b.x,b.y+b.d,b.h),
        iso(b.x,b.y,0), iso(b.x+b.w,b.y,0),
        iso(b.x+b.w,b.y+b.d,0), iso(b.x,b.y+b.d,0)
      ];
      // 顶面
      const top = document.createElementNS(ns,'polygon');
      top.setAttribute('points',pts([corners[0],corners[1],corners[2],corners[3]]));
      top.setAttribute('fill','#b8c4d4');
      top.setAttribute('stroke','#8898ac');
      top.setAttribute('stroke-width','1');
      top.setAttribute('opacity','0.9');
      top.classList.add('iso-beam-top');
      isoGroup.appendChild(top);
      // 前面
      const front = document.createElementNS(ns,'polygon');
      front.setAttribute('points',pts([corners[4],corners[5],corners[1],corners[0]]));
      front.setAttribute('fill','#8a98ac');
      front.setAttribute('stroke','#7a8898');
      front.setAttribute('stroke-width','.8');
      front.setAttribute('opacity','0.85');
      front.classList.add('iso-beam-front');
      isoGroup.appendChild(front);
      // 右面
      const right = document.createElementNS(ns,'polygon');
      right.setAttribute('points',pts([corners[5],corners[6],corners[2],corners[1]]));
      right.setAttribute('fill','#6a7888');
      right.setAttribute('stroke','#5a6878');
      right.setAttribute('stroke-width','.8');
      right.setAttribute('opacity','0.75');
      right.classList.add('iso-beam-right');
      isoGroup.appendChild(right);
    });

    // 角件标记
    const corners3d = [[0,0],[FW-PT,0],[FW-PT,FD-PT],[0,FD-PT]];
    corners3d.forEach(c => {
      const [px,py] = iso(c[0]+PT/2, c[1]+PT/2, FH+2);
      const circle = document.createElementNS(ns,'circle');
      circle.setAttribute('cx',px); circle.setAttribute('cy',py);
      circle.setAttribute('r','4');
      circle.setAttribute('fill','var(--accent)');
      circle.setAttribute('opacity','0.7');
      circle.classList.add('iso-corner');
      isoGroup.appendChild(circle);
    });

    // 等轴测标签
    const [lx,ly] = iso(FW/2, -20, FH+20);
    const isoLabel = document.createElementNS(ns,'text');
    isoLabel.setAttribute('x', lx);
    isoLabel.setAttribute('y', ly);
    isoLabel.setAttribute('text-anchor','middle');
    isoLabel.setAttribute('font-family','Share Tech Mono,monospace');
    isoLabel.setAttribute('font-size','12');
    isoLabel.setAttribute('fill','var(--dim)');
    isoLabel.textContent = '等轴测装配视图';
    isoGroup.appendChild(isoLabel);
  }

  /* ===== 构建阶段指示条 ===== */
  function buildPhaseBar(){
    const bar = $('phaseBar');
    PHASES.forEach((p,i) => {
      const dot = document.createElement('div');
      dot.className = 'phase-dot';
      dot.id = 'pdot-'+i;
      dot.title = p.label;
      bar.appendChild(dot);
    });
  }

  /* ===== 辅助动画函数 ===== */
  function ease(t){ return t<.5?2*t*t:-1+(4-2*t)*t; }
  function lerp(a,b,t){ return a+(b-a)*t; }
  function clamp01(t){ return Math.max(0,Math.min(1,t)); }
  function fadeIn(el,dur,delay){
    el.style.transition = `opacity ${dur}ms ease ${delay}ms`;
    el.setAttribute('opacity','1');
  }
  function fadeOut(el,dur){
    el.style.transition = `opacity ${dur}ms ease`;
    el.setAttribute('opacity','0');
  }
  function setOp(el,v){ el.setAttribute('opacity',String(v)); }

  /* ===== 动画状态 ===== */
  let startTime = null;
  let paused = false;
  let pauseTime = 0;
  let speed = 1;
  let rafId = null;

  /* ===== 阶段更新函数 ===== */
  function updatePhase(elapsed){
    const t = elapsed % TOTAL;
    let phaseIdx = PHASES.length - 1;
    for(let i=0;i<PHASES.length;i++){
      if(t >= PHASES[i].start && t < PHASES[i].end){ phaseIdx = i; break; }
    }
    const phase = PHASES[phaseIdx];
    const progress = clamp01((t - phase.start)/(phase.end - phase.start));

    // 更新阶段指示条
    PHASES.forEach((p,i) => {
      const dot = $('pdot-'+i);
      if(!dot) return;
      dot.className = 'phase-dot' + (i<phaseIdx?' done':'') + (i===phaseIdx?' active':'');
    });

    // 更新阶段标签
    phaseLabel.textContent = phase.label;
    setOp(phaseLabel, progress < 0.1 ? ease(progress/0.1) : (progress > 0.9 ? ease((1-progress)/0.1) : 1));

    // 根据阶段执行动画
    switch(phase.id){
      case 'structure': animStructure(progress, t); break;
      case 'chambers':  animChambers(progress, t); break;
      case 'wiring':    animWiring(progress, t); break;
      case 'lifting':   animLifting(progress, t); break;
      case 'mounting':  animMounting(progress, t); break;
      case 'summary':   animSummary(progress, t); break;
    }
  }

  /* ===== 阶段1: 型材截面解剖 ===== */
  let structureInit = false;
  function animStructure(p, t){
    if(!structureInit){
      structureInit = true;
      // 重置所有元素
      setOp(xsectGroup, 1);
      setOp($('profileBody'), 1);
      setOp($('lvChamber'), 0);
      setOp($('mainChamber'), 0);
      setOp($('hvChamber'), 0);
      setOp($('partition1'), 0);
      setOp($('partition2'), 0);
      setOp($('tSlotGroup'), 0);
      setOp($('liftHoleGroup'), 0);
      setOp($('chamberLabels'), 0);
      setOp($('dimLines'), 0);
      setOp($('hvWire'), 0);
      setOp($('lvWire'), 0);
      setOp($('liftHook'), 0);
      setOp($('tSlider'), 0);
      setOp(isoGroup, 0);
      setOp(ifrSummary, 0);
      setOp(forceArrows, 0);
      setOp(isolationIndicator, 0);
      setOp($('mainTitle'), 0);
      setOp($('subTitle'), 0);
    }
    // 标题淡入
    setOp($('mainTitle'), clamp01(p/0.15));
    setOp($('subTitle'), clamp01((p-0.05)/0.15));
    // 截面组淡入
    setOp(xsectGroup, clamp01(p/0.1));
    // 隔墙出现
    setOp($('partition1'), clamp01((p-0.15)/0.1));
    setOp($('partition2'), clamp01((p-0.2)/0.1));
    // 尺寸标注
    setOp($('dimLines'), clamp01((p-0.4)/0.15));
    // T型槽
    setOp($('tSlotGroup'), clamp01((p-0.6)/0.12));
    // 吊装孔
    setOp($('liftHoleGroup'), clamp01((p-0.75)/0.12));
    // 等轴测框架淡入
    setOp(isoGroup, clamp01((p-0.5)/0.2));
  }

  /* ===== 阶段2: 三腔室功能集成 ===== */
  let chambersInit = false;
  function animChambers(p, t){
    if(!chambersInit){
      chambersInit = true;
      // 确保基础元素可见
      setOp(xsectGroup, 1);
      setOp($('partition1'), 1);
      setOp($('partition2'), 1);
      setOp($('dimLines'), 1);
      setOp(isoGroup, 1);
    }
    // 三个腔室依次高亮
    const lvP  = clamp01((p - 0.0) / 0.2);
    const mainP = clamp01((p - 0.25) / 0.2);
    const hvP  = clamp01((p - 0.5) / 0.2);

    setOp($('lvChamber'), lvP);
    setOp($('mainChamber'), mainP);
    setOp($('hvChamber'), hvP);

    // 标签
    setOp($('chamberLabels'), clamp01((p - 0.6) / 0.15));

    // 高低压隔离指示 (后期出现)
    setOp(isolationIndicator, clamp01((p - 0.75) / 0.15));
  }

  /* ===== 阶段3: 高低压线束走线 ===== */
  let wiringInit = false;
  function animWiring(p, t){
    if(!wiringInit){
      wiringInit = true;
      setOp($('lvChamber'), 1);
      setOp($('mainChamber'), 1);
      setOp($('hvChamber'), 1);
      setOp($('chamberLabels'), 1);
      setOp(isolationIndicator, 0.8);
    }
    // 高压线动画 (红色)
    const hvP = clamp01((p - 0.05) / 0.4);
    setOp($('hvWire'), hvP > 0 ? 0.9 : 0);
    if(hvP > 0){
      const wire = $('hvWire');
      const len = wire.getTotalLength ? wire.getTotalLength() : 400;
      wire.setAttribute('stroke-dashoffset', String(-t/40));
    }
    // 低压线动画 (蓝色)
    const lvP = clamp01((p - 0.3) / 0.4);
    setOp($('lvWire'), lvP > 0 ? 0.9 : 0);
    if(lvP > 0){
      const wire = $('lvWire');
      wire.setAttribute('stroke-dashoffset', String(-t/50));
    }
    // 隔离壁闪烁强调
    if(p > 0.7){
      const blink = 0.5 + 0.5 * Math.sin(t / 200);
      setOp(isolationIndicator, blink * 0.8);
    }
  }

  /* ===== 阶段4: 集成吊装受力 ===== */
  let liftingInit = false;
  function animLifting(p, t){
    if(!liftingInit){
      liftingInit = true;
      setOp($('hvWire'), 0.6);
      setOp($('lvWire'), 0.6);
      setOp(isolationIndicator, 0.3);
      // 线束停止流动
    }
    // 吊钩下降
    const hookP = clamp01(p / 0.3);
    const hookY = lerp(-50, 0, ease(hookP));
    $('liftHook').setAttribute('transform', `translate(0,${-160 + hookY - 10})`);
    setOp($('liftHook'), clamp01(p / 0.15));

    // 框架微微抬起 (表示受力)
    if(p > 0.4){
      const liftP = ease(clamp01((p - 0.4) / 0.25));
      const liftY = -8 * liftP + Math.sin(t/300) * 1.5 * liftP;
      xsectGroup.setAttribute('transform', `translate(330,${470 + liftY})`);
      isoGroup.setAttribute('transform', `translate(0,${liftY})`);
    }

    // 力流箭头
    setOp(forceArrows, clamp01((p - 0.5) / 0.15));
    if(p > 0.5 && forceArrows.childElementCount === 0){
      buildForceArrows();
    }
  }

  /* ===== 阶段5: T型槽滑块固定 ===== */
  let mountingInit = false;
  function animMounting(p, t){
    if(!mountingInit){
      mountingInit = true;
      // 恢复框架位置
      xsectGroup.setAttribute('transform', 'translate(330,470)');
      isoGroup.setAttribute('transform', 'translate(0,0)');
      setOp($('liftHook'), 0.4);
    }
    // T型槽高亮
    setOp($('tSlotGroup'), 0.5 + 0.5 * Math.sin(t / 200));

    // 滑块螺母滑入
    const sliderP = ease(clamp01((p - 0.1) / 0.35));
    const sliderX = lerp(-300, -236, sliderP);
    $('tSlider').setAttribute('transform', `translate(${sliderX - (-236)},0)`);
    setOp($('tSlider'), clamp01(p / 0.1));

    // 底板 (在等轴测视图中)
    if(p > 0.6 && !document.querySelector('.base-plate')){
      buildBasePlate();
    }
  }

  /* ===== 阶段6: 最终理想解 ===== */
  let summaryInit = false;
  function animSummary(p, t){
    if(!summaryInit){
      summaryInit = true;
    }
    // 所有功能同时高亮
    setOp($('lvChamber'), 0.8 + 0.2 * Math.sin(t/300));
    setOp($('mainChamber'), 0.8 + 0.2 * Math.sin(t/300 + 1));
    setOp($('hvChamber'), 0.8 + 0.2 * Math.sin(t/300 + 2));
    setOp($('chamberLabels'), 1);
    setOp($('tSlotGroup'), 0.7 + 0.3 * Math.sin(t/250));
    setOp($('liftHoleGroup'), 0.7 + 0.3 * Math.sin(t/250 + 1));
    setOp($('hvWire'), 0.6);
    setOp($('lvWire'), 0.6);
    $('hvWire').setAttribute('stroke-dashoffset', String(-t/40));
    $('lvWire').setAttribute('stroke-dashoffset', String(-t/50));

    // IFR总结
    setOp(ifrSummary, ease(clamp01(p / 0.3)));

    // 重置标记(为循环准备)
    if(p > 0.95){
      structureInit = false;
      chambersInit = false;
      wiringInit = false;
      liftingInit = false;
      mountingInit = false;
      summaryInit = false;
      // 清理力箭头和底板
      forceArrows.innerHTML = '';
      const bp = document.querySelector('.base-plate');
      if(bp) bp.remove();
      xsectGroup.setAttribute('transform', 'translate(330,470)');
      isoGroup.setAttribute('transform', 'translate(0,0)');
    }
  }

  /* ===== 构建力流箭头 ===== */
  function buildForceArrows(){
    const ns = 'http://www.w3.org/2000/svg';
    // 向下的力 (重力)
    const arrow1 = document.createElementNS(ns,'polygon');
    arrow1.setAttribute('points','326,280 334,280 330,300');
    arrow1.setAttribute('fill','var(--gold)');
    arrow1.setAttribute('opacity','0.8');
    forceArrows.appendChild(arrow1);
    // 向上的反力 (吊装)
    const arrow2 = document.createElementNS(ns,'polygon');
    arrow2.setAttribute('points','326,260 334,260 330,240');
    arrow2.setAttribute('fill','var(--accent)');
    arrow2.setAttribute('opacity','0.8');
    forceArrows.appendChild(arrow2);
    // 力传递路径 (在截面内向下)
    const path = document.createElementNS(ns,'line');
    path.setAttribute('x1','330'); path.setAttribute('y1','300');
    path.setAttribute('x2','330'); path.setAttribute('y2','360');
    path.setAttribute('stroke','var(--gold)');
    path.setAttribute('stroke-width','2');
    path.setAttribute('stroke-dasharray','4,3');
    path.setAttribute('opacity','0.6');
    forceArrows.appendChild(path);
    // 力流标注
    const label = document.createElementNS(ns,'text');
    label.setAttribute('x','348'); label.setAttribute('y','330');
    label.setAttribute('font-family','Share Tech Mono,monospace');
    label.setAttribute('font-size','10');
    label.setAttribute('fill','var(--gold)');
    label.textContent='力流传导';
    forceArrows.appendChild(label);
  }

  /* ===== 构建底板 ===== */
  function buildBasePlate(){
    const ns = 'http://www.w3.org/2000/svg';
    const g = document.createElementNS(ns,'g');
    g.classList.add('base-plate');
    // 底板 (等轴测)
    const p0=iso(-20,FD+10,-5), p1=iso(FW+20,FD+10,-5),
          p2=iso(FW+20,-10,-5), p3=iso(-20,-10,-5);
    const plate = document.createElementNS(ns,'polygon');
    plate.setAttribute('points',pts([p0,p1,p2,p3]));
    plate.setAttribute('fill','rgba(30,50,70,.6)');
    plate.setAttribute('stroke','rgba(60,90,120,.5)');
    plate.setAttribute('stroke-width','1');
    g.appendChild(plate);
    // 底板标签
    const cx=(p0[0]+p2[0])/2, cy=(p0[1]+p2[1])/2;
    const label = document.createElementNS(ns,'text');
    label.setAttribute('x',cx); label.setAttribute('y',cy+4);
    label.setAttribute('text-anchor','middle');
    label.setAttribute('font-family','Share Tech Mono,monospace');
    label.setAttribute('font-size','11');
    label.setAttribute('fill','rgba(100,140,180,.6)');
    label.textContent='设备底盘';
    g.appendChild(label);
    // 连接螺栓 (从T型槽到底板)
    const boltPositions = [[PT/2, PT/2], [PT/2, FD-PT/2],
                           [FW-PT/2, PT/2], [FW-PT/2, FD-PT/2]];
    boltPositions.forEach(bp => {
      const [bx, by] = iso(bp[0], bp[1], -5);
      const [tx, ty] = iso(bp[0], bp[1], 0);
      const bolt = document.createElementNS(ns,'line');
      bolt.setAttribute('x1',tx); bolt.setAttribute('y1',ty);
      bolt.setAttribute('x2',bx); bolt.setAttribute('y2',by);
      bolt.setAttribute('stroke','var(--gold)');
      bolt.setAttribute('stroke-width','2');
      bolt.setAttribute('opacity','0.6');
      g.appendChild(bolt);
    });
    isoGroup.appendChild(g);
  }

  /* ===== 主动画循环 ===== */
  function animate(now){
    if(!startTime) startTime = now;
    if(paused){ rafId = requestAnimationFrame(animate); return; }
    const elapsed = (now - startTime) * speed;
    updatePhase(elapsed);
    rafId = requestAnimationFrame(animate);
  }

  /* ===== 控件事件 ===== */
  $('speedSlider').addEventListener('input', function(){
    speed = parseFloat(this.value);
    $('speedVal').textContent = speed.toFixed(1) + 'x';
  });
  $('pauseBtn').addEventListener('click', function(){
    paused = !paused;
    this.textContent = paused ? '继续' : '暂停';
    if(!paused){
      // 调整startTime以保持连续性
      startTime = performance.now() - (pauseTime / speed) * speed;
    } else {
      pauseTime = performance.now() - startTime;
    }
  });
  $('resetBtn').addEventListener('click', function(){
    startTime = performance.now();
    paused = false;
    $('pauseBtn').textContent = '暂停';
    // 重置所有初始化标记
    structureInit = chambersInit = wiringInit = liftingInit = mountingInit = summaryInit = false;
    forceArrows.innerHTML = '';
    const bp = document.querySelector('.base-plate');
    if(bp) bp.remove();
    xsectGroup.setAttribute('transform','translate(330,470)');
    isoGroup.setAttribute('transform','translate(0,0)');
  });

  /* ===== 初始化 ===== */
  function init(){
    buildIsoFrame();
    buildPhaseBar();
    rafId = requestAnimationFrame(animate);
  }

  // 页面加载后自动启动
  if(document.readyState === 'loading'){
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }
  // 确保重载时也能自动播放
  window.addEventListener('load', function(){
    if(!startTime){
      startTime = performance.now();
      if(!rafId) rafId = requestAnimationFrame(animate);
    }
  });
})();
</script>
</body>
</html>

实现说明

动画核心设计思路:基于 TRIZ "最终理想解 (IFR)" 思想,整个动画聚焦于展示型材"一材三用"的理想状态——结构骨架、走线通道、吊装支点三合一,而非前后对比。

六阶段自动循环动画(26秒一周期):

  1. 截面解剖:型材截面主体绘制,隔墙、T型槽、吊装孔依次显现,等轴测框架同步淡入
  2. 三腔室集成:低压信号腔(蓝)、主承重腔(银)、高压线束腔(红)依次高亮填充,高低压隔离壁闪烁强调
  3. 线束走线:红色高压线与蓝色低压线以流动虚线动画沿各自腔室穿行,隔离壁脉冲闪烁突出防干扰核心
  4. 集成吊装:吊钩下降穿入吊装孔,框架微微抬起并伴有呼吸式振动,力流箭头指示传力路径
  5. T型槽固定:滑块螺母从侧方滑入T型槽并锁紧,等轴测视图出现设备底盘与连接螺栓
  6. 最终理想解:所有功能同时呼吸式高亮,IFR 总结文字浮现——"一材三用 · 消除冗余"

交互控制:右上角提供速度滑块(0.3x–2x)、暂停/继续和重置按钮;底部阶段指示条实时标记当前进度。

视觉特色:深色工业蓝图风格,铝合金金属渐变截面,红蓝双色线束流动,青色/金色高亮引导视觉焦点,等轴测投影提供三维装配语境。

积分规则:第一轮对话扣减8分,后续每轮扣6分