分享图
A
动画渲染工坊
就绪
<!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 rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Rajdhani:wght@400;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
<style>
*{margin:0;padding:0;box-sizing:border-box}
:root{
  --bg:#060a14;--bg2:#0c1222;--card:#111a2e;--card-b:#1c2a44;
  --t1:#e2e8f0;--t2:#8ea4c0;--t3:#546580;
  --accent:#00e5ff;--accent2:#00b8d4;--accent-dim:rgba(0,229,255,.12);
  --mr-liq:#ff9f43;--mr-sol:#4a9ebb;
  --memb:rgba(255,140,155,.6);--pcb:#22c55e;--pcb2:#166534;
  --ok:#10b981;--warn:#f59e0b;--err:#ef4444;
}
body{background:var(--bg);color:var(--t1);font-family:'Noto Sans SC',sans-serif;min-height:100vh;display:flex;flex-direction:column;align-items:center;overflow-x:hidden}
.page{width:100%;max-width:1280px;padding:20px 16px 32px}
header{text-align:center;margin-bottom:12px}
header h1{font-family:'Rajdhani',sans-serif;font-weight:700;font-size:clamp(22px,3.2vw,36px);letter-spacing:2px;background:linear-gradient(135deg,var(--accent),#80ffea);-webkit-background-clip:text;-webkit-text-fill-color:transparent;margin-bottom:4px}
header p{font-size:13px;color:var(--t3);letter-spacing:1px}
.svg-wrap{background:var(--bg2);border:1px solid var(--card-b);border-radius:14px;overflow:hidden;position:relative;margin-bottom:16px}
.svg-wrap svg{display:block;width:100%;height:auto}
.info-row{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:14px}
.info-card{flex:1;min-width:200px;background:var(--card);border:1px solid var(--card-b);border-radius:10px;padding:14px 16px;transition:border-color .3s}
.info-card.active{border-color:var(--accent)}
.info-card h3{font-family:'Rajdhani',sans-serif;font-size:14px;color:var(--accent);margin-bottom:6px;letter-spacing:1px}
.info-card p{font-size:13px;color:var(--t2);line-height:1.6}
.ifr-tag{display:inline-block;background:linear-gradient(135deg,var(--accent-dim),rgba(0,229,255,.05));border:1px solid rgba(0,229,255,.25);border-radius:4px;padding:2px 8px;font-size:11px;color:var(--accent);margin-top:6px;letter-spacing:.5px}
.ctrl-row{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
.btn{font-family:'Rajdhani',sans-serif;font-weight:600;font-size:13px;padding:7px 18px;border-radius:7px;border:1px solid var(--card-b);background:var(--card);color:var(--t2);cursor:pointer;transition:all .2s;letter-spacing:.5px;user-select:none}
.btn:hover{border-color:var(--accent);color:var(--t1)}
.btn.active{background:rgba(0,229,255,.1);border-color:var(--accent);color:var(--accent)}
.btn.play{min-width:90px}
.phase-dots{display:flex;gap:6px;align-items:center}
.phase-dot{width:10px;height:10px;border-radius:50%;background:var(--card-b);border:1.5px solid var(--t3);transition:all .3s;cursor:pointer}
.phase-dot.done{background:var(--accent2);border-color:var(--accent)}
.phase-dot.current{background:var(--accent);border-color:var(--accent);box-shadow:0 0 8px var(--accent)}
.slider-group{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--t2)}
.slider-group label{white-space:nowrap;min-width:80px}
.slider-group input[type=range]{-webkit-appearance:none;width:120px;height:4px;background:var(--card-b);border-radius:2px;outline:none}
.slider-group input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;border-radius:50%;background:var(--accent);cursor:pointer;border:none}
.slider-group span{min-width:36px;text-align:right;font-family:'Rajdhani',sans-serif;color:var(--accent)}
.params{display:flex;gap:16px;flex-wrap:wrap;margin-top:12px;padding-top:10px;border-top:1px solid var(--card-b)}
.param{font-size:11px;color:var(--t3)}.param b{color:var(--t2);font-weight:500}
@media(max-width:640px){.info-row{flex-direction:column}.ctrl-row{flex-direction:column;align-items:stretch}}
</style>
</head>
<body>
<div class="page">
<header>
  <h1>MAGNETORHEOLOGICAL ADAPTIVE BRACKET</h1>
  <p>磁流变柔性自适应托架 · IFR 最终理想解原理动画</p>
</header>

<div class="svg-wrap">
<svg id="mainSvg" viewBox="0 0 1200 680" xmlns="http://www.w3.org/2000/svg">
<defs>
  <!-- 蜂窝图案 -->
  <pattern id="honeycomb" x="0" y="0" width="22" height="19" patternUnits="userSpaceOnUse">
    <polygon points="11,0 22,5.5 22,13.5 11,19 0,13.5 0,5.5" fill="none" stroke="#556677" stroke-width=".5" opacity=".35"/>
  </pattern>
  <!-- 铜走线图案 -->
  <pattern id="copperTraces" x="0" y="0" width="40" height="18" patternUnits="userSpaceOnUse">
    <line x1="0" y1="6" x2="40" y2="6" stroke="#c87533" stroke-width=".8" opacity=".3"/>
    <line x1="0" y1="14" x2="40" y2="14" stroke="#c87533" stroke-width=".6" opacity=".2"/>
    <circle cx="20" cy="10" r="1.5" fill="#c87533" opacity=".25"/>
  </pattern>
  <!-- 发光滤镜 -->
  <filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
    <feGaussianBlur stdDeviation="4" result="blur"/>
    <feComposite in="SourceGraphic" in2="blur" operator="over"/>
  </filter>
  <filter id="glowStrong" x="-50%" y="-50%" width="200%" height="200%">
    <feGaussianBlur stdDeviation="8" result="blur"/>
    <feComposite in="SourceGraphic" in2="blur" operator="over"/>
  </filter>
  <!-- MR流体渐变(液态) -->
  <linearGradient id="mrLiqGrad" x1="0" y1="0" x2="0" y2="1">
    <stop offset="0%" stop-color="#ffbe76"/>
    <stop offset="100%" stop-color="#ff793f"/>
  </linearGradient>
  <!-- MR流体渐变(固态) -->
  <linearGradient id="mrSolGrad" x1="0" y1="0" x2="0" y2="1">
    <stop offset="0%" stop-color="#5dade2"/>
    <stop offset="100%" stop-color="#2e86c1"/>
  </linearGradient>
  <!-- 流体裁剪 -->
  <clipPath id="fluidClip"><path id="fluidClipPath" d=""/></clipPath>
  <!-- 磁力线标记 -->
  <marker id="arrowCyan" viewBox="0 0 6 6" refX="3" refY="3" markerWidth="4" markerHeight="4" orient="auto">
    <path d="M0,0 L6,3 L0,6 Z" fill="#00e5ff" opacity=".6"/>
  </marker>
</defs>

<!-- 背景网格 -->
<g opacity=".08">
  <line x1="0" y1="340" x2="1200" y2="340" stroke="#00e5ff" stroke-width=".5" stroke-dasharray="4 8"/>
  <line x1="600" y1="0" x2="600" y2="680" stroke="#00e5ff" stroke-width=".5" stroke-dasharray="4 8"/>
</g>

<!-- 左侧导轨 -->
<g id="rails" opacity=".5">
  <rect x="218" y="120" width="8" height="480" rx="2" fill="#1c2a44" stroke="#2a3a55" stroke-width=".5"/>
  <rect x="974" y="120" width="8" height="480" rx="2" fill="#1c2a44" stroke="#2a3a55" stroke-width=".5"/>
  <text x="222" y="110" font-size="9" fill="#546580" font-family="Rajdhani" text-anchor="middle">GUIDE</text>
  <text x="978" y="110" font-size="9" fill="#546580" font-family="Rajdhani" text-anchor="middle">GUIDE</text>
</g>

<!-- 机械臂横梁 -->
<g id="armCrossbar">
  <rect x="210" y="125" width="780" height="14" rx="3" fill="#1a2540" stroke="#2a3a55" stroke-width="1"/>
  <rect x="580" y="112" width="40" height="18" rx="4" fill="#0d1825" stroke="#2a3a55" stroke-width="1"/>
  <text x="600" y="125" font-size="8" fill="#546580" font-family="Rajdhani" text-anchor="middle">ACTUATOR</text>
</g>

<!-- 连接杆(从横梁到托架) -->
<g id="armConnectors">
  <rect id="connL" x="280" y="139" width="6" height="60" rx="1" fill="#1a2540" stroke="#2a3a55" stroke-width=".5"/>
  <rect id="connR" x="914" y="139" width="6" height="60" rx="1" fill="#1a2540" stroke="#2a3a55" stroke-width=".5"/>
</g>

<!-- ===== 托架组件组(整体可移动) ===== -->
<g id="bracketGroup">

  <!-- 基板 -->
  <rect id="basePlate" x="250" y="358" width="700" height="30" rx="2" fill="#8899aa" stroke="#667788" stroke-width="1"/>
  <rect id="baseHoneycomb" x="250" y="358" width="700" height="30" rx="2" fill="url(#honeycomb)"/>
  <text x="600" y="377" font-size="9" fill="#334455" font-family="Rajdhani" text-anchor="middle" font-weight="600" letter-spacing="2">ALUMINUM HONEYCOMB BASE</text>

  <!-- 电磁铁阵列 -->
  <g id="electromagnets"></g>

  <!-- MR流体区域 -->
  <path id="mrFluid" d="" fill="url(#mrLiqGrad)" opacity=".85"/>

  <!-- MR流体粒子(在裁剪区内) -->
  <g clip-path="url(#fluidClip)">
    <g id="mrParticles"></g>
  </g>

  <!-- 硅胶膜 -->
  <path id="membrane" d="" fill="rgba(255,140,155,.22)" stroke="rgba(255,140,155,.7)" stroke-width="2.5"/>

</g>

<!-- ===== PCB组件 ===== -->
<g id="pcbGroup">
  <!-- PCB弯曲指示线 -->
  <path id="bendLine" d="" fill="none" stroke="#ef4444" stroke-width="1.5" stroke-dasharray="6 4" opacity="0"/>

  <!-- PCB板 -->
  <rect id="pcbBoard" x="250" y="248" width="700" height="18" rx="1" fill="#166534" stroke="#22c55e" stroke-width=".8"/>
  <rect x="250" y="248" width="700" height="18" rx="1" fill="url(#copperTraces)"/>
  <text x="600" y="261" font-size="9" fill="#4ade80" font-family="Rajdhani" text-anchor="middle" font-weight="600" letter-spacing="3">PCB — 13kg</text>

  <!-- 底部元器件 -->
  <g id="components"></g>
</g>

<!-- 均匀支撑力箭头 -->
<g id="forceArrows" opacity="0"></g>

<!-- 磁力线 -->
<g id="fieldLines" opacity="0"></g>

<!-- 标注文字 -->
<g id="annotations" font-family="'Noto Sans SC',sans-serif"></g>

<!-- 相位标签 -->
<g id="phaseLabel" font-family="'Rajdhani',sans-serif">
  <rect x="20" y="20" width="200" height="36" rx="6" fill="rgba(0,229,255,.08)" stroke="rgba(0,229,255,.25)" stroke-width="1"/>
  <text id="phaseText" x="120" y="43" font-size="14" fill="#00e5ff" text-anchor="middle" font-weight="600" letter-spacing="1"></text>
</g>

<!-- 挠度指示 -->
<g id="deflection" opacity="0" font-family="Rajdhani,sans-serif">
  <rect x="980" y="240" width="140" height="30" rx="5" fill="rgba(239,68,68,.1)" stroke="rgba(239,68,68,.3)" stroke-width="1"/>
  <text id="deflText" x="1050" y="260" font-size="12" fill="#ef4444" text-anchor="middle" font-weight="600"></text>
</g>

</svg>
</div>

<!-- 信息面板 -->
<div class="info-row">
  <div class="info-card" id="cardMech">
    <h3>MECHANISM / 核心机理</h3>
    <p>磁流变液在磁场下毫秒级固化,使柔性托架瞬间从"液态自适应"转为"刚性定制模具",实现全表面均匀支撑。</p>
    <span class="ifr-tag">IFR: 流体自适应 = 自动寻优支撑面</span>
  </div>
  <div class="info-card" id="cardIFR">
    <h3>IFR INSIGHT / 理想解洞察</h3>
    <p id="ifrText">等待动画启动…</p>
    <span class="ifr-tag" id="ifrTag">—</span>
  </div>
  <div class="info-card" id="cardParam">
    <h3>KEY PARAMS / 关键参数</h3>
    <p>固化响应 ≤50ms | 硅胶膜 2mm | 电磁铁间距 20mm</p>
    <p style="margin-top:4px;font-size:11px;color:var(--t3)">边界:高温PCB不适用;尖锐元器件可能刺破硅胶膜</p>
  </div>
</div>

<!-- 控制面板 -->
<div class="ctrl-row">
  <button class="btn play" id="btnPlay" onclick="togglePlay()">▶ 自动播放</button>
  <button class="btn" onclick="resetAnim()">↺ 重置</button>
  <div class="phase-dots" id="phaseDots"></div>
  <div class="slider-group">
    <label>磁场强度</label>
    <input type="range" id="sliderField" min="0" max="100" value="0" oninput="onFieldSlider(this.value)">
    <span id="fieldVal">0%</span>
  </div>
  <div class="slider-group">
    <label>动画速度</label>
    <input type="range" id="sliderSpeed" min="25" max="200" value="100" oninput="onSpeedSlider(this.value)">
    <span id="speedVal">1.0x</span>
  </div>
</div>
<div class="params">
  <span class="param">基板: 铝制蜂窝 <b>轻量化</b></span>
  <span class="param">填充: 磁流变液 <b>MR Fluid</b></span>
  <span class="param">表面: 弹性硅胶膜 <b>2mm</b></span>
  <span class="param">阵列: 微型电磁铁 <b>20mm间距</b></span>
</div>
</div>

<script>
/* =========================================
   磁流变柔性自适应托架 · IFR原理动画引擎
   ========================================= */

const SVG_NS = 'http://www.w3.org/2000/svg';
const $ = id => document.getElementById(id);

// ---- 常量 ----
const PCB = { x:250, y:248, w:700, h:18 };
const PCB_BOT = PCB.y + PCB.h; // 266

const COMPS = [
  { x:325, w:55, h:38, label:'电解电容', clr:'#252535', clr2:'#353548' },
  { x:468, w:42, h:18, label:'贴片IC',   clr:'#1a1a2e', clr2:'#2a2a40' },
  { x:592, w:68, h:44, label:'功率模块', clr:'#252535', clr2:'#353548' },
  { x:778, w:48, h:24, label:'连接器',   clr:'#2a2a28', clr2:'#3a3a35' },
];

const BASE_Y = 358;       // 基板顶面(接触位)
const BASE_H = 30;
const BRK_L = PCB.x, BRK_R = PCB.x + PCB.w;
const INIT_OFFSET = 130;  // 初始间距

const PHASES = [
  { name:'待机就绪',   desc:'柔性托架位于PCB下方待机位', ifr:'准备阶段:托架呈液态柔性', tag:'STANDBY' },
  { name:'下降贴合',   desc:'机械手下降,硅胶膜接触PCB底面', ifr:'流体自然贴合——无需计算支撑点', tag:'APPROACH' },
  { name:'自适应塑形', desc:'微抽空气,液态托架完美贴合底部异形轮廓', ifr:'理想解核心:流体自动填充所有间隙,100%吻合', tag:'CONFORM' },
  { name:'磁场固化',   desc:'电磁铁通电,磁流变液≤50ms固化成刚性模具', ifr:'无形资源(磁场)瞬间锁定理想形态——极简触发', tag:'SOLIDIFY' },
  { name:'提升取板',   desc:'全表面刚性均匀支撑,安全提升无应力集中', ifr:'矛盾消除:柔性适应 + 刚性支撑,同时实现', tag:'LIFT' },
  { name:'释放分离',   desc:'到位断电,磁流变液恢复液态,轻松脱模', ifr:'可逆转换:同一资源,按需在柔/刚间切换', tag:'RELEASE' },
];

// ---- 状态 ----
let phase = 0, progress = 0, playing = false, speed = 1;
let fieldStr = 0, conformity = 0, solidify = 0, bracketOff = INIT_OFFSET, liftOff = 0;
let lastTs = 0;
let particles = [];
let animId = null;

// ---- 初始化 ----
function init() {
  createComponents();
  createElectromagnets();
  createParticles();
  createPhaseDots();
  updateAll();
}

function createComponents() {
  const g = $('components');
  COMPS.forEach((c,i) => {
    const y = PCB_BOT;
    // 元器件主体
    const r = document.createElementNS(SVG_NS,'rect');
    r.setAttribute('x', c.x); r.setAttribute('y', y);
    r.setAttribute('width', c.w); r.setAttribute('height', c.h);
    r.setAttribute('rx', 2); r.setAttribute('fill', c.clr);
    r.setAttribute('stroke', c.clr2); r.setAttribute('stroke-width', '1');
    r.id = 'comp'+i;
    g.appendChild(r);
    // 引脚
    const pins = 3 + Math.floor(Math.random()*3);
    for(let p=0;p<pins;p++){
      const px = c.x + 4 + p * ((c.w-8)/(pins-1));
      const ln = document.createElementNS(SVG_NS,'line');
      ln.setAttribute('x1',px); ln.setAttribute('y1',y);
      ln.setAttribute('x2',px); ln.setAttribute('y2',y+5);
      ln.setAttribute('stroke','#888'); ln.setAttribute('stroke-width','1.5');
      g.appendChild(ln);
    }
    // 标签
    const t = document.createElementNS(SVG_NS,'text');
    t.setAttribute('x', c.x + c.w/2); t.setAttribute('y', y + c.h/2 + 3);
    t.setAttribute('font-size','7'); t.setAttribute('fill','#667');
    t.setAttribute('text-anchor','middle'); t.setAttribute('font-family','Rajdhani');
    t.textContent = c.label;
    g.appendChild(t);
  });
}

function createElectromagnets() {
  const g = $('electromagnets');
  const spacing = 35; // 视觉间距
  const y = BASE_Y + BASE_H/2;
  for(let x = BRK_L + 20; x < BRK_R - 10; x += spacing) {
    // 外圈
    const c1 = document.createElementNS(SVG_NS,'circle');
    c1.setAttribute('cx',x); c1.setAttribute('cy',y);
    c1.setAttribute('r',5); c1.setAttribute('fill','none');
    c1.setAttribute('stroke','#b87333'); c1.setAttribute('stroke-width','1.2');
    c1.classList.add('em-coil');
    g.appendChild(c1);
    // 内芯
    const c2 = document.createElementNS(SVG_NS,'circle');
    c2.setAttribute('cx',x); c2.setAttribute('cy',y);
    c2.setAttribute('r',2); c2.setAttribute('fill','#8b5e3c');
    c2.classList.add('em-core');
    g.appendChild(c2);
    // 发光圈(初始隐藏)
    const c3 = document.createElementNS(SVG_NS,'circle');
    c3.setAttribute('cx',x); c3.setAttribute('cy',y);
    c3.setAttribute('r',8); c3.setAttribute('fill','none');
    c3.setAttribute('stroke','#00e5ff'); c3.setAttribute('stroke-width','1');
    c3.setAttribute('opacity','0'); c3.classList.add('em-glow');
    g.appendChild(c3);
  }
}

function createParticles() {
  const g = $('mrParticles');
  particles = [];
  const count = 70;
  for(let i=0;i<count;i++){
    const px = BRK_L + 20 + Math.random()*(BRK_R - BRK_L - 40);
    const py = PCB_BOT + 10 + Math.random()*80;
    const c = document.createElementNS(SVG_NS,'circle');
    c.setAttribute('cx',px); c.setAttribute('cy',py);
    const r = 1.5 + Math.random()*2.5;
    c.setAttribute('r', r);
    c.setAttribute('fill','#ffbe76'); c.setAttribute('opacity','0.7');
    g.appendChild(c);
    particles.push({
      el:c, bx:px, by:py, x:px, y:py,
      r, vx:(Math.random()-.5)*1.2, vy:(Math.random()-.5)*1.2,
      tx:0, ty:0 // 固化目标位置
    });
  }
  // 设置固化目标(网格排列)
  const cols = 14, rows = 5;
  const gapX = (BRK_R - BRK_L - 40)/cols, gapY = 70/rows;
  particles.forEach((p,i) => {
    const col = i % cols, row = Math.floor(i/cols) % rows;
    p.tx = BRK_L + 20 + col*gapX + gapX/2;
    p.ty = PCB_BOT + 15 + row*gapY + gapY/2;
  });
}

function createPhaseDots() {
  const d = $('phaseDots');
  PHASES.forEach((_,i) => {
    const dot = document.createElement('div');
    dot.className = 'phase-dot'; dot.dataset.idx = i;
    dot.onclick = () => jumpToPhase(i);
    dot.title = PHASES[i].name;
    d.appendChild(dot);
  });
}

// ---- 路径生成 ----
function getMembranePath(conf, off) {
  // conf: 0=平直 1=完全贴合; off: 托架垂直偏移
  const baseY = PCB_BOT + off; // 膜顶部基准
  let d = `M ${BRK_L} ${baseY}`;
  let cx = BRK_L;
  COMPS.forEach(c => {
    const compBot = PCB_BOT + c.h;
    const targetBot = baseY + c.h * conf;
    // 平直段到组件左侧
    const ease = 8;
    d += ` L ${c.x - ease} ${baseY}`;
    // 圆弧下降到组件底部
    d += ` C ${c.x} ${baseY}, ${c.x} ${targetBot}, ${c.x + 4} ${targetBot}`;
    // 组件底部平直
    d += ` L ${c.x + c.w - 4} ${targetBot}`;
    // 圆弧上升回基准
    d += ` C ${c.x + c.w} ${targetBot}, ${c.x + c.w} ${baseY}, ${c.x + c.w + ease} ${baseY}`;
    cx = c.x + c.w + ease;
  });
  d += ` L ${BRK_R} ${baseY}`;
  return d;
}

function getFluidPath(conf, off) {
  const baseY = PCB_BOT + off;
  const baseInner = BASE_Y + off; // 基板内表面
  const memD = getMembranePath(conf, off);
  // 膜路径 → 右下角 → 基板底 → 左下角 → 闭合
  return memD + ` L ${BRK_R} ${baseInner} L ${BRK_L} ${baseInner} Z`;
}

function getBendPath(amount) {
  // PCB弯曲曲线(抛物线近似)
  if(amount < 0.01) return `M ${BRK_L} ${PCB_BOT} L ${BRK_R} ${PCB_BOT}`;
  const sag = amount * 18; // 最大挠度像素
  const mid = (BRK_L + BRK_R)/2;
  return `M ${BRK_L} ${PCB_BOT} Q ${mid} ${PCB_BOT + sag} ${BRK_R} ${PCB_BOT}`;
}

// ---- 更新视觉 ----
function updateAll() {
  const off = bracketOff - liftOff;

  // 托架组位置
  $('bracketGroup').setAttribute('transform', `translate(0,${off})`);

  // 膜路径(相对于托架组内部坐标,所以不需要off偏移)
  // 注意:在bracketGroup内部,坐标是原始坐标,但group整体移动了off
  // 所以膜路径的y值应该使用PCB_BOT(接触时的位置),而group的transform负责偏移
  const memPath = getMembranePath(conformity, 0);
  $('membrane').setAttribute('d', memPath);

  // MR流体
  const fluidPath = getFluidPath(conformity, 0);
  $('mrFluid').setAttribute('d', fluidPath);
  $('fluidClipPath').setAttribute('d', fluidPath);

  // MR流体颜色(液态→固态渐变)
  const liqR=255,liqG=159,liqB=67, solR=74,solG=158,solB=187;
  const r=Math.round(liqR+(solR-liqR)*solidify);
  const g=Math.round(liqG+(solG-liqG)*solidify);
  const b=Math.round(liqB+(solB-liqB)*solidify);
  const r2=Math.round(255+(46-255)*solidify);
  const g2=Math.round(121+(134-121)*solidify);
  const b2=Math.round(63+(193-63)*solidify);
  $('mrFluid').setAttribute('fill', `url(#mrLiqGrad)`);
  // 动态更新渐变色
  const stops = $('mrLiqGrad').querySelectorAll('stop');
  stops[0].setAttribute('stop-color',`rgb(${r},${g},${b})`);
  stops[1].setAttribute('stop-color',`rgb(${r2},${g2},${b2})`);

  // 膜颜色(贴合时略微更不透明)
  const membAlpha = .22 + conformity * .15;
  const membStroke = .5 + conformity * .3;
  $('membrane').setAttribute('fill', `rgba(255,140,155,${membAlpha})`);
  $('membrane').setAttribute('stroke', `rgba(255,140,155,${membStroke})`);

  // 电磁铁发光
  document.querySelectorAll('.em-glow').forEach(el => {
    el.setAttribute('opacity', fieldStr * .6);
    el.setAttribute('r', 8 + fieldStr * 4);
  });
  document.querySelectorAll('.em-core').forEach(el => {
    if(fieldStr > .3) {
      el.setAttribute('fill', `rgb(${Math.round(139+(0-139)*fieldStr)},${Math.round(94+(229-94)*fieldStr)},${Math.round(60+(255-60)*fieldStr)})`);
    } else {
      el.setAttribute('fill','#8b5e3c');
    }
  });

  // PCB组位置(被提升时)
  $('pcbGroup').setAttribute('transform', `translate(0,${-liftOff})`);

  // 弯曲指示
  const bendAmt = (phase < 4 && phase > 0) ? (1 - conformity * solidify) * 0.6 : (phase === 0 ? 0.8 : 0);
  $('bendLine').setAttribute('d', getBendPath(bendAmt));
  $('bendLine').setAttribute('opacity', bendAmt > 0.05 ? .7 : 0);

  // 挠度指示
  const deflMm = (bendAmt * 3.2).toFixed(1);
  const deflEl = $('deflection');
  if(bendAmt > 0.05) {
    deflEl.setAttribute('opacity','1');
    $('deflText').textContent = `挠度 ${deflMm}mm`;
    $('deflText').setAttribute('fill', bendAmt > .3 ? '#ef4444' : '#f59e0b');
    deflEl.querySelector('rect').setAttribute('fill', bendAmt > .3 ? 'rgba(239,68,68,.1)' : 'rgba(245,158,11,.1)');
    deflEl.querySelector('rect').setAttribute('stroke', bendAmt > .3 ? 'rgba(239,68,68,.3)' : 'rgba(245,158,11,.3)');
  } else {
    deflEl.setAttribute('opacity','0');
  }

  // 力箭头
  updateForceArrows();

  // 磁力线
  updateFieldLines();

  // 粒子
  updateParticles();

  // 连接杆
  const bracketTop = BASE_Y + off;
  const connH = Math.max(10, bracketTop - 139);
  $('connL').setAttribute('height', connH);
  $('connR').setAttribute('height', connH);

  // 相位标签
  $('phaseText').textContent = `${phase+1}/6 — ${PHASES[phase].name}`;

  // 信息卡
  document.querySelectorAll('.info-card').forEach(c => c.classList.remove('active'));
  $('cardIFR').classList.add('active');
  $('ifrText').textContent = PHASES[phase].ifr;
  $('ifrTag').textContent = PHASES[phase].tag;

  // 相位点
  document.querySelectorAll('.phase-dot').forEach((d,i) => {
    d.classList.toggle('done', i < phase);
    d.classList.toggle('current', i === phase);
  });
}

function updateForceArrows() {
  const g = $('forceArrows');
  g.innerHTML = '';
  if(solidify < .5) { g.setAttribute('opacity','0'); return; }
  g.setAttribute('opacity', String((solidify-.5)*2 * (phase===5? Math.max(0,1-progress*3) : 1)));
  const arrowCount = 12;
  const spacing = (BRK_R - BRK_L - 40)/(arrowCount-1);
  for(let i=0;i<arrowCount;i++){
    const ax = BRK_L + 20 + i*spacing;
    const ay = PCB_BOT - 6;
    const ln = document.createElementNS(SVG_NS,'line');
    ln.setAttribute('x1',ax); ln.setAttribute('y1',ay+16);
    ln.setAttribute('x2',ax); ln.setAttribute('y2',ay);
    ln.setAttribute('stroke','#10b981'); ln.setAttribute('stroke-width','1.5');
    ln.setAttribute('marker-end','url(#arrowCyan)');
    // 改为绿色箭头
    ln.setAttribute('stroke','#10b981');
    g.appendChild(ln);
    // 箭头尖
    const pg = document.createElementNS(SVG_NS,'polygon');
    pg.setAttribute('points',`${ax-3},${ay+3} ${ax},${ay-2} ${ax+3},${ay+3}`);
    pg.setAttribute('fill','#10b981');
    g.appendChild(pg);
  }
  // 标注
  const tx = document.createElementNS(SVG_NS,'text');
  tx.setAttribute('x', BRK_L + 10); tx.setAttribute('y', PCB_BOT - 12);
  tx.setAttribute('font-size','9'); tx.setAttribute('fill','#10b981');
  tx.setAttribute('font-family','Rajdhani'); tx.setAttribute('font-weight','600');
  tx.textContent = 'UNIFORM SUPPORT — 0应力集中';
  g.appendChild(tx);
}

function updateFieldLines() {
  const g = $('fieldLines');
  g.innerHTML = '';
  if(fieldStr < .05) { g.setAttribute('opacity','0'); return; }
  g.setAttribute('opacity', String(fieldStr * .7));
  // 从电磁铁向上发出弧形磁力线
  const spacing = 70;
  const y0 = BASE_Y + BASE_H/2;
  for(let x = BRK_L + 50; x < BRK_R - 30; x += spacing){
    for(let dy = -1; dy <= 1; dy += 2){
      const p = document.createElementNS(SVG_NS,'path');
      const h = 30 + fieldStr * 50;
      const cx1 = x + dy*15, cy1 = y0 - h*.4;
      const cx2 = x + dy*8, cy2 = y0 - h*.8;
      p.setAttribute('d',`M ${x} ${y0} C ${cx1} ${cy1}, ${cx2} ${cy2}, ${x+dy*3} ${y0-h}`);
      p.setAttribute('fill','none'); p.setAttribute('stroke','#00e5ff');
      p.setAttribute('stroke-width', String(.6 + fieldStr*.8));
      p.setAttribute('stroke-dasharray','4 3');
      p.setAttribute('opacity', String(.3 + fieldStr*.4));
      g.appendChild(p);
    }
  }
}

function updateParticles() {
  const t = Date.now() * .001;
  particles.forEach(p => {
    if(solidify < .1) {
      // 液态:布朗运动
      p.x += p.vx + Math.sin(t*2 + p.bx)*0.3;
      p.y += p.vy + Math.cos(t*1.7 + p.by)*0.3;
      // 边界弹回(相对于流体区域)
      const minY = PCB_BOT + 5, maxY = BASE_Y - 5;
      const minX = BRK_L + 10, maxX = BRK_R - 10;
      if(p.x < minX || p.x > maxX) p.vx *= -1;
      if(p.y < minY || p.y > maxY) p.vy *= -1;
      p.x = Math.max(minX, Math.min(maxX, p.x));
      p.y = Math.max(minY, Math.min(maxY, p.y));
    } else {
      // 固化中:向目标位置移动
      const lerpSpeed = .02 + solidify * .08;
      p.x += (p.tx - p.x) * lerpSpeed;
      p.y += (p.ty - p.y) * lerpSpeed;
    }
    p.el.setAttribute('cx', p.x);
    p.el.setAttribute('cy', p.y);
    // 颜色
    const liqC = [255,190,118], solC = [93,173,226];
    const cr = Math.round(liqC[0]+(solC[0]-liqC[0])*solidify);
    const cg = Math.round(liqC[1]+(solC[1]-liqC[1])*solidify);
    const cb = Math.round(liqC[2]+(solC[2]-liqC[2])*solidify);
    p.el.setAttribute('fill',`rgb(${cr},${cg},${cb})`);
    p.el.setAttribute('opacity', .5 + solidify * .4);
  });
}

// ---- 动画循环 ----
function animate(ts) {
  if(!lastTs) lastTs = ts;
  const dt = Math.min((ts - lastTs)/1000, .05) * speed;
  lastTs = ts;

  if(playing) {
    progress += dt * .35;
    if(progress >= 1) {
      progress = 0;
      if(phase < 5) { phase++; }
      else { playing = false; progress = 1; updatePlayBtn(); }
    }
    applyPhase();
  } else {
    // 即使暂停,粒子仍需更新(液态时)
    updateParticles();
  }

  updateAll();
  animId = requestAnimationFrame(animate);
}

function applyPhase() {
  const t = easeInOut(progress);
  switch(phase) {
    case 0: // 待机
      bracketOff = INIT_OFFSET;
      conformity = 0; solidify = 0; fieldStr = 0; liftOff = 0;
      break;
    case 1: // 下降贴合
      bracketOff = INIT_OFFSET * (1 - t);
      conformity = 0; solidify = 0; fieldStr = 0; liftOff = 0;
      break;
    case 2: // 自适应塑形
      bracketOff = 0;
      conformity = t;
      solidify = 0; fieldStr = 0; liftOff = 0;
      break;
    case 3: // 磁场固化
      bracketOff = 0; conformity = 1;
      solidify = t; fieldStr = t;
      liftOff = 0;
      break;
    case 4: // 提升取板
      bracketOff = 0; conformity = 1;
      solidify = 1; fieldStr = 1;
      liftOff = t * 80;
      break;
    case 5: // 释放分离
      bracketOff = 0; conformity = 1;
      solidify = Math.max(0, 1 - t*2.5);
      fieldStr = Math.max(0, 1 - t*2.5);
      liftOff = 80;
      if(t > .4) {
        conformity = Math.max(0, 1 - (t-.4)*1.8);
        bracketOff = (t-.4) * 60;
      }
      break;
  }
  // 同步滑块
  $('sliderField').value = Math.round(fieldStr*100);
  $('fieldVal').textContent = Math.round(fieldStr*100)+'%';
}

function easeInOut(t) {
  return t < .5 ? 2*t*t : 1 - Math.pow(-2*t+2,2)/2;
}

// ---- 控制 ----
function togglePlay() {
  playing = !playing;
  if(playing && phase >= 5 && progress >= 1) {
    phase = 0; progress = 0;
  }
  updatePlayBtn();
}

function updatePlayBtn() {
  const btn = $('btnPlay');
  btn.textContent = playing ? '⏸ 暂停' : '▶ 自动播放';
  btn.classList.toggle('active', playing);
}

function resetAnim() {
  playing = false; phase = 0; progress = 0;
  bracketOff = INIT_OFFSET; conformity = 0; solidify = 0; fieldStr = 0; liftOff = 0;
  updatePlayBtn();
  // 重置粒子位置
  particles.forEach(p => {
    p.x = p.bx; p.y = p.by;
    p.vx = (Math.random()-.5)*1.2;
    p.vy = (Math.random()-.5)*1.2;
  });
  updateAll();
}

function jumpToPhase(idx) {
  phase = idx; progress = 0; playing = false;
  // 快速设置该相位初始状态
  switch(idx) {
    case 0: bracketOff=INIT_OFFSET; conformity=0; solidify=0; fieldStr=0; liftOff=0; break;
    case 1: bracketOff=INIT_OFFSET; conformity=0; solidify=0; fieldStr=0; liftOff=0; break;
    case 2: bracketOff=0; conformity=0; solidify=0; fieldStr=0; liftOff=0; break;
    case 3: bracketOff=0; conformity=1; solidify=0; fieldStr=0; liftOff=0; break;
    case 4: bracketOff=0; conformity=1; solidify=1; fieldStr=1; liftOff=0; break;
    case 5: bracketOff=0; conformity=1; solidify=1; fieldStr=1; liftOff=80; break;
  }
  updatePlayBtn();
  updateAll();
}

function onFieldSlider(v) {
  fieldStr = v/100;
  // 如果在固化阶段,同步solidify
  if(phase === 3 || phase === 4) {
    solidify = fieldStr;
  }
  $('fieldVal').textContent = v+'%';
  updateAll();
}

function onSpeedSlider(v) {
  speed = v/100;
  $('speedVal').textContent = speed.toFixed(1)+'x';
}

// ---- 启动 ----
init();
animId = requestAnimationFrame(animate);
</script>
</body>
</html>

这段代码实现了一个完整的磁流变柔性自适应托架 IFR 原理动画,以下是关键设计说明:

视觉设计

  • 深色工程美学风格,以青色(#00e5ff)为核心强调色
  • MR流体液态呈暖琥珀色,固化后过渡为冷钢蓝色,粒子同步从布朗运动转为有序排列
  • 硅胶膜以半透明粉色呈现,贴合度越高越不透明,直观表达"塑形完成"
  • 电磁铁激活时产生青色辉光和磁力线弧,磁场强度与滑块联动

IFR 原理聚焦

  • 直接展示理想解运行过程,无传统方案对比
  • Phase 2(自适应塑形)突出"流体自动填充所有间隙"——无需计算支撑点
  • Phase 3(磁场固化)强调"无形资源瞬间锁定"——极简触发
  • Phase 4(提升取板)显示均匀支撑力箭头 + "0应力集中"标注
  • 弯曲指示线 + 挠度数值实时显示变形消除过程

交互控制

  • 6相位自动播放/暂停,可点击相位圆点跳转
  • 磁场强度滑块可手动控制固化程度,实时影响粒子行为和颜色
  • 动画速度可调(0.25x ~ 2.0x)
  • 粒子系统70个粒子,液态布朗运动 → 固态网格对齐,流畅过渡
积分规则:第一轮对话扣减6分,后续每轮扣4分