独立渲染引擎就绪引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<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=Syne:wght@400;600;700;800&family=IBM+Plex+Mono:wght@300;400;500;600&display=swap" rel="stylesheet">
<style>
:root{--bg:#090d13;--fg:#d4d8e0;--muted:#5c6370;--accent:#e8a225;--accent2:#0fa67a;--card:#111820;--border:#1c2533;--red:#d94040;--glow-amber:rgba(232,162,37,.35);--glow-teal:rgba(15,166,122,.3)}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--fg);font-family:'IBM Plex Mono',monospace;min-height:100vh;display:flex;flex-direction:column;align-items:center;overflow-x:hidden}
body::before{content:'';position:fixed;inset:0;background:radial-gradient(ellipse at 25% 15%,rgba(232,162,37,.04) 0%,transparent 55%),radial-gradient(ellipse at 75% 85%,rgba(15,166,122,.04) 0%,transparent 55%);pointer-events:none;z-index:0}
.wrap{position:relative;z-index:1;width:100%;max-width:1140px;padding:1.8rem 1.2rem 2.5rem}
header{text-align:center;margin-bottom:1.2rem}
header h1{font-family:'Syne',sans-serif;font-weight:800;font-size:clamp(1.3rem,3vw,2rem);letter-spacing:-.02em;background:linear-gradient(135deg,var(--accent),var(--accent2));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
header p{font-size:.72rem;color:var(--muted);margin-top:.35rem;font-weight:300;letter-spacing:.03em}
.svg-box{width:100%;display:flex;justify-content:center;margin-bottom:1.2rem}
.svg-box svg{width:100%;max-width:1060px;height:auto;display:block}
.controls{display:flex;align-items:center;gap:1rem;justify-content:center;flex-wrap:wrap;margin-bottom:1.3rem}
.cg{display:flex;align-items:center;gap:.6rem;background:var(--card);border:1px solid var(--border);border-radius:7px;padding:.5rem .9rem}
.cg label{font-size:.7rem;color:var(--muted);white-space:nowrap}
.cg input[type=range]{width:160px;accent-color:var(--accent);cursor:pointer}
.cg .val{font-size:.75rem;color:var(--accent);min-width:36px;text-align:right;font-weight:500}
.mbtn{background:var(--card);border:1px solid var(--border);color:var(--fg);font-family:'IBM Plex Mono',monospace;font-size:.7rem;padding:.5rem .9rem;border-radius:7px;cursor:pointer;transition:all .2s}
.mbtn:hover{border-color:var(--accent);color:var(--accent)}
.mbtn.on{background:rgba(232,162,37,.08);border-color:var(--accent);color:var(--accent)}
.si{display:flex;align-items:center;gap:.45rem;background:var(--card);border:1px solid var(--border);border-radius:7px;padding:.5rem .9rem}
.sd{width:8px;height:8px;border-radius:50%;background:#22c55e;transition:background .3s}
.sd.locked{background:#ef4444}
.sd.trans{background:var(--accent);animation:pulse .45s ease-in-out infinite alternate}
@keyframes pulse{from{opacity:.45}to{opacity:1}}
.st{font-size:.7rem;color:var(--fg)}
.info{display:grid;grid-template-columns:repeat(auto-fit,minmax(195px,1fr));gap:.8rem}
.ic{background:var(--card);border:1px solid var(--border);border-radius:7px;padding:.85rem 1rem}
.ic h3{font-family:'Syne',sans-serif;font-size:.78rem;font-weight:600;color:var(--accent);margin-bottom:.35rem}
.ic p{font-size:.66rem;color:var(--muted);line-height:1.55}
@media(max-width:640px){.cg input[type=range]{width:110px}.controls{gap:.6rem}}
@media(prefers-reduced-motion:reduce){*{animation-duration:.01ms!important;transition-duration:.01ms!important}}
</style>
</head>
<body>
<div class="wrap">
<header>
<h1>十字滑台无级锁定机构</h1>
<p>单线控双轴 · 楔块自锁 · 摩擦片无级压紧 — IFR 原理动画</p>
</header>
<div class="svg-box">
<svg id="mech" viewBox="0 0 960 560" xmlns="http://www.w3.org/2000/svg">
<defs>
<!-- 背景网格 -->
<pattern id="grid" width="30" height="30" patternUnits="userSpaceOnUse">
<path d="M30 0L0 0 0 30" fill="none" stroke="#151d28" stroke-width=".4"/>
</pattern>
<!-- 摩擦面发光 -->
<filter id="glowA" x="-40%" y="-40%" width="180%" height="180%">
<feGaussianBlur in="SourceGraphic" stdDeviation="6" result="b"/>
<feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
<filter id="glowT" x="-40%" y="-40%" width="180%" height="180%">
<feGaussianBlur in="SourceGraphic" stdDeviation="5" result="b"/>
<feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
<!-- 箭头标记 -->
<marker id="arrG" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto">
<path d="M0,0 L8,3 L0,6" fill="#22c55e"/>
</marker>
<marker id="arrR" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto">
<path d="M0,0 L8,3 L0,6" fill="#ef4444"/>
</marker>
<!-- 渐变 -->
<linearGradient id="padGrad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#c87a15"/>
<stop offset="50%" stop-color="#e8a225"/>
<stop offset="100%" stop-color="#c87a15"/>
</linearGradient>
<linearGradient id="wedgeGrad" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#0fa67a"/>
<stop offset="100%" stop-color="#0b7d5e"/>
</linearGradient>
<linearGradient id="baseGrad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#2a3444"/>
<stop offset="100%" stop-color="#1e2632"/>
</linearGradient>
<linearGradient id="plateGrad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#1a3356"/>
<stop offset="100%" stop-color="#132847"/>
</linearGradient>
</defs>
<!-- 背景 -->
<rect width="960" height="560" fill="#0a0f16"/>
<rect width="960" height="560" fill="url(#grid)" opacity=".6"/>
<!-- ========== 主截面视图 ========== -->
<g id="mainView">
<!-- 标题 -->
<text x="310" y="35" fill="#5c6370" font-family="Syne,sans-serif" font-size="13" font-weight="600" text-anchor="middle" letter-spacing=".08em">SIDE CROSS-SECTION</text>
<text x="310" y="52" fill="#3a4250" font-family="IBM Plex Mono,monospace" font-size="9" text-anchor="middle">侧视截面 · 楔块锁定原理</text>
<!-- 固定座(外框) -->
<rect x="110" y="70" width="400" height="430" rx="5" fill="url(#baseGrad)" stroke="#3a4558" stroke-width="2"/>
<!-- 内腔 -->
<rect x="130" y="90" width="360" height="390" rx="3" fill="#0d1219" stroke="#252e3b" stroke-width=".8"/>
<!-- 左壁内表面高亮线 -->
<line id="wallL" x1="135" y1="95" x2="135" y2="475" stroke="#3a4558" stroke-width="1.5"/>
<!-- 右壁内表面高亮线 -->
<line id="wallR" x1="485" y1="95" x2="485" y2="475" stroke="#3a4558" stroke-width="1.5"/>
<!-- 固定座标注 -->
<text x="310" y="86" fill="#4a5568" font-size="8" text-anchor="middle" font-family="IBM Plex Mono,monospace">固定座 (接椅背)</text>
<!-- 滑动板(可漂移) -->
<g id="plateGroup">
<rect id="plate" x="175" y="130" width="270" height="310" rx="3" fill="url(#plateGrad)" stroke="#2b5a8a" stroke-width="1.2" opacity=".85"/>
<!-- 十字导轨示意 (水平) -->
<rect id="railH1" x="195" y="185" width="230" height="5" rx="2" fill="#1e3a5f" stroke="#2b5a8a" stroke-width=".5"/>
<rect id="railH2" x="195" y="380" width="230" height="5" rx="2" fill="#1e3a5f" stroke="#2b5a8a" stroke-width=".5"/>
<!-- 十字导轨示意 (垂直) -->
<rect id="railV1" x="220" y="150" width="5" height="270" rx="2" fill="#1e3a5f" stroke="#2b5a8a" stroke-width=".5"/>
<rect id="railV1b" x="395" y="150" width="5" height="270" rx="2" fill="#1e3a5f" stroke="#2b5a8a" stroke-width=".5"/>
<!-- 滑动板标注 -->
<text x="310" y="170" fill="#5a8ab5" font-size="8" text-anchor="middle" font-family="IBM Plex Mono,monospace">滑动板 (接腰靠)</text>
<!-- 中央楔槽 -->
<rect x="280" y="130" width="60" height="310" rx="2" fill="#090d13" stroke="#1c2533" stroke-width=".5"/>
<!-- 摩擦片 - 左 -->
<rect id="padL" x="205" y="195" width="75" height="190" rx="2" fill="url(#padGrad)" stroke="#d4911e" stroke-width="1"/>
<!-- 摩擦片 - 右 -->
<rect id="padR" x="340" y="195" width="75" height="190" rx="2" fill="url(#padGrad)" stroke="#d4911e" stroke-width="1"/>
<!-- 摩擦片标注 -->
<text id="padLLabel" x="242" y="295" fill="#0d1219" font-size="7.5" text-anchor="middle" font-weight="500" font-family="IBM Plex Mono,monospace">摩擦片</text>
<text id="padRLabel" x="377" y="295" fill="#0d1219" font-size="7.5" text-anchor="middle" font-weight="500" font-family="IBM Plex Mono,monospace">摩擦片</text>
<!-- 楔块 -->
<polygon id="wedge" points="288,170 332,170 356,350 264,350" fill="url(#wedgeGrad)" stroke="#0fa67a" stroke-width="1.2" stroke-linejoin="round"/>
<!-- 楔块中心线 -->
<line id="wedgeCL" x1="310" y1="170" x2="310" y2="350" stroke="#0fa67a" stroke-width=".4" stroke-dasharray="3,3" opacity=".5"/>
<!-- 楔角标注 -->
<g id="angleAnnotation" opacity=".7">
<path d="M310,310 L330,310" stroke="#0fa67a" stroke-width=".6" fill="none"/>
<path d="M310,310 L310,330" stroke="#0fa67a" stroke-width=".6" fill="none"/>
<path d="M318,310 A8,8 0 0,1 310,318" stroke="#0fa67a" stroke-width=".7" fill="none"/>
<text x="325" y="323" fill="#0fa67a" font-size="8" font-family="IBM Plex Mono,monospace">8°</text>
</g>
<!-- 楔块标注 -->
<text id="wedgeLabel" x="310" y="268" fill="#b5f5e0" font-size="8" text-anchor="middle" font-weight="500" font-family="IBM Plex Mono,monospace">双面楔块</text>
</g>
<!-- 间隙指示器 - 左 -->
<g id="gapL" opacity=".8">
<line id="gapLLine1" x1="135" y1="285" x2="205" y2="285" stroke="#ef4444" stroke-width=".6" stroke-dasharray="2,2"/>
<line id="gapLLine2" x1="135" y1="280" x2="135" y2="290" stroke="#ef4444" stroke-width=".6"/>
<line id="gapLLine3" x1="205" y1="280" x2="205" y2="290" stroke="#ef4444" stroke-width=".6"/>
<text id="gapLText" x="170" y="278" fill="#ef4444" font-size="7" text-anchor="middle" font-family="IBM Plex Mono,monospace">间隙</text>
</g>
<!-- 间隙指示器 - 右 -->
<g id="gapR" opacity=".8">
<line id="gapRLine1" x1="415" y1="285" x2="485" y2="285" stroke="#ef4444" stroke-width=".6" stroke-dasharray="2,2"/>
<line id="gapRLine2" x1="415" y1="280" x2="415" y2="290" stroke="#ef4444" stroke-width=".6"/>
<line id="gapRLine3" x1="485" y1="280" x2="485" y2="290" stroke="#ef4444" stroke-width=".6"/>
<text id="gapRText" x="450" y="278" fill="#ef4444" font-size="7" text-anchor="middle" font-family="IBM Plex Mono,monospace">间隙</text>
</g>
<!-- 摩擦接触发光层 -->
<rect id="contactGlowL" x="133" y="195" width="4" height="190" rx="1" fill="#e8a225" opacity="0" filter="url(#glowA)"/>
<rect id="contactGlowR" x="483" y="195" width="4" height="190" rx="1" fill="#e8a225" opacity="0" filter="url(#glowA)"/>
<!-- 弹簧 -->
<g id="springGroup">
<path id="spring" d="M310,115 L310,125 M310,125 L300,133 L320,141 L300,149 L320,157 L300,165 L320,173 L310,180" fill="none" stroke="#8b5cf6" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<text x="335" y="150" fill="#8b5cf6" font-size="7" font-family="IBM Plex Mono,monospace" opacity=".7">复位弹簧</text>
</g>
<!-- 线缆 -->
<g id="cableGroup">
<path id="cable" d="M310,350 L310,430 Q310,455 290,470 L180,510" fill="none" stroke="#d94040" stroke-width="1.8" stroke-linecap="round"/>
<circle id="cableEnd" cx="180" cy="510" r="5" fill="#d94040" stroke="#ff6b6b" stroke-width="1"/>
<text x="155" y="528" fill="#d94040" font-size="7.5" font-family="IBM Plex Mono,monospace" text-anchor="middle">线控手柄</text>
</g>
<!-- 力箭头组 -->
<g id="forceArrows" opacity="0">
<!-- 楔块横向推力 - 左 -->
<line id="fArrL1" x1="275" y1="290" x2="220" y2="290" stroke="#22c55e" stroke-width="1.8" marker-end="url(#arrG)"/>
<!-- 楔块横向推力 - 右 -->
<line id="fArrR1" x1="345" y1="290" x2="400" y2="290" stroke="#22c55e" stroke-width="1.8" marker-end="url(#arrG)"/>
<!-- 纵向拉力 -->
<line id="fArrDown" x1="310" y1="360" x2="310" y2="405" stroke="#ef4444" stroke-width="1.5" marker-end="url(#arrR)"/>
<!-- 摩擦力 - 左 -->
<line id="fFricL" x1="138" y1="260" x2="138" y2="320" stroke="#e8a225" stroke-width="1.3" marker-end="url(#arrA)"/>
<line id="fFricL2" x1="138" y1="320" x2="138" y2="260" stroke="#e8a225" stroke-width="1.3"/>
<!-- 摩擦力 - 右 -->
<line id="fFricR" x1="482" y1="260" x2="482" y2="320" stroke="#e8a225" stroke-width="1.3"/>
<line id="fFricR2" x1="482" y1="320" x2="482" y2="260" stroke="#e8a225" stroke-width="1.3"/>
</g>
<!-- 力标注 -->
<g id="forceLabels" opacity="0">
<text id="fLabelL" x="248" y="283" fill="#22c55e" font-size="7.5" font-weight="500" font-family="IBM Plex Mono,monospace">侧向推力</text>
<text id="fLabelR" x="348" y="283" fill="#22c55e" font-size="7.5" font-weight="500" font-family="IBM Plex Mono,monospace">侧向推力</text>
<text id="fLabelD" x="320" y="395" fill="#ef4444" font-size="7.5" font-weight="500" font-family="IBM Plex Mono,monospace">拉力</text>
<text id="fLabelFric" x="140" y="255" fill="#e8a225" font-size="7" font-family="IBM Plex Mono,monospace">摩擦力</text>
</g>
<!-- 锁定状态指示 -->
<g id="lockIndicator" opacity="0">
<rect x="240" y="410" width="140" height="26" rx="4" fill="rgba(239,68,68,.15)" stroke="#ef4444" stroke-width="1"/>
<text x="310" y="427" fill="#ef4444" font-size="10" text-anchor="middle" font-weight="600" font-family="Syne,sans-serif" letter-spacing=".1em">LOCKED</text>
</g>
<!-- 自由状态指示 -->
<g id="freeIndicator" opacity=".7">
<rect x="240" y="410" width="140" height="26" rx="4" fill="rgba(34,197,94,.08)" stroke="#22c55e" stroke-width=".8"/>
<text x="310" y="427" fill="#22c55e" font-size="10" text-anchor="middle" font-weight="600" font-family="Syne,sans-serif" letter-spacing=".1em">FREE</text>
</g>
</g>
<!-- ========== 俯视导轨视图 ========== -->
<g id="topView" transform="translate(610,30)">
<rect x="0" y="0" width="310" height="230" rx="5" fill="#0d1219" stroke="#1c2533" stroke-width="1"/>
<text x="155" y="20" fill="#5c6370" font-size="10" text-anchor="middle" font-weight="600" font-family="Syne,sans-serif" letter-spacing=".06em">TOP VIEW</text>
<text x="155" y="34" fill="#3a4250" font-size="8" text-anchor="middle" font-family="IBM Plex Mono,monospace">俯视 · 十字导轨滑动范围</text>
<!-- 固定座俯视 -->
<rect x="25" y="48" width="260" height="160" rx="3" fill="url(#baseGrad)" stroke="#3a4558" stroke-width="1.2"/>
<!-- X 导轨 -->
<rect x="40" y="95" width="230" height="4" rx="2" fill="#1e3a5f" stroke="#2b5a8a" stroke-width=".5"/>
<rect x="40" y="155" width="230" height="4" rx="2" fill="#1e3a5f" stroke="#2b5a8a" stroke-width=".5"/>
<text x="50" y="92" fill="#2b5a8a" font-size="7" font-family="IBM Plex Mono,monospace">X-rail</text>
<!-- Y 导轨 -->
<rect x="90" y="58" width="4" height="140" rx="2" fill="#1e3a5f" stroke="#2b5a8a" stroke-width=".5"/>
<rect x="216" y="58" width="4" height="140" rx="2" fill="#1e3a5f" stroke="#2b5a8a" stroke-width=".5"/>
<text x="98" y="72" fill="#2b5a8a" font-size="7" font-family="IBM Plex Mono,monospace">Y-rail</text>
<!-- 滑动板俯视 -->
<rect id="topPlate" x="100" y="78" width="110" height="98" rx="3" fill="url(#plateGrad)" stroke="#2b5a8a" stroke-width="1" opacity=".85"/>
<text x="155" y="132" fill="#5a8ab5" font-size="7.5" text-anchor="middle" font-family="IBM Plex Mono,monospace">滑动板</text>
<!-- 滑动范围指示 -->
<rect x="60" y="55" width="190" height="148" rx="2" fill="none" stroke="#e8a225" stroke-width=".5" stroke-dasharray="4,3" opacity=".4"/>
<text x="155" y="215" fill="#e8a225" font-size="7" text-anchor="middle" font-family="IBM Plex Mono,monospace" opacity=".6">8 × 5 cm 滑动范围</text>
<!-- X方向箭头 -->
<line x1="50" y1="220" x2="100" y2="220" stroke="#5c6370" stroke-width=".8" marker-end="url(#arrG)"/>
<text x="75" y="228" fill="#5c6370" font-size="6.5" text-anchor="middle" font-family="IBM Plex Mono,monospace">X</text>
<!-- Y方向箭头 -->
<line x1="280" y1="60" x2="280" y2="110" stroke="#5c6370" stroke-width=".8" marker-end="url(#arrG)"/>
<text x="290" y="90" fill="#5c6370" font-size="6.5" font-family="IBM Plex Mono,monospace">Y</text>
<!-- 中心十字 -->
<line x1="152" y1="123" x2="158" y2="123" stroke="#0fa67a" stroke-width=".6"/>
<line x1="155" y1="120" x2="155" y2="126" stroke="#0fa67a" stroke-width=".6"/>
</g>
<!-- ========== 参数面板 ========== -->
<g id="paramPanel" transform="translate(610,280)">
<rect x="0" y="0" width="310" height="250" rx="5" fill="#0d1219" stroke="#1c2533" stroke-width="1"/>
<text x="155" y="22" fill="#5c6370" font-size="10" text-anchor="middle" font-weight="600" font-family="Syne,sans-serif" letter-spacing=".06em">PARAMETERS</text>
<text x="155" y="36" fill="#3a4250" font-size="8" text-anchor="middle" font-family="IBM Plex Mono,monospace">关键参数与 IFR 分析</text>
<line x1="20" y1="46" x2="290" y2="46" stroke="#1c2533" stroke-width=".5"/>
<!-- 参数1 -->
<circle cx="32" cy="66" r="4" fill="#0fa67a" opacity=".6"/>
<text x="44" y="69" fill="#e8a225" font-size="9" font-weight="500" font-family="IBM Plex Mono,monospace">楔角 = 8°</text>
<text x="44" y="82" fill="#5c6370" font-size="7.5" font-family="IBM Plex Mono,monospace">小于摩擦角 → 自锁条件</text>
<!-- 参数2 -->
<circle cx="32" cy="102" r="4" fill="#e8a225" opacity=".6"/>
<text x="44" y="105" fill="#e8a225" font-size="9" font-weight="500" font-family="IBM Plex Mono,monospace">摩擦片 = 邵氏70A / 1.5mm</text>
<text x="44" y="118" fill="#5c6370" font-size="7.5" font-family="IBM Plex Mono,monospace">聚氨酯涂层 · 柔性面摩擦</text>
<!-- 参数3 -->
<circle cx="32" cy="138" r="4" fill="#8b5cf6" opacity=".6"/>
<text x="44" y="141" fill="#e8a225" font-size="9" font-weight="500" font-family="IBM Plex Mono,monospace">滑动范围 = 8 × 5 cm</text>
<text x="44" y="154" fill="#5c6370" font-size="7.5" font-family="IBM Plex Mono,monospace">十字导轨 · 双轴无级</text>
<line x1="20" y1="168" x2="290" y2="168" stroke="#1c2533" stroke-width=".5"/>
<!-- IFR分析 -->
<text x="155" y="186" fill="#0fa67a" font-size="9" font-weight="600" text-anchor="middle" font-family="Syne,sans-serif" letter-spacing=".05em">IDEAL FINAL RESULT</text>
<text x="22" y="204" fill="#5c6370" font-size="7.5" font-family="IBM Plex Mono,monospace">
<tspan x="22" dy="0">刚性卡扣 → 柔性面摩擦</tspan>
<tspan x="22" dy="14">级差限制 → 任意位置锁定</tspan>
<tspan x="22" dy="14">双轴独立锁 → 单线控双轴</tspan>
<tspan x="22" dy="14" fill="#0fa67a">系统自锁:松手即锁,无需能耗</tspan>
</text>
</g>
<!-- ========== 动作时序 ========== -->
<g id="sequenceBar" transform="translate(610,545)">
<rect x="0" y="0" width="310" height="12" rx="3" fill="#111820" stroke="#1c2533" stroke-width=".5"/>
<rect id="seqProgress" x="1" y="1" width="0" height="10" rx="2" fill="#0fa67a" opacity=".7"/>
<!-- 阶段标记 -->
<line x1="77" y1="0" x2="77" y2="12" stroke="#1c2533" stroke-width=".5"/>
<line x1="155" y1="0" x2="155" y2="12" stroke="#1c2533" stroke-width=".5"/>
<line x1="232" y1="0" x2="232" y2="12" stroke="#1c2533" stroke-width=".5"/>
<text x="38" y="-3" fill="#3a4250" font-size="6" text-anchor="middle" font-family="IBM Plex Mono,monospace">寻位</text>
<text x="116" y="-3" fill="#3a4250" font-size="6" text-anchor="middle" font-family="IBM Plex Mono,monospace">锁定</text>
<text x="193" y="-3" fill="#3a4250" font-size="6" text-anchor="middle" font-family="IBM Plex Mono,monospace">保持</text>
<text x="271" y="-3" fill="#3a4250" font-size="6" text-anchor="middle" font-family="IBM Plex Mono,monospace">释放</text>
</g>
</svg>
</div>
<!-- 控制面板 -->
<div class="controls">
<div class="cg">
<label>线缆拉力</label>
<input type="range" id="tensionSlider" min="0" max="100" value="0">
<span class="val" id="tensionVal">0%</span>
</div>
<button class="mbtn on" id="autoBtn">自动播放</button>
<button class="mbtn" id="manualBtn">手动控制</button>
<div class="si">
<div class="sd" id="stateDot"></div>
<span class="st" id="stateText">自由滑动</span>
</div>
</div>
<!-- 信息卡片 -->
<div class="info">
<div class="ic">
<h3>楔块自锁原理</h3>
<p>楔角 8° 严格小于摩擦角,拉力撤除后楔块无法自行退回,实现零能耗自锁——松手即锁,无需持续施力。</p>
</div>
<div class="ic">
<h3>摩擦片无级锁定</h3>
<p>以面摩擦替代刚性插销,邵氏 70A 聚氨酯涂层提供高摩擦系数与适度弹性,彻底消除级差,实现任意位置锁定。</p>
</div>
<div class="ic">
<h3>单线控双轴同步</h3>
<p>双面楔块将单根线缆的纵向拉力同时转化为两侧横向压紧力,一次操作同时锁定 X/Y 两轴,结构极简。</p>
</div>
<div class="ic">
<h3>IFR 最终理想解</h3>
<p>机构自身「消失」——不增加操作步骤,不引入级差,锁定力由楔块几何与摩擦自动提供,系统在无外部能量时仍保持锁定。</p>
</div>
</div>
</div>
<script>
(function(){
'use strict';
/* ===== 元素引用 ===== */
const $ = id => document.getElementById(id);
const svg = $('mech');
const padL = $('padL'), padR = $('padR');
const wedge = $('wedge');
const plate = $('plate');
const plateGroup = $('plateGroup');
const spring = $('spring');
const cable = $('cable');
const cableEnd = $('cableEnd');
const contactGlowL = $('contactGlowL'), contactGlowR = $('contactGlowR');
const forceArrows = $('forceArrows'), forceLabels = $('forceLabels');
const lockIndicator = $('lockIndicator'), freeIndicator = $('freeIndicator');
const gapL = $('gapL'), gapR = $('gapR');
const topPlate = $('topPlate');
const seqProgress = $('seqProgress');
const tensionSlider = $('tensionSlider'), tensionVal = $('tensionVal');
const autoBtn = $('autoBtn'), manualBtn = $('manualBtn');
const stateDot = $('stateDot'), stateText = $('stateText');
/* ===== 状态 ===== */
let tension = 0; // 0~1 锁紧程度
let autoPlay = true;
let time = 0;
let lastTimestamp = null;
/* ===== 常量 ===== */
const CX = 310; // 楔块中心 X
const PAD_WIDTH = 75;
const PAD_HEIGHT = 190;
const PAD_Y = 195;
const LEFT_WALL = 135;
const RIGHT_WALL = 485;
// 楔块几何 (倒梯形:顶宽底窄,下移时宽部到摩擦片高度 → 推开摩擦片)
const WEDGE_TOP_W = 72; // 顶部宽
const WEDGE_BOT_W = 26; // 底部窄
const WEDGE_H = 170;
const WEDGE_UNLOCKED_TOP_Y = 140; // 未锁定时楔块顶 Y
const WEDGE_TRAVEL = 65; // 最大下移距离
// 摩擦片最大外移量 (让摩擦片恰好贴墙)
const PAD_MAX_SHIFT = 22;
/* ===== 缓动 ===== */
function easeInOut(t){ return t<.5? 4*t*t*t : 1-Math.pow(-2*t+2,3)/2; }
/* ===== 动画周期 (秒) ===== */
const CYCLE = 9;
const P = { free:2, locking:1.5, locked:2.5, unlocking:1.5, free2:1.5 };
/* ===== 更新机构 ===== */
function updateMechanism(t){
// --- 楔块位置 ---
const wedgeTopY = WEDGE_UNLOCKED_TOP_Y + t * WEDGE_TRAVEL;
const wedgeBotY = wedgeTopY + WEDGE_H;
const hw_top = WEDGE_TOP_W / 2;
const hw_bot = WEDGE_BOT_W / 2;
wedge.setAttribute('points',
`${CX-hw_top},${wedgeTopY} ${CX+hw_top},${wedgeTopY} ${CX+hw_bot},${wedgeBotY} ${CX-hw_bot},${wedgeBotY}`);
// 楔块在摩擦片中心高度处的宽度
const padCenterY = PAD_Y + PAD_HEIGHT / 2;
let ratio = (padCenterY - wedgeTopY) / WEDGE_H;
ratio = Math.max(0, Math.min(1, ratio));
const halfWAtPad = hw_top + (hw_bot - hw_top) * ratio;
// --- 摩擦片位置 (内边始终贴楔块面) ---
const padInnerShift = (hw_top - halfWAtPad); // 楔块变宽→内边外移
const padShift = padInnerShift * (PAD_MAX_SHIFT / (hw_top - hw_bot/2)); // 归一化
const leftPadInnerX = CX - halfWAtPad;
const leftPadOuterX = leftPadInnerX - PAD_WIDTH;
const rightPadInnerX = CX + halfWAtPad;
const rightPadOuterX = rightPadInnerX + PAD_WIDTH;
padL.setAttribute('x', leftPadOuterX);
padR.setAttribute('x', rightPadInnerX);
// 摩擦片标注跟随
$('padLLabel').setAttribute('x', leftPadOuterX + PAD_WIDTH/2);
$('padRLabel').setAttribute('x', rightPadInnerX + PAD_WIDTH/2);
// --- 间隙指示 ---
const gapLeft = leftPadOuterX - LEFT_WALL;
const gapRight = RIGHT_WALL - rightPadOuterX;
const gapOpacity = Math.max(0, 1 - t * 3);
gapL.setAttribute('opacity', gapOpacity * 0.8);
gapR.setAttribute('opacity', gapOpacity * 0.8);
// 间隙线位置
$('gapLLine1').setAttribute('x1', LEFT_WALL);
$('gapLLine1').setAttribute('x2', leftPadOuterX);
$('gapLLine2').setAttribute('x1', LEFT_WALL);
$('gapLLine3').setAttribute('x1', leftPadOuterX);
$('gapLLine3').setAttribute('x2', leftPadOuterX);
$('gapLText').setAttribute('x', (LEFT_WALL + leftPadOuterX) / 2);
$('gapRLine1').setAttribute('x1', rightPadOuterX);
$('gapRLine1').setAttribute('x2', RIGHT_WALL);
$('gapRLine2').setAttribute('x1', rightPadOuterX);
$('gapRLine3').setAttribute('x1', RIGHT_WALL);
$('gapRText').setAttribute('x', (rightPadOuterX + RIGHT_WALL) / 2);
// --- 接触发光 ---
const contactL = Math.max(0, leftPadOuterX - LEFT_WALL) < 2;
const contactR = Math.max(0, RIGHT_WALL - rightPadOuterX) < 2;
const glowIntensity = contactL ? Math.min(1, (t - 0.5) * 4) : 0;
contactGlowL.setAttribute('opacity', glowIntensity * 0.9);
contactGlowR.setAttribute('opacity', glowIntensity * 0.9);
// --- 弹簧 ---
const springCompress = t * 30; // 压缩量
const sTop = 115 + springCompress * 0.3;
const sBot = wedgeTopY - 2;
const coils = 6;
const coilH = (sBot - sTop - 10) / coils;
let sPath = `M${CX},${sTop} L${CX},${sTop+5}`;
for(let i = 0; i < coils; i++){
const y1 = sTop + 5 + i * coilH;
const y2 = y1 + coilH;
const dir = i % 2 === 0 ? 1 : -1;
sPath += ` L${CX + dir*10},${(y1+y2)/2} L${CX - dir*10},${y2}`;
}
sPath += ` L${CX},${sBot}`;
spring.setAttribute('d', sPath);
// --- 线缆 ---
const cableStartY = wedgeBotY;
const cablePullX = t * 12; // 线缆微弯
cable.setAttribute('d',
`M${CX},${cableStartY} L${CX},${cableStartY+30} Q${CX+cablePullX},${cableStartY+55} ${CX-10},${cableStartY+70} L190,510`);
cableEnd.setAttribute('cx', 190 - t * 8);
// --- 力箭头 ---
const arrowOpacity = Math.max(0, (t - 0.3) * 2);
forceArrows.setAttribute('opacity', arrowOpacity);
forceLabels.setAttribute('opacity', arrowOpacity);
// 力箭头位置跟随摩擦片
$('fArrL1').setAttribute('x1', leftPadInnerX - 5);
$('fArrL1').setAttribute('x2', leftPadOuterX + 5);
$('fArrR1').setAttribute('x1', rightPadInnerX + 5);
$('fArrR1').setAttribute('x2', rightPadOuterX - 5);
$('fArrDown').setAttribute('y1', cableStartY + 5);
$('fArrDown').setAttribute('y2', cableStartY + 40);
$('fLabelL').setAttribute('x', (leftPadInnerX + leftPadOuterX) / 2);
$('fLabelR').setAttribute('x', (rightPadInnerX + rightPadOuterX) / 2);
$('fLabelD').setAttribute('y', cableStartY + 35);
// 摩擦力箭头
$('fFricL').setAttribute('x1', LEFT_WALL + 3);
$('fFricL').setAttribute('x2', LEFT_WALL + 3);
$('fFricL2').setAttribute('x1', LEFT_WALL + 3);
$('fFricL2').setAttribute('x2', LEFT_WALL + 3);
$('fFricR').setAttribute('x1', RIGHT_WALL - 3);
$('fFricR').setAttribute('x2', RIGHT_WALL - 3);
$('fFricR2').setAttribute('x1', RIGHT_WALL - 3);
$('fFricR2').setAttribute('x2', RIGHT_WALL - 3);
$('fLabelFric').setAttribute('x', LEFT_WALL + 14);
// --- 状态指示 ---
const lockOp = Math.max(0, (t - 0.8) * 5);
const freeOp = Math.max(0, 1 - t * 3);
lockIndicator.setAttribute('opacity', lockOp);
freeIndicator.setAttribute('opacity', freeOp * 0.7);
// --- 楔块标注跟随 ---
$('wedgeLabel').setAttribute('y', wedgeTopY + WEDGE_H * 0.38);
$('wedgeCL').setAttribute('y1', wedgeTopY);
$('wedgeCL').setAttribute('y2', wedgeBotY);
// 角度标注
const annG = $('angleAnnotation');
annG.querySelector('path').nextElementSibling; // text
const annTexts = annG.querySelectorAll('text');
const annY = wedgeTopY + WEDGE_H * 0.7;
annG.querySelectorAll('path')[0].setAttribute('d', `M${CX},${annY} L${CX+20},${annY}`);
annG.querySelectorAll('path')[1].setAttribute('d', `M${CX},${annY} L${CX},${annY+20}`);
annG.querySelectorAll('path')[2].setAttribute('d', `M${CX+12},${annY} A8,8 0 0,1 ${CX},${annY+8}`);
if(annTexts.length) annTexts[0].setAttribute('y', annY + 15);
}
/* ===== 滑动板漂移 ===== */
function updateDrift(t, dt){
if(t > 0.3) return {dx:0, dy:0}; // 锁定时无漂移
const driftFactor = 1 - t * 3;
const dx = driftFactor * 10 * Math.sin(time * 0.7);
const dy = driftFactor * 7 * Math.sin(time * 1.05 + 1);
return {dx, dy};
}
/* ===== 俯视滑动板位置 ===== */
function updateTopPlate(t){
if(t > 0.3){
topPlate.setAttribute('x', 155 - 55);
topPlate.setAttribute('y', 127 - 49);
return;
}
const df = 1 - t * 3;
const dx = df * 18 * Math.sin(time * 0.7);
const dy = df * 12 * Math.sin(time * 1.05 + 1);
topPlate.setAttribute('x', 100 + dx);
topPlate.setAttribute('y', 78 + dy);
}
/* ===== 自动播放 ===== */
function getAutoTension(t){
const c = t % CYCLE;
let acc = 0;
acc += P.free; if(c < acc) return 0;
acc += P.locking; if(c < acc) return easeInOut((c - acc + P.locking) / P.locking);
acc += P.locked; if(c < acc) return 1;
acc += P.unlocking; if(c < acc) return 1 - easeInOut((c - acc + P.unlocking) / P.unlocking);
return 0;
}
/* ===== 状态文字 ===== */
function updateState(t){
stateDot.className = 'sd';
if(t < 0.15){
stateText.textContent = '自由滑动';
stateDot.classList.add(''); // green default
} else if(t < 0.85){
stateText.textContent = '锁定中...';
stateDot.classList.add('trans');
} else {
stateText.textContent = '已锁定';
stateDot.classList.add('locked');
}
}
/* ===== 序列进度条 ===== */
function updateSeqBar(t){
const c = time % CYCLE;
const pct = (c / CYCLE) * 100;
seqProgress.setAttribute('width', Math.max(0, pct * 3.08));
// 颜色
if(t < 0.15) seqProgress.setAttribute('fill', '#22c55e');
else if(t < 0.85) seqProgress.setAttribute('fill', '#e8a225');
else seqProgress.setAttribute('fill', '#ef4444');
}
/* ===== 主循环 ===== */
function animate(timestamp){
if(!lastTimestamp) lastTimestamp = timestamp;
const dt = Math.min((timestamp - lastTimestamp) / 1000, 0.05);
lastTimestamp = timestamp;
time += dt;
if(autoPlay){
tension = getAutoTension(time);
tensionSlider.value = Math.round(tension * 100);
}
tensionVal.textContent = Math.round(tension * 100) + '%';
// 滑动板漂移
const drift = updateDrift(tension, dt);
plateGroup.setAttribute('transform', `translate(${drift.dx},${drift.dy})`);
// 更新机构
updateMechanism(tension);
updateTopPlate(tension);
updateState(tension);
updateSeqBar(t);
requestAnimationFrame(animate);
}
/* ===== 交互 ===== */
tensionSlider.addEventListener('input', function(){
if(!autoPlay){
tension = this.value / 100;
}
});
autoBtn.addEventListener('click', function(){
autoPlay = true;
autoBtn.classList.add('on');
manualBtn.classList.remove('on');
});
manualBtn.addEventListener('click', function(){
autoPlay = false;
manualBtn.classList.add('on');
autoBtn.classList.remove('on');
tension = tensionSlider.value / 100;
});
/* ===== 启动 ===== */
document.addEventListener('DOMContentLoaded', function(){
requestAnimationFrame(animate);
});
// 兼容:页面已加载完成时直接启动
if(document.readyState !== 'loading'){
requestAnimationFrame(animate);
}
})();
</script>
</body>
</html>
这个动画实现了以下核心设计:
原理可视化:
- 主截面视图(左侧 2/3):展示楔块-摩擦片-固定座的核心锁定原理。倒梯形楔块下移时,宽部到达摩擦片高度,将两片摩擦片向两侧推开,直至紧贴固定座内壁,靠摩擦力锁定整个滑动板。
- 俯视导轨视图(右上):展示十字导轨的 X-Y 双轴滑动范围(8×5cm),滑动板在自由状态下缓慢漂移,直观体现"随动贴合"。
- 参数与 IFR 面板(右下):标注楔角 8°、摩擦片 70A/1.5mm 等关键参数,并从最终理想解视角总结矛盾消除逻辑。
动态反馈层次:
- 细节层:摩擦片从间隙到贴墙的颜色渐变与发光、力箭头渐显、弹簧压缩跟随楔块位移。
- 结构层:楔块下移→摩擦片外推→间隙闭合→锁定指示的完整因果链,时序进度条同步呈现四阶段(寻位→锁定→保持→释放)。
- 场景层:自由状态下滑动板的正弦漂移,锁定时骤然静止,形成鲜明对比。
交互控制: 提供「自动播放 / 手动控制」两种模式,手动模式下拖动滑块可精确控制线缆拉力 0~100%,深入体验楔块自锁的临界点。
积分规则:第一轮对话扣减8分,后续每轮扣6分
等待动画代码生成...
