独立渲染引擎就绪引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>轴向自锁伸缩伞骨机构原理动画</title>
<style>
:root {
--bg-color: #0c1017;
--card-bg: rgba(18, 24, 38, 0.85);
--card-border: rgba(56, 189, 248, 0.18);
--accent-cyan: #38bdf8;
--accent-amber: #fbbf24;
--accent-emerald: #34d399;
--accent-rose: #f43f5e;
--tube-outer: #475569;
--tube-mid: #64748b;
--tube-inner: #94a3b8;
--spring-color: #f59e0b;
--text-main: #e2e8f0;
--text-muted: #94a3b8;
--font-mono: "JetBrains Mono", "Fira Code", "Courier New", monospace;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
user-select: none;
}
body {
background-color: var(--bg-color);
color: var(--text-main);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
overflow: hidden;
background-image:
radial-gradient(circle at 50% 20%, rgba(56, 189, 248, 0.08) 0%, transparent 60%),
linear-gradient(to right, rgba(255, 255, 255, 0.02) 1px, transparent 1px),
linear-gradient(to bottom, rgba(255, 255, 255, 0.02) 1px, transparent 1px);
background-size: 100% 100%, 32px 32px, 32px 32px;
}
/* 顶部精简状态条 - 避免遮挡 */
header {
width: 100%;
padding: 12px 24px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
backdrop-filter: blur(8px);
z-index: 10;
}
.brand {
display: flex;
align-items: center;
gap: 10px;
}
.brand-tag {
font-size: 10px;
font-family: var(--font-mono);
color: var(--accent-cyan);
background: rgba(56, 189, 248, 0.12);
border: 1px solid rgba(56, 189, 248, 0.3);
padding: 2px 6px;
border-radius: 4px;
letter-spacing: 0.5px;
}
.brand-title {
font-size: 14px;
font-weight: 600;
letter-spacing: 0.3px;
color: #f8fafc;
}
.specs-strip {
display: flex;
gap: 16px;
}
.spec-item {
display: flex;
align-items: baseline;
gap: 4px;
font-size: 11px;
}
.spec-label {
color: var(--text-muted);
}
.spec-val {
font-family: var(--font-mono);
font-weight: 600;
color: var(--accent-cyan);
}
/* 主可视化舞台 */
main {
flex: 1;
width: 100%;
position: relative;
display: flex;
align-items: center;
justify-content: center;
padding: 10px;
}
.stage-container {
width: 100%;
max-width: 1180px;
height: 100%;
max-height: 680px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
svg#mechanism-stage {
width: 100%;
height: 100%;
overflow: visible;
}
/* 浮动边缘微型数据卡 (非侵入式布局,靠边置放) */
.hud-overlay {
position: absolute;
top: 14px;
left: 14px;
display: flex;
flex-direction: column;
gap: 8px;
pointer-events: none;
z-index: 5;
}
.status-badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 5px 10px;
background: var(--card-bg);
border: 1px solid var(--card-border);
border-radius: 6px;
font-size: 11px;
backdrop-filter: blur(10px);
}
.status-dot {
width: 7px;
height: 7px;
border-radius: 50%;
background: var(--accent-emerald);
box-shadow: 0 0 8px var(--accent-emerald);
transition: all 0.3s ease;
}
.status-dot.retracting {
background: var(--accent-amber);
box-shadow: 0 0 8px var(--accent-amber);
}
.status-dot.unlocking {
background: var(--accent-rose);
box-shadow: 0 0 8px var(--accent-rose);
}
.hud-metrics {
display: grid;
grid-template-columns: repeat(2, auto);
gap: 6px;
}
.metric-pill {
background: rgba(15, 23, 42, 0.75);
border: 1px solid rgba(255, 255, 255, 0.07);
padding: 4px 8px;
border-radius: 4px;
font-size: 10px;
font-family: var(--font-mono);
display: flex;
justify-content: space-between;
gap: 8px;
}
/* 右上角伞形联动形态监视小窗 */
.umbrella-mini-view {
position: absolute;
top: 14px;
right: 14px;
width: 140px;
height: 110px;
background: var(--card-bg);
border: 1px solid var(--card-border);
border-radius: 8px;
padding: 6px;
display: flex;
flex-direction: column;
align-items: center;
backdrop-filter: blur(8px);
pointer-events: none;
z-index: 5;
}
.mini-view-title {
font-size: 9px;
font-family: var(--font-mono);
color: var(--text-muted);
margin-bottom: 2px;
width: 100%;
text-align: left;
}
/* 底部控制中心 */
footer {
width: 100%;
padding: 10px 24px 16px;
background: rgba(12, 16, 23, 0.9);
border-top: 1px solid rgba(255, 255, 255, 0.07);
display: flex;
flex-direction: column;
gap: 8px;
align-items: center;
z-index: 10;
}
.timeline-container {
width: 100%;
max-width: 900px;
display: flex;
align-items: center;
gap: 12px;
}
.time-slider {
flex: 1;
-webkit-appearance: none;
height: 5px;
border-radius: 3px;
background: #1e293b;
outline: none;
cursor: pointer;
position: relative;
}
.time-slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 14px;
height: 14px;
border-radius: 50%;
background: var(--accent-cyan);
box-shadow: 0 0 10px var(--accent-cyan);
cursor: pointer;
border: 2px solid #0f172a;
}
.controls-row {
display: flex;
align-items: center;
gap: 16px;
font-size: 11px;
}
.btn {
background: #1e293b;
color: #e2e8f0;
border: 1px solid rgba(255, 255, 255, 0.12);
padding: 5px 12px;
border-radius: 5px;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 11px;
transition: all 0.2s;
}
.btn:hover {
background: #334155;
border-color: var(--accent-cyan);
}
.btn.active {
background: rgba(56, 189, 248, 0.15);
border-color: var(--accent-cyan);
color: var(--accent-cyan);
}
.step-pill-group {
display: flex;
background: #0f172a;
padding: 2px;
border-radius: 6px;
border: 1px solid rgba(255, 255, 255, 0.08);
gap: 2px;
}
.step-pill {
background: transparent;
border: none;
color: var(--text-muted);
padding: 3px 8px;
font-size: 10px;
border-radius: 4px;
cursor: pointer;
transition: 0.2s;
}
.step-pill.active {
background: #1e293b;
color: var(--accent-cyan);
font-weight: 600;
}
/* SVG 内部微动画样式 */
.glow-cyan { filter: drop-shadow(0 0 4px rgba(56, 189, 248, 0.8)); }
.glow-amber { filter: drop-shadow(0 0 4px rgba(251, 191, 36, 0.8)); }
.glow-emerald { filter: drop-shadow(0 0 5px rgba(52, 211, 153, 0.9)); }
.glow-rose { filter: drop-shadow(0 0 5px rgba(244, 63, 94, 0.9)); }
.vector-arrow {
stroke-dasharray: 4, 3;
animation: dashMove 1s linear infinite;
}
@keyframes dashMove {
from { stroke-dashoffset: 14; }
to { stroke-dashoffset: 0; }
}
.spring-coils {
stroke-dasharray: 3, 1.5;
}
</style>
</head>
<body>
<!-- 顶部精简抬头条 -->
<header>
<div class="brand">
<span class="brand-tag">IFR-DESIGN</span>
<span class="brand-title">轴向自锁套接伞骨原理动画 (Axial Telescopic Rib)</span>
</div>
<div class="specs-strip">
<div class="spec-item"><span class="spec-label">套管节数:</span><span class="spec-val">3节 (304薄壁管)</span></div>
<div class="spec-item"><span class="spec-label">行程压缩:</span><span class="spec-val">550mm → 200mm (350mm)</span></div>
<div class="spec-item"><span class="spec-label">卷簧恒力:</span><span class="spec-val">6.0 N</span></div>
<div class="spec-item"><span class="spec-label">重叠自锁:</span><span class="spec-val">40 mm</span></div>
</div>
</header>
<!-- 主动画展示舞台 -->
<main>
<div class="stage-container">
<!-- 边缘非遮挡 HUD 读数 -->
<div class="hud-overlay">
<div class="status-badge">
<div class="status-dot" id="statusDot"></div>
<span id="stateName" style="font-weight: 600; font-size: 11px;">状态:连续循环演示中</span>
</div>
<div class="hud-metrics">
<div class="metric-pill"><span>骨架总长:</span><span id="hudLength" class="spec-val">200 mm</span></div>
<div class="metric-pill"><span>自锁爪状态:</span><span id="hudLock" class="spec-val" style="color:var(--accent-amber)">就绪/待锁</span></div>
<div class="metric-pill"><span>卷簧张力:</span><span id="hudSpring" class="spec-val">6.0 N 蓄能</span></div>
<div class="metric-pill"><span>释放推杆:</span><span id="hudPusher" class="spec-val">原位复位</span></div>
</div>
</div>
<!-- 右上角整伞联动小窗 -->
<div class="umbrella-mini-view">
<div class="mini-view-title">整伞形态联动投影</div>
<svg id="miniUmbrella" viewBox="0 0 120 80" width="100%" height="100%">
<defs>
<linearGradient id="canopyGrad" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#0284c7" stop-opacity="0.75"/>
<stop offset="100%" stop-color="#0369a1" stop-opacity="0.25"/>
</linearGradient>
</defs>
<!-- 伞中棒 -->
<line x1="60" y1="12" x2="60" y2="72" stroke="#64748b" stroke-width="2.5" stroke-linecap="round"/>
<circle cx="60" cy="12" r="3" fill="#38bdf8"/>
<rect x="56" y="66" width="8" height="9" rx="2" fill="#334155"/>
<!-- 下巢滑块 -->
<rect id="miniRunner" x="57" y="52" width="6" height="5" rx="1" fill="#38bdf8"/>
<!-- 动态伞面 -->
<path id="miniCanopy" d="M 15 48 Q 60 10 105 48" fill="url(#canopyGrad)" stroke="#38bdf8" stroke-width="1.5"/>
<!-- 左右支撑副骨 -->
<line id="miniStrutL" x1="57" y1="52" x2="32" y2="38" stroke="#94a3b8" stroke-width="1.2"/>
<line id="miniStrutR" x1="63" y1="52" x2="88" y2="38" stroke="#94a3b8" stroke-width="1.2"/>
<!-- 左右伸缩主骨 -->
<line id="miniRibL" x1="60" y1="12" x2="15" y2="48" stroke="#f8fafc" stroke-width="1.6"/>
<line id="miniRibR" x1="60" y1="12" x2="105" y2="48" stroke="#f8fafc" stroke-width="1.6"/>
</svg>
</div>
<!-- 核心原理剖面 SVG -->
<svg id="mechanism-stage" viewBox="0 0 1000 520">
<defs>
<!-- 滤镜与渐变定义 -->
<linearGradient id="gradOuterTube" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#64748b"/>
<stop offset="30%" stop-color="#475569"/>
<stop offset="70%" stop-color="#334155"/>
<stop offset="100%" stop-color="#1e293b"/>
</linearGradient>
<linearGradient id="gradMidTube" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#94a3b8"/>
<stop offset="30%" stop-color="#64748b"/>
<stop offset="70%" stop-color="#475569"/>
<stop offset="100%" stop-color="#334155"/>
</linearGradient>
<linearGradient id="gradInnerTube" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#cbd5e1"/>
<stop offset="30%" stop-color="#94a3b8"/>
<stop offset="70%" stop-color="#64748b"/>
<stop offset="100%" stop-color="#475569"/>
</linearGradient>
<linearGradient id="gradSpring" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#f59e0b"/>
<stop offset="50%" stop-color="#fbbf24"/>
<stop offset="100%" stop-color="#d97706"/>
</linearGradient>
<filter id="glow-cyan" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="3" result="blur"/>
<feComposite in="SourceGraphic" in2="blur" operator="over"/>
</filter>
<filter id="glow-gold" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="3" result="blur"/>
<feComposite in="SourceGraphic" in2="blur" operator="over"/>
</filter>
<marker id="arrowhead" markerWidth="6" markerHeight="4" refX="5" refY="2" orient="auto">
<polygon points="0 0, 6 2, 0 4" fill="#38bdf8"/>
</marker>
<marker id="arrowhead-amber" markerWidth="6" markerHeight="4" refX="5" refY="2" orient="auto">
<polygon points="0 0, 6 2, 0 4" fill="#fbbf24"/>
</marker>
</defs>
<!-- 背景工程基准线网格 -->
<g opacity="0.18">
<line x1="80" y1="260" x2="940" y2="260" stroke="#38bdf8" stroke-dasharray="8 4" stroke-width="1"/>
<line x1="120" y1="120" x2="120" y2="400" stroke="#94a3b8" stroke-dasharray="2 4" stroke-width="1"/>
<line x1="380" y1="120" x2="380" y2="400" stroke="#94a3b8" stroke-dasharray="2 4" stroke-width="1"/>
<line x1="640" y1="120" x2="640" y2="400" stroke="#94a3b8" stroke-dasharray="2 4" stroke-width="1"/>
<line x1="900" y1="120" x2="900" y2="400" stroke="#94a3b8" stroke-dasharray="2 4" stroke-width="1"/>
</g>
<!-- 顶部动态总行程标尺 -->
<g id="dimensionLineGroup" transform="translate(0, -30)">
<line id="dimLine" x1="130" y1="145" x2="390" y2="145" stroke="#38bdf8" stroke-width="1.5"/>
<line x1="130" y1="138" x2="130" y2="152" stroke="#38bdf8" stroke-width="1.5"/>
<line id="dimTickEnd" x1="390" y1="138" x2="390" y2="152" stroke="#38bdf8" stroke-width="1.5"/>
<rect id="dimBadge" x="220" y="132" width="80" height="18" rx="3" fill="#0f172a" stroke="#38bdf8" stroke-width="1"/>
<text id="dimText" x="260" y="145" fill="#38bdf8" font-size="11" font-family="monospace" text-anchor="middle" dominant-baseline="central">200 mm</text>
</g>
<!-- 主机构装配体 (居中基准 Y=260) -->
<g id="mainAssembly" transform="translate(0, 0)">
<!-- 1. 中央伞盘与释放驱动模块 (Base Mount & Release Collar) -->
<g id="baseCollarGroup">
<!-- 伞顶固定座 -->
<path d="M 80,210 L 130,210 L 130,310 L 80,310 Z" fill="#1e293b" stroke="#475569" stroke-width="2"/>
<circle cx="105" cy="260" r="14" fill="#0f172a" stroke="#38bdf8" stroke-width="2"/>
<circle cx="105" cy="260" r="4" fill="#38bdf8"/>
<text x="105" y="332" fill="#94a3b8" font-size="10" text-anchor="middle">伞头铰接座</text>
<!-- 恒力簧卷盘 (固定在基座内部) -->
<circle cx="148" cy="260" r="16" fill="#1e293b" stroke="#d97706" stroke-width="2" class="glow-gold"/>
<circle cx="148" cy="260" r="7" fill="#d97706"/>
<!-- 卷簧发条涡卷纹 -->
<path d="M 148,248 A 12 12 0 1 1 138,265 A 7 7 0 1 1 148,255" fill="none" stroke="#fbbf24" stroke-width="1.8"/>
<!-- 中央环形释放推压板 (Release Collar Actuator) -->
<g id="releaseCollar" transform="translate(0, 0)">
<rect x="70" y="234" width="14" height="52" rx="3" fill="#e11d48" stroke="#fda4af" stroke-width="1.5" class="glow-rose"/>
<polygon points="62,260 68,254 68,266" fill="#f43f5e"/>
<text id="releaseText" x="52" y="264" fill="#f43f5e" font-size="9" font-weight="bold" text-anchor="end">释放环</text>
</g>
<!-- 解锁细推杆 (穿过管壁内部) -->
<line id="pushRod" x1="84" y1="240" x2="370" y2="240" stroke="#f43f5e" stroke-width="2" stroke-dasharray="6 2" opacity="0.9"/>
</g>
<!-- 2. 第一节:外节薄壁管 (Base Tube, 固定在伞座) -->
<g id="outerTubeGroup">
<!-- 外管剖面主体 (外径 14mm,壁厚 0.3mm 示意) -->
<path d="M 130,224 L 390,224 L 390,234 L 130,234 Z" fill="url(#gradOuterTube)" stroke="#64748b" stroke-width="1"/>
<path d="M 130,286 L 390,286 L 390,296 L 130,296 Z" fill="url(#gradOuterTube)" stroke="#64748b" stroke-width="1"/>
<!-- 外管右端锁定凹槽 (Locking Notch 1) -->
<rect x="366" y="220" width="12" height="5" fill="#0f172a" stroke="#38bdf8" stroke-width="1.2"/>
<rect x="366" y="295" width="12" height="5" fill="#0f172a" stroke="#38bdf8" stroke-width="1.2"/>
<!-- O形防尘密封阻尼圈 (40mm 重叠端部) -->
<ellipse cx="386" cy="229" rx="3" ry="4" fill="#0284c7" stroke="#38bdf8"/>
<ellipse cx="386" cy="291" rx="3" ry="4" fill="#0284c7" stroke="#38bdf8"/>
<text x="365" y="208" fill="#94a3b8" font-size="10" text-anchor="middle">外节管 (节1) / 定位槽</text>
</g>
<!-- 3. 第二节:中节套管 (Mid Tube, 可轴向伸缩) -->
<g id="midTubeGroup" transform="translate(0, 0)">
<!-- 中节管剖面 (略小一圈,嵌套在外管中) -->
<path d="M 150,235 L 410,235 L 410,243 L 150,243 Z" fill="url(#gradMidTube)" stroke="#94a3b8" stroke-width="1"/>
<path d="M 150,277 L 410,277 L 410,285 L 150,285 Z" fill="url(#gradMidTube)" stroke="#94a3b8" stroke-width="1"/>
<!-- 中节管左端弹性卡爪 1 (Pawl 1) -->
<g id="pawl1Group" transform="translate(160, 0)">
<!-- 上弹片 -->
<path id="pawl1Upper" d="M -10,243 Q 5,243 14,228 L 22,228 L 22,243 Z" fill="#38bdf8" stroke="#7dd3fc" stroke-width="1"/>
<!-- 下弹片 -->
<path id="pawl1Lower" d="M -10,277 Q 5,277 14,292 L 22,292 L 22,277 Z" fill="#38bdf8" stroke="#7dd3fc" stroke-width="1"/>
<circle cx="16" cy="228" r="2" fill="#ffffff" class="glow-cyan"/>
</g>
<!-- 中节管右端锁定凹槽 (Locking Notch 2) -->
<rect x="388" y="232" width="10" height="4" fill="#0f172a" stroke="#38bdf8" stroke-width="1"/>
<rect x="388" y="284" width="10" height="4" fill="#0f172a" stroke="#38bdf8" stroke-width="1"/>
<!-- 中节管防泥沙O圈 -->
<ellipse cx="406" cy="239" rx="2.5" ry="3.5" fill="#0284c7"/>
<ellipse cx="406" cy="281" rx="2.5" ry="3.5" fill="#0284c7"/>
</g>
<!-- 4. 第三节:内节末端管 (Inner Tip Tube, 伸至伞骨末端) -->
<g id="innerTubeGroup" transform="translate(0, 0)">
<!-- 内节管剖面 -->
<path d="M 170,244 L 430,244 L 430,250 L 170,250 Z" fill="url(#gradInnerTube)" stroke="#cbd5e1" stroke-width="1"/>
<path d="M 170,270 L 430,270 L 430,276 L 170,276 Z" fill="url(#gradInnerTube)" stroke="#cbd5e1" stroke-width="1"/>
<!-- 伞骨末梢珠尾 (Tip Cap) -->
<path d="M 430,240 L 444,244 L 448,260 L 444,276 L 430,280 Z" fill="#38bdf8" stroke="#e0f2fe" stroke-width="1.5" class="glow-cyan"/>
<circle cx="442" cy="260" r="3" fill="#ffffff"/>
<!-- 内节管左端弹性卡爪 2 (Pawl 2) -->
<g id="pawl2Group" transform="translate(180, 0)">
<!-- 上弹片 -->
<path id="pawl2Upper" d="M -10,250 Q 5,250 12,238 L 18,238 L 18,250 Z" fill="#38bdf8" stroke="#7dd3fc" stroke-width="1"/>
<!-- 下弹片 -->
<path id="pawl2Lower" d="M -10,270 Q 5,270 12,282 L 18,282 L 18,270 Z" fill="#38bdf8" stroke="#7dd3fc" stroke-width="1"/>
<circle cx="14" cy="238" r="2" fill="#ffffff" class="glow-cyan"/>
</g>
<!-- 恒力簧与末端管的锚定点固定块 -->
<circle cx="426" cy="260" r="4" fill="#fbbf24" stroke="#d97706" stroke-width="1.5"/>
</g>
<!-- 5. 核心机构:0.1mm 恒力卷簧拉伸带 (Constant Force Spring Strip) -->
<g id="springBeltGroup">
<!-- 卷簧钢带 (从卷轴 148,260 连至内节锚定点) -->
<line id="springBelt" x1="164" y1="260" x2="426" y2="260" stroke="url(#gradSpring)" stroke-width="3" stroke-linecap="round" class="glow-gold"/>
<!-- 恒力张力微波纹/刻度 -->
<line id="springTexture" x1="164" y1="260" x2="426" y2="260" stroke="#ffffff" stroke-width="1" stroke-dasharray="5 3" opacity="0.6"/>
</g>
<!-- 6. 动态受力与自锁微观状态高亮层 (Visual FX) -->
<!-- 自锁入槽光晕与提示 -->
<g id="lockHighlight1" opacity="0" transform="translate(372, 222)">
<circle cx="0" cy="0" r="10" fill="none" stroke="#34d399" stroke-width="2" class="glow-emerald"/>
<polygon points="-4,-7 0,-14 4,-7" fill="#34d399"/>
<text x="0" y="-18" fill="#34d399" font-size="10" font-family="monospace" font-weight="bold" text-anchor="middle">自锁锁定 40mm</text>
</g>
<g id="lockHighlight2" opacity="0" transform="translate(632, 234)">
<circle cx="0" cy="0" r="10" fill="none" stroke="#34d399" stroke-width="2" class="glow-emerald"/>
<polygon points="-4,-7 0,-14 4,-7" fill="#34d399"/>
<text x="0" y="-18" fill="#34d399" font-size="10" font-family="monospace" font-weight="bold" text-anchor="middle">末节自锁到位</text>
</g>
<!-- 恒力卷簧 6N 恒定收缩力矢量箭头 -->
<g id="forceVectorGroup" opacity="0.8">
<line id="vectorLine" x1="420" y1="260" x2="340" y2="260" stroke="#fbbf24" stroke-width="2.5" marker-end="url(#arrowhead-amber)" class="vector-arrow"/>
<text id="vectorText" x="380" y="278" fill="#fbbf24" font-size="10" font-family="monospace" font-weight="bold" text-anchor="middle">F_spring = 6.0 N (恒力回缩)</text>
</g>
</g>
<!-- 底部精简图例与结构导引 (不遮挡主体) -->
<g transform="translate(100, 440)">
<!-- 导引 1 -->
<g transform="translate(0, 0)">
<rect x="0" y="0" width="12" height="12" rx="2" fill="#475569" stroke="#64748b"/>
<text x="18" y="10" fill="#94a3b8" font-size="11">3节薄壁套管 (0.3mm 304不锈钢/碳纤)</text>
</g>
<!-- 导引 2 -->
<g transform="translate(260, 0)">
<rect x="0" y="0" width="12" height="12" rx="2" fill="#fbbf24"/>
<text x="18" y="10" fill="#94a3b8" font-size="11">0.1mm 内置恒力卷簧 (提供全行程 6N 恒拉力)</text>
</g>
<!-- 导引 3 -->
<g transform="translate(540, 0)">
<polygon points="0,12 6,0 12,12" fill="#38bdf8"/>
<text x="18" y="10" fill="#94a3b8" font-size="11">双侧弹性自锁卡爪 (抗伞面张力与暴风压)</text>
</g>
<!-- 导引 4 -->
<g transform="translate(790, 0)">
<rect x="0" y="0" width="12" height="12" rx="2" fill="#f43f5e"/>
<text x="18" y="10" fill="#94a3b8" font-size="11">中央推杆同步解锁</text>
</g>
</g>
</svg>
</div>
</main>
<!-- 底部操作与时序控制条 -->
<footer>
<div class="timeline-container">
<span style="font-size: 11px; font-family: var(--font-mono); color: var(--text-muted);">进度</span>
<input type="range" id="progressSlider" class="time-slider" min="0" max="1000" value="0">
<span id="progressTime" style="font-size: 11px; font-family: var(--font-mono); color: var(--accent-cyan); min-width: 45px;">0.0s</span>
</div>
<div class="controls-row">
<button id="btnPlayPause" class="btn active">
<span id="playIcon">⏸</span>
<span id="playText">自动演示中</span>
</button>
<div class="step-pill-group">
<button class="step-pill active" onclick="seekToPhase(0)">1. 极限收拢 (20cm)</button>
<button class="step-pill" onclick="seekToPhase(0.35)">2. 轴向抽出</button>
<button class="step-pill" onclick="seekToPhase(0.55)">3. 卡爪自锁 (55cm)</button>
<button class="step-pill" onclick="seekToPhase(0.72)">4. 触发展开/释放</button>
<button class="step-pill" onclick="seekToPhase(0.88)">5. 卷簧自缩回</button>
</div>
<div style="display: flex; align-items: center; gap: 6px; margin-left: 8px;">
<span style="color: var(--text-muted); font-size: 10px;">速度:</span>
<button class="btn" style="padding: 2px 7px; font-size: 10px;" onclick="setSpeed(0.5)">0.5x</button>
<button class="btn active" id="spd1" style="padding: 2px 7px; font-size: 10px;" onclick="setSpeed(1)">1.0x</button>
<button class="btn" style="padding: 2px 7px; font-size: 10px;" onclick="setSpeed(1.8)">1.8x</button>
</div>
</div>
</footer>
<script>
// --- 机械运动核心变量与时序参数 ---
const TOTAL_DURATION = 9000; // 一个完整循环 9 秒
let isPlaying = true;
let animSpeed = 1.0;
let startTime = performance.now();
let currentProgress = 0; // 0.0 ~ 1.0
// DOM 元素引用
const midTube = document.getElementById('midTubeGroup');
const innerTube = document.getElementById('innerTubeGroup');
const springBelt = document.getElementById('springBelt');
const springTexture = document.getElementById('springTexture');
const pushRod = document.getElementById('pushRod');
const releaseCollar = document.getElementById('releaseCollar');
const dimLine = document.getElementById('dimLine');
const dimTickEnd = document.getElementById('dimTickEnd');
const dimBadge = document.getElementById('dimBadge');
const dimText = document.getElementById('dimText');
const lockH1 = document.getElementById('lockHighlight1');
const lockH2 = document.getElementById('lockHighlight2');
const forceVec = document.getElementById('forceVectorGroup');
const vectorLine = document.getElementById('vectorLine');
const vectorText = document.getElementById('vectorText');
const pawl1U = document.getElementById('pawl1Upper');
const pawl1L = document.getElementById('pawl1Lower');
const pawl2U = document.getElementById('pawl2Upper');
const pawl2L = document.getElementById('pawl2Lower');
// HUD 读数
const statusDot = document.getElementById('statusDot');
const stateName = document.getElementById('stateName');
const hudLength = document.getElementById('hudLength');
const hudLock = document.getElementById('hudLock');
const hudSpring = document.getElementById('hudSpring');
const hudPusher = document.getElementById('hudPusher');
// 联动小窗
const miniCanopy = document.getElementById('miniCanopy');
const miniRunner = document.getElementById('miniRunner');
const miniStrutL = document.getElementById('miniStrutL');
const miniStrutR = document.getElementById('miniStrutR');
const miniRibL = document.getElementById('miniRibL');
const miniRibR = document.getElementById('miniRibR');
// 控制栏
const slider = document.getElementById('progressSlider');
const timeDisplay = document.getElementById('progressTime');
const btnPlayPause = document.getElementById('btnPlayPause');
const playIcon = document.getElementById('playIcon');
const playText = document.getElementById('playText');
const stepPills = document.querySelectorAll('.step-pill');
// 最大物理像素位移 (对应 350mm 真实行程)
const MAX_DISP_MID = 240; // 中节滑出 240px (~175mm)
const MAX_DISP_INNER = 480; // 内节总滑出 480px (~350mm)
// 缓动函数
function easeInOutQuad(t) {
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
}
function easeOutBack(t) {
const c1 = 1.70158;
const c3 = c1 + 1;
return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
}
function easeInQuad(t) {
return t * t;
}
// --- 主帧更新循环 ---
function updatePhysics(progress) {
currentProgress = progress;
slider.value = Math.floor(progress * 1000);
timeDisplay.textContent = ((progress * TOTAL_DURATION) / 1000).toFixed(1) + 's';
// 阶段时序划分:
// 0.00 - 0.15: 紧凑收纳状态展示 (总长 200mm)
// 0.15 - 0.48: 上推展开,各节套管向右平滑抽出,恒力簧被拉开
// 0.48 - 0.68: 卡爪弹入凹槽完全自锁,抵抗风压稳态 (总长 550mm)
// 0.68 - 0.78: 按压中央释放环,推杆顶开卡爪解锁
// 0.78 - 0.95: 恒力卷簧 6N 恒定自回缩,秒级缩回最短
// 0.95 - 1.00: 循环缓冲复位
let midX = 0;
let innerX = 0;
let collarX = 0;
let rodStroke = 0;
let isLocked = false;
let isUnlocking = false;
let isRetracting = false;
if (progress <= 0.15) {
// [阶段 1] 极致紧凑收拢
midX = 0;
innerX = 0;
collarX = 0;
stateName.textContent = "1. 极致紧凑收拢态 (骨长20cm/无冗余折段)";
statusDot.className = "status-dot";
hudLock.textContent = "解除锁定 / 自由";
hudLock.style.color = "var(--text-muted)";
hudPusher.textContent = "原位复位";
updateActivePill(0);
}
else if (progress > 0.15 && progress <= 0.48) {
// [阶段 2] 轴向平稳抽出展开
const p = (progress - 0.15) / 0.33;
const eased = easeInOutQuad(p);
midX = eased * MAX_DISP_MID;
innerX = eased * MAX_DISP_INNER;
stateName.textContent = "2. 上推轴向抽出 (套管逐节延伸/卷簧匀速储能)";
statusDot.className = "status-dot";
hudLock.textContent = "滑动到位中...";
hudLock.style.color = "var(--accent-cyan)";
hudPusher.textContent = "待命";
updateActivePill(1);
}
else if (progress > 0.48 && progress <= 0.68) {
// [阶段 3] 自锁锁定,伞面饱满撑开
midX = MAX_DISP_MID;
innerX = MAX_DISP_INNER;
isLocked = true;
stateName.textContent = "3. 弹性卡爪弹入槽口自锁 (刚性抵抗风压与张力)";
statusDot.className = "status-dot";
hudLock.textContent = "双节全刚性自锁 ✓";
hudLock.style.color = "var(--accent-emerald)";
hudPusher.textContent = "锁定保持";
updateActivePill(2);
}
else if (progress > 0.68 && progress <= 0.78) {
// [阶段 4] 释放环动作,推杆顶出解锁
midX = MAX_DISP_MID;
innerX = MAX_DISP_INNER;
const p = (progress - 0.68) / 0.10;
collarX = Math.sin(p * Math.PI) * 12; // 释放环按压行程 12px
rodStroke = collarX;
isUnlocking = true;
stateName.textContent = "4. 伞柄释放环同步顶开卡爪 (释放自锁)";
statusDot.className = "status-dot unlocking";
hudLock.textContent = "卡爪脱出凹槽 ⚡";
hudLock.style.color = "var(--accent-rose)";
hudPusher.textContent = `行程 ${Math.round(collarX * 0.25 + 1)}mm (驱动中)`;
updateActivePill(3);
}
else if (progress > 0.78 && progress <= 0.95) {
// [阶段 5] 卷簧 6N 恒定自动缩回
const p = (progress - 0.78) / 0.17;
const eased = 1 - easeInOutQuad(p);
midX = eased * MAX_DISP_MID;
innerX = eased * MAX_DISP_INNER;
isRetracting = true;
stateName.textContent = "5. 恒力卷簧 6N 恒定拉力瞬间自回缩";
statusDot.className = "status-dot retracting";
hudLock.textContent = "自动滑移归位";
hudLock.style.color = "var(--accent-amber)";
hudPusher.textContent = "自动复位";
updateActivePill(4);
}
else {
// 缓冲复位
midX = 0;
innerX = 0;
stateName.textContent = "1. 极致紧凑收拢态 (准备就绪)";
statusDot.className = "status-dot";
updateActivePill(0);
}
// --- SVG 主管段位移应用 ---
midTube.setAttribute('transform', `translate(${midX}, 0)`);
innerTube.setAttribute('transform', `translate(${innerX}, 0)`);
releaseCollar.setAttribute('transform', `translate(${collarX}, 0)`);
// 推杆联动
pushRod.setAttribute('x1', 84 + collarX);
pushRod.setAttribute('x2', 370 + (isUnlocking ? 20 : 0));
// 恒力弹簧带长度更新 (卷筒中心固定在 148,锚定点随 innerX 移动)
const springTipX = 426 + innerX;
springBelt.setAttribute('x2', springTipX);
springTexture.setAttribute('x2', springTipX);
// 卡爪弹片微观开合动画
if (isLocked) {
// 弹入凹槽 (深扣)
pawl1U.setAttribute('d', 'M -10,243 Q 5,243 14,222 L 24,222 L 24,243 Z');
pawl1L.setAttribute('d', 'M -10,277 Q 5,277 14,298 L 24,298 L 24,277 Z');
pawl2U.setAttribute('d', 'M -10,250 Q 5,250 12,233 L 20,233 L 20,250 Z');
pawl2L.setAttribute('d', 'M -10,270 Q 5,270 12,287 L 20,287 L 20,270 Z');
lockH1.setAttribute('opacity', '1');
lockH2.setAttribute('opacity', '1');
} else if (isUnlocking) {
// 被推杆压平 (脱出槽口)
pawl1U.setAttribute('d', 'M -10,243 Q 5,243 14,236 L 22,236 L 22,243 Z');
pawl1L.setAttribute('d', 'M -10,277 Q 5,277 14,284 L 22,284 L 22,277 Z');
pawl2U.setAttribute('d', 'M -10,250 Q 5,250 12,245 L 18,245 L 18,250 Z');
pawl2L.setAttribute('d', 'M -10,270 Q 5,270 12,275 L 18,275 L 18,270 Z');
lockH1.setAttribute('opacity', '0');
lockH2.setAttribute('opacity', '0');
} else {
// 管内滑动平伏态
pawl1U.setAttribute('d', 'M -10,243 Q 5,243 14,233 L 22,233 L 22,243 Z');
pawl1L.setAttribute('d', 'M -10,277 Q 5,277 14,287 L 22,287 L 22,277 Z');
pawl2U.setAttribute('d', 'M -10,250 Q 5,250 12,242 L 18,242 L 18,250 Z');
pawl2L.setAttribute('d', 'M -10,270 Q 5,270 12,278 L 18,278 L 18,270 Z');
lockH1.setAttribute('opacity', '0');
lockH2.setAttribute('opacity', '0');
}
// 实时尺寸标尺更新 (从 200mm 到 550mm)
const currentLengthMm = Math.round(200 + (innerX / MAX_DISP_INNER) * 350);
const endPixelX = 390 + innerX;
dimLine.setAttribute('x2', endPixelX);
dimTickEnd.setAttribute('x1', endPixelX);
dimTickEnd.setAttribute('x2', endPixelX);
const badgeX = (130 + endPixelX) / 2 - 40;
dimBadge.setAttribute('x', badgeX);
dimText.setAttribute('x', badgeX + 40);
dimText.textContent = `${currentLengthMm} mm`;
hudLength.textContent = `${currentLengthMm} mm`;
// 6N 恒力回缩矢量动态跟随末端
forceVec.setAttribute('transform', `translate(${innerX}, 0)`);
if (isRetracting) {
forceVec.setAttribute('opacity', '1');
vectorText.textContent = "F_spring = 6.0 N (正在高速回缩)";
} else {
forceVec.setAttribute('opacity', '0.7');
vectorText.textContent = "F_spring = 6.0 N (恒力待命)";
}
// --- 右上角小伞联动形态更新 ---
const expandRatio = innerX / MAX_DISP_INNER; // 0.0 ~ 1.0
// 伞面展开几何计算
const runnerY = 66 - expandRatio * 28; // 下巢向上滑动
const canopyTipY = 48 + expandRatio * 6;
const canopySpan = 15 + (1 - expandRatio) * 35; // 伞边宽度展开
const ribTipLX = 60 - (45 * (0.35 + expandRatio * 0.65));
const ribTipRX = 60 + (45 * (0.35 + expandRatio * 0.65));
miniRunner.setAttribute('y', runnerY);
miniRibL.setAttribute('x2', ribTipLX);
miniRibL.setAttribute('y2', canopyTipY);
miniRibR.setAttribute('x2', ribTipRX);
miniRibR.setAttribute('y2', canopyTipY);
miniStrutL.setAttribute('y1', runnerY + 2);
miniStrutL.setAttribute('x2', 60 - 28 * expandRatio);
miniStrutL.setAttribute('y2', 20 + 18 * expandRatio);
miniStrutR.setAttribute('y1', runnerY + 2);
miniStrutR.setAttribute('x2', 60 + 28 * expandRatio);
miniStrutR.setAttribute('y2', 20 + 18 * expandRatio);
const curveControlY = 10 - expandRatio * 4;
miniCanopy.setAttribute('d', `M ${ribTipLX} ${canopyTipY} Q 60 ${curveControlY} ${ribTipRX} ${canopyTipY}`);
}
// 更新分相按钮高亮
function updateActivePill(index) {
stepPills.forEach((pill, idx) => {
if (idx === index) pill.classList.add('active');
else pill.classList.remove('active');
});
}
// --- 动画主循环引擎 (自动播放 & 随时重开) ---
function animationLoop(timestamp) {
if (isPlaying) {
const elapsed = (timestamp - startTime) * animSpeed;
const progress = (elapsed % TOTAL_DURATION) / TOTAL_DURATION;
updatePhysics(progress);
}
requestAnimationFrame(animationLoop);
}
// 交互控制:播放/暂停
btnPlayPause.addEventListener('click', () => {
isPlaying = !isPlaying;
if (isPlaying) {
startTime = performance.now() - (currentProgress * TOTAL_DURATION) / animSpeed;
btnPlayPause.classList.add('active');
playIcon.textContent = "⏸";
playText.textContent = "自动演示中";
} else {
btnPlayPause.classList.remove('active');
playIcon.textContent = "▶";
playText.textContent = "已暂停";
}
});
// 进度条手动拖动
slider.addEventListener('input', (e) => {
isPlaying = false;
btnPlayPause.classList.remove('active');
playIcon.textContent = "▶";
playText.textContent = "手动单步";
const progress = parseFloat(e.target.value) / 1000;
updatePhysics(progress);
});
// 分相跳转
window.seekToPhase = function(targetProgress) {
isPlaying = false;
btnPlayPause.classList.remove('active');
playIcon.textContent = "▶";
playText.textContent = "单步驻留";
updatePhysics(targetProgress);
};
// 速度调节
window.setSpeed = function(spd) {
const now = performance.now();
const currentElapsed = (now - startTime) * animSpeed;
animSpeed = spd;
startTime = now - (currentElapsed / animSpeed);
document.querySelectorAll('.controls-row .btn').forEach(b => {
if (b.textContent.includes(spd + 'x')) b.classList.add('active');
else if (b.textContent.includes('x')) b.classList.remove('active');
});
};
// 页面完全就绪与 iframe 重载时自动自启播放
document.addEventListener('DOMContentLoaded', () => {
startTime = performance.now();
requestAnimationFrame(animationLoop);
});
window.addEventListener('pageshow', () => {
startTime = performance.now();
isPlaying = true;
});
</script>
</body>
</html>
积分规则:每轮对话扣10分
等待动画代码生成...
