<!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">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<style>
:root {
--bg:#080c14;--bg2:#0e1422;--card:#131b2a;--border:#1e2d42;
--text:#d8e0ec;--muted:#6b7a90;--accent:#00e5ff;
--gold:#ffb300;--gold-dim:#5c4a10;--red:#ff5252;
--seg:#1a2636;--seg-s:#2e4058;--teeth-off:#3a4a5e;
}
*{margin:0;padding:0;box-sizing:border-box}
body{
background:var(--bg);color:var(--text);
font-family:'Share Tech Mono',monospace;
min-height:100vh;display:flex;flex-direction:column;align-items:center;
overflow-x:hidden;
background-image:
radial-gradient(ellipse 80% 60% at 50% 30%,rgba(0,229,255,.04),transparent),
radial-gradient(ellipse 60% 50% at 80% 70%,rgba(255,179,0,.03),transparent);
}
header{
text-align:center;padding:28px 20px 10px;width:100%;max-width:1100px;
}
header h1{
font-family:'Rajdhani',sans-serif;font-weight:700;font-size:2.2rem;
letter-spacing:.08em;color:var(--text);
background:linear-gradient(90deg,var(--accent),var(--gold));
-webkit-background-clip:text;-webkit-text-fill-color:transparent;
}
header p{
font-size:.82rem;color:var(--muted);margin-top:4px;letter-spacing:.15em;
text-transform:uppercase;
}
.main-wrap{
width:100%;max-width:1100px;padding:0 16px;
display:flex;flex-direction:column;gap:14px;
}
.svg-box{
background:var(--bg2);border:1px solid var(--border);border-radius:12px;
overflow:hidden;position:relative;
}
.svg-box svg{display:block;width:100%;height:auto}
.panels{
display:grid;grid-template-columns:1fr 1fr;gap:14px;
}
@media(max-width:700px){.panels{grid-template-columns:1fr}}
.panel{
background:var(--card);border:1px solid var(--border);border-radius:10px;
padding:16px;position:relative;overflow:hidden;
}
.panel::before{
content:'';position:absolute;top:0;left:0;right:0;height:2px;
background:linear-gradient(90deg,transparent,var(--accent),transparent);opacity:.4;
}
.panel-title{
font-family:'Rajdhani',sans-serif;font-weight:600;font-size:.85rem;
color:var(--accent);letter-spacing:.12em;text-transform:uppercase;margin-bottom:10px;
}
.info-row{
display:flex;justify-content:space-between;align-items:center;
padding:6px 0;border-bottom:1px solid rgba(255,255,255,.04);font-size:.78rem;
}
.info-row:last-child{border:none}
.info-label{color:var(--muted)}
.info-value{font-weight:600}
.info-value.lock{color:var(--gold)}
.info-value.unlock{color:var(--red)}
.info-value.trans{color:var(--accent)}
.controls-bar{
background:var(--card);border:1px solid var(--border);border-radius:10px;
padding:16px 20px;display:flex;flex-wrap:wrap;align-items:center;gap:14px;
}
.slider-group{flex:1;min-width:200px;display:flex;flex-direction:column;gap:4px}
.slider-group label{font-size:.72rem;color:var(--muted);letter-spacing:.1em;text-transform:uppercase}
input[type=range]{
-webkit-appearance:none;width:100%;height:6px;border-radius:3px;
background:linear-gradient(90deg,var(--red),var(--accent),var(--gold));
outline:none;cursor:pointer;
}
input[type=range]::-webkit-slider-thumb{
-webkit-appearance:none;width:20px;height:20px;border-radius:50%;
background:var(--text);border:3px solid var(--accent);cursor:grab;
box-shadow:0 0 10px rgba(0,229,255,.4);
}
.btn{
font-family:'Rajdhani',sans-serif;font-weight:600;font-size:.82rem;
letter-spacing:.08em;padding:8px 18px;border:1px solid var(--border);
border-radius:6px;background:var(--bg2);color:var(--text);cursor:pointer;
transition:all .2s;display:flex;align-items:center;gap:6px;
}
.btn:hover{border-color:var(--accent);color:var(--accent);background:rgba(0,229,255,.06)}
.btn.active{border-color:var(--gold);color:var(--gold);background:rgba(255,179,0,.08)}
.speed-group{display:flex;align-items:center;gap:8px;font-size:.72rem;color:var(--muted)}
.speed-group input[type=range]{width:80px;height:4px;
background:linear-gradient(90deg,var(--muted),var(--accent))}
.ifr-footer{
max-width:1100px;width:100%;padding:14px 20px 30px;
font-size:.74rem;color:var(--muted);line-height:1.7;
}
.ifr-footer strong{color:var(--gold);font-weight:600}
@keyframes pulse-glow{0%,100%{opacity:.6}50%{opacity:1}}
</style>
</head>
<body>
<header>
<h1>连环体伞骨 · 最终理想解原理动画</h1>
<p>Chain-Link Umbrella Rib — Ideal Final Result Demonstration</p>
</header>
<div class="main-wrap">
<!-- 主动画 -->
<div class="svg-box">
<svg id="mainSvg" viewBox="0 0 1060 440" xmlns="http://www.w3.org/2000/svg"></svg>
</div>
<!-- 面板 -->
<div class="panels">
<!-- 细节视图 -->
<div class="panel">
<div class="panel-title"><i class="fa fa-search-plus"></i> 锯齿啮合细节</div>
<svg id="detailSvg" viewBox="0 0 480 220" xmlns="http://www.w3.org/2000/svg"></svg>
</div>
<!-- 状态信息 -->
<div class="panel">
<div class="panel-title"><i class="fa fa-info-circle"></i> 机构状态</div>
<div id="infoPanel">
<div class="info-row"><span class="info-label">当前状态</span><span class="info-value" id="stState">刚性锁定</span></div>
<div class="info-row"><span class="info-label">锯齿啮合度</span><span class="info-value" id="stEngage">100%</span></div>
<div class="info-row"><span class="info-label">轴向力方向</span><span class="info-value" id="stForce">压缩</span></div>
<div class="info-row"><span class="info-label">镍钛超弹丝</span><span class="info-value" id="stWire">张紧承压</span></div>
<div class="info-row"><span class="info-label">链节自由度</span><span class="info-value" id="stDof">0° (锁定)</span></div>
<div class="info-row"><span class="info-label">环体参数</span><span class="info-value" style="color:var(--muted)">5mm×⌀3mm Ti</span></div>
<div class="info-row"><span class="info-label">丝径 / 齿高</span><span class="info-value" style="color:var(--muted)">⌀1.0mm / 0.3mm</span></div>
<div class="info-row"><span class="info-label">锯齿互锁角</span><span class="info-value" style="color:var(--muted)">120°</span></div>
</div>
</div>
</div>
<!-- 控制栏 -->
<div class="controls-bar">
<div class="slider-group">
<label>开合度 (Openness)</label>
<input type="range" id="openSlider" min="0" max="100" value="100">
</div>
<button class="btn" id="btnAuto"><i class="fa fa-play"></i> 自动演示</button>
<button class="btn" id="btnReset"><i class="fa fa-undo"></i> 重置</button>
<div class="speed-group">
<span>速度</span>
<input type="range" id="speedSlider" min="20" max="200" value="80">
</div>
</div>
</div>
<div class="ifr-footer">
<strong>IFR 核心原理:</strong>利用开合运动中推块自身的轴向推力驱动锯齿啮合,以零额外动力源、极小增重实现「受压刚化、卸载柔化」的可逆刚柔转换——矛盾在系统内部自消除,理想解即资源自足。
</div>
<script>
// ============ 常量 ============
const NS='http://www.w3.org/2000/svg';
const C={
N:10,SEG_W:52,SEG_H:22,TOOTH_H:6,TOOTH_N:5,
GAP_MAX:5,FIXED_X:115,FIXED_Y:195,RAIL_Y:195
};
// ============ 状态 ============
let openness=1, autoPlay=false, autoDir=-1, autoTime=0, speed=80;
let mainSvg, detailSvg, segGroups=[], jointGlows=[], wirePath, pushBlock, pushRod;
let forceArrows=[], stateLabel, engageIndicators=[];
let detSegGroups=[], detTeethPaths=[], detWirePath;
// ============ 工具函数 ============
function el(tag,attrs,parent){
const e=document.createElementNS(NS,tag);
for(const[k,v] of Object.entries(attrs||{})) e.setAttribute(k,v);
if(parent) parent.appendChild(e);
return e;
}
function lerp(a,b,t){return a+(b-a)*t}
function clamp(v,lo,hi){return Math.max(lo,Math.min(hi,v))}
// ============ 计算链节位置 ============
function computeChain(open){
const joints=[{x:C.FIXED_X,y:C.FIXED_Y}];
const segs=[];
let x=C.FIXED_X, y=C.FIXED_Y;
for(let i=0;i<C.N;i++){
const progress=i/(C.N-1);
const maxAng=82;
// 角度沿链条逐渐增大(闭合时形成自然悬垂曲线)
const ang=open*0+(1-open)*maxAng*progress;
const gap=(1-open)*C.GAP_MAX;
const total=C.SEG_W+gap;
const rad=ang*Math.PI/180;
const cx=x+total/2*Math.cos(rad);
const cy=y+total/2*Math.sin(rad);
segs.push({x:cx,y:cy,angle:ang,engage:open});
x+=total*Math.cos(rad);
y+=total*Math.sin(rad);
joints.push({x,y});
}
return {joints,segs,lastX:x,lastY:y};
}
// ============ 创建主视图 ============
function createMainView(){
mainSvg=document.getElementById('mainSvg');
// 背景网格
const gridG=el('g',{opacity:.08},mainSvg);
for(let x=0;x<=1060;x+=40) el('line',{x1:x,y1:0,x2:x,y2:440,stroke:'#4af'},gridG);
for(let y=0;y<=440;y+=40) el('line',{x1:0,y1:y,x2:1060,y2:y,stroke:'#4af'},gridG);
// 定义滤镜和渐变
const defs=el('defs',{},mainSvg);
// 发光滤镜
const fGlow=el('filter',{id:'glow',x:-50%,y:-50%,width:200%,height:200%},defs);
el('feGaussianBlur',{in:'SourceGraphic',stdDeviation:4,result:'b'},fGlow);
const fMerge=el('feMerge',{},fGlow);
el('feMergeNode',{in:'b'},fMerge);
el('feMergeNode',{in:'SourceGraphic'},fMerge);
// 金色发光
const fGold=el('filter',{id:'glowGold',x:-50%,y:-50%,width:200%,height:200%},defs);
el('feGaussianBlur',{in:'SourceGraphic',stdDeviation:3,result:'b'},fGold);
const fMerge2=el('feMerge',{},fGold);
el('feMergeNode',{in:'b'},fMerge2);
el('feMergeNode',{in:'SourceGraphic'},fMerge2);
// 箭头标记
const mArrow=el('marker',{id:'arrowR',markerWidth:8,markerHeight:6,refX:8,refY:3,orient:'auto'},defs);
el('polygon',{points:'0 0,8 3,0 6',fill:'var(--red)'},mArrow);
const mArrowC=el('marker',{id:'arrowC',markerWidth:8,markerHeight:6,refX:8,refY:3,orient:'auto'},defs);
el('polygon',{points:'0 0,8 3,0 6',fill:'var(--accent)'},mArrowC);
// 导轨
el('line',{x1:80,y1:C.RAIL_Y,x2:1020,y2:C.RAIL_Y,stroke:'#1e2d42','stroke-width':2,'stroke-dasharray':'6 4'},mainSvg);
// 固定端(伞尖端)
const fixG=el('g',{},mainSvg);
el('rect',{x:C.FIXED_X-14,y:C.RAIL_Y-30,width:14,height:60,rx:3,fill:'#1e2d42',stroke:'#2e4058','stroke-width':1.5},fixG);
el('polygon',{points:`${C.FIXED_X-7},${C.RAIL_Y-38} ${C.FIXED_X-18},${C.RAIL_Y-30} ${C.FIXED_X+4},${C.RAIL_Y-30}`,fill:'var(--accent)',opacity:.6},fixG);
el('text',{x:C.FIXED_X-7,y:C.RAIL_Y+50,'text-anchor':'middle',fill:'var(--muted)','font-size':'10','font-family':'Share Tech Mono'},fixG).textContent='固定端(伞尖)';
// 推杆和推块(稍后更新位置)
pushRod=el('line',{x1:0,y1:C.RAIL_Y,x2:0,y2:C.RAIL_Y,stroke:'#3a5068','stroke-width':3},mainSvg);
pushBlock=el('g',{},mainSvg);
el('rect',{x:-15,y:C.RAIL_Y-28,width:30,height:56,rx:4,fill:'#1a2a3c',stroke:'var(--accent)','stroke-width':1.5},pushBlock);
el('line',{x1:-6,y1:C.RAIL_Y-8,x2:6,y2:C.RAIL_Y-8,stroke:'var(--accent)','stroke-width':1.5,opacity:.5},pushBlock);
el('line',{x1:-6,y1:C.RAIL_Y,x2:6,y2:C.RAIL_Y,stroke:'var(--accent)','stroke-width':1.5,opacity:.5},pushBlock);
el('line',{x1:-6,y1:C.RAIL_Y+8,x2:6,y2:C.RAIL_Y+8,stroke:'var(--accent)','stroke-width':1.5,opacity:.5},pushBlock);
// 镍钛丝
wirePath=el('path',{fill:'none',stroke:'var(--accent)','stroke-width':2,'stroke-linecap':'round'},mainSvg);
// 链节
for(let i=0;i<C.N;i++){
const g=el('g',{},mainSvg);
// 节段主体
el('rect',{x:-C.SEG_W/2,y:-C.SEG_H/2,width:C.SEG_W,height:C.SEG_H,rx:3,
fill:'#1a2636',stroke:'#2e4058','stroke-width':1.2,'class':'seg-body'},g);
// 左侧锯齿指示(简化三角)
for(let t=0;t<3;t++){
const ty=-C.SEG_H/2+C.SEG_H*(t+0.5)/3;
el('polygon',{points:`${-C.SEG_W/2},${ty-3} ${-C.SEG_W/2-5},${ty} ${-C.SEG_W/2},${ty+3}`,
fill:'#2e4058','class':'tooth-l',opacity:.7},g);
}
// 右侧锯齿指示
for(let t=0;t<3;t++){
const ty=-C.SEG_H/2+C.SEG_H*(t+0.5)/3;
el('polygon',{points:`${C.SEG_W/2},${ty-3} ${C.SEG_W/2+5},${ty} ${C.SEG_W/2},${ty+3}`,
fill:'#2e4058','class':'tooth-r',opacity:.7},g);
}
// 中心丝孔
el('circle',{cx:0,cy:0,r:2.5,fill:'none',stroke:'#2e4058','stroke-width':.8},g);
// 编号
el('text',{x:0,y:1,'text-anchor':'middle','dominant-baseline':'middle',
fill:'#4a5a70','font-size':'8','font-family':'Share Tech Mono'},g).textContent=i+1;
segGroups.push(g);
}
// 啮合高亮点(节点处)
for(let i=0;i<C.N-1;i++){
const glow=el('circle',{r:8,fill:'var(--gold)',opacity:0,filter:'url(#glowGold)'},mainSvg);
jointGlows.push(glow);
}
// 力方向箭头
for(let i=0;i<3;i++){
const arr=el('line',{'stroke-width':2,'marker-end':'url(#arrowR)',opacity:0},mainSvg);
forceArrows.push(arr);
}
// 张力箭头
const tensArr=el('line',{'stroke-width':2,'marker-end':'url(#arrowC)',opacity:0,stroke:'var(--accent)'},mainSvg);
forceArrows.push(tensArr);
// 状态标签
stateLabel=el('text',{x:530,y:40,'text-anchor':'middle',
'font-family':'Rajdhani, sans-serif','font-weight':700,'font-size':'22',
fill:'var(--gold)',letterSpacing:3},mainSvg);
// 推块标签
const pbLabel=el('text',{x:0,y:C.RAIL_Y+50,'text-anchor':'middle',fill:'var(--accent)',
'font-size':'10','font-family':'Share Tech Mono'},mainSvg);
pbLabel.textContent='推块';
pushBlock._label=pbLabel;
// 伞形轮廓上下文
const umbG=el('g',{transform:'translate(940,60)',opacity:.35},mainSvg);
el('line',{x1:0,y1:-25,x2:0,y2:45,stroke:'#4a6a8a','stroke-width':2},umbG);
const dPath='M -50 10 Q -50 -20 0 -30 Q 50 -20 50 10';
el('path',{d:dPath,fill:'none',stroke:'#4a6a8a','stroke-width':1.5},umbG);
el('line',{x1:0,y1:-30,x2:-50,y2:10,stroke:'#4a6a8a','stroke-width':1,'stroke-dasharray':'3 2'},umbG);
el('line',{x1:0,y1:-30,x2:50,y2:10,stroke:'#4a6a8a','stroke-width':1,'stroke-dasharray':'3 2'},umbG);
// 高亮伞骨
el('line',{x1:0,y1:5,x2:-42,y2:8,stroke:'var(--gold)','stroke-width':2.5},umbG);
el('text',{x:0,y:60,'text-anchor':'middle',fill:'#4a6a8a','font-size':'9','font-family':'Share Tech Mono'},umbG).textContent='应用场景';
// IFR 资源利用注释
const noteG=el('g',{transform:'translate(530,400)'},mainSvg);
el('rect',{x:-220,y:-16,width:440,height:30,rx:6,fill:'rgba(0,229,255,.06)',stroke:'rgba(0,229,255,.15)','stroke-width':1},noteG);
el('text',{x:0,y:2,'text-anchor':'middle',fill:'var(--accent)','font-size':'11','font-family':'Share Tech Mono'},noteG)
.textContent='IFR: 推力即资源 → 受压刚化 / 卸载柔化 / 零额外驱动';
}
// ============ 创建细节视图 ============
function createDetailView(){
detailSvg=document.getElementById('detailSvg');
const defs=el('defs',{},detailSvg);
const fG=el('filter',{id:'dGlow',x:-50%,y:-50%,width:200%,height:200%},defs);
el('feGaussianBlur',{in:'SourceGraphic',stdDeviation:2.5,result:'b'},fG);
const fm=el('feMerge',{},fG);
el('feMergeNode',{in:'b'},fm);
el('feMergeNode',{in:'SourceGraphic'},fm);
// 标注线和标签
const labels=[
{x:30,y:20,text:'锯齿面 (120°)'},
{x:240,y:20,text:'镍钛诺超弹丝 ⌀1.0mm'},
{x:400,y:20,text:'钛合金环体 5mm'},
];
labels.forEach(l=>{
el('text',{x:l.x,y:l.y,fill:'var(--muted)','font-size':'9','font-family':'Share Tech Mono'},detailSvg).textContent=l.text;
});
// 3个放大的节段
const detW=90, detH=48, detTH=14;
const baseX=70, baseY=115, spacing=10;
for(let i=0;i<3;i++){
const bx=baseX+i*(detW+spacing);
const g=el('g',{},detailSvg);
// 节段体
el('rect',{x:0,y:0,width:detW,height:detH,rx:4,fill:'#1a2636',stroke:'#2e4058','stroke-width':1.2},g);
// 左侧锯齿
const leftTeeth=el('path',{fill:'none',stroke:'#2e4058','stroke-width':1.5,'class':'dt-path'},g);
// 右侧锯齿
const rightTeeth=el('path',{fill:'none',stroke:'#2e4058','stroke-width':1.5,'class':'dt-path'},g);
// 中心丝
el('circle',{cx:detW/2,cy:detH/2,r:4,fill:'none',stroke:'#2e4058','stroke-width':1},g);
// 丝线
el('line',{x1:-20,y1:detH/2,x2:detW+20,y2:detH/2,stroke:'var(--accent)','stroke-width':1.5,opacity:.5,'stroke-dasharray':'4 3'},g);
detSegGroups.push({g,leftTeeth,rightTeeth,bx,by:baseY,detW,detH});
g.setAttribute('transform',`translate(${bx},${baseY})`);
detailSvg.appendChild(g);
// 生成锯齿路径
const nTeeth=5;
const toothW=detH/nTeeth;
// 右侧锯齿(从上到下)
let rd=`M ${detW} 0`;
for(let t=0;t<nTeeth;t++){
const y1=t*toothW, y2=y1+toothW/2, y3=y1+toothW;
rd+=` L ${detW+detTH} ${y2} L ${detW} ${y3}`;
}
rightTeeth.setAttribute('d',rd);
// 左侧锯齿(从下到上,偏移半个齿距实现互锁)
let ld=`M 0 ${detH}`;
for(let t=0;t<nTeeth;t++){
const y3=detH-t*toothW, y2=y3-toothW/2, y1=y3-toothW;
ld+=` L ${-detTH} ${y2} L 0 ${y1}`;
}
leftTeeth.setAttribute('d',ld);
detTeethPaths.push({left:leftTeeth,right:rightTeeth});
}
// 啮合状态指示
const engRect1=el('rect',{x:baseX+detW-2,y:baseY-5,width:spacing+4,height:detH+10,rx:2,
fill:'none',stroke:'var(--gold)','stroke-width':1.5,opacity:0,'stroke-dasharray':'3 2'},detailSvg);
const engRect2=el('rect',{x:baseX+2*(detW+spacing)-2,y:baseY-5,width:spacing+4,height:detH+10,rx:2,
fill:'none',stroke:'var(--gold)','stroke-width':1.5,opacity:0,'stroke-dasharray':'3 2'},detailSvg);
detailSvg._engRects=[engRect1,engRect2];
// 啮合/脱开标签
const engLabel=el('text',{x:240,y:190,'text-anchor':'middle',fill:'var(--gold)',
'font-size':'12','font-family':'Rajdhani, sans-serif','font-weight':600},detailSvg);
detailSvg._engLabel=engLabel;
// 力方向指示
const fArr1=el('line',{x1:baseX-18,y1:baseY+detH/2,x2:baseX-4,y2:baseY+detH/2,
stroke:'var(--red)','stroke-width':2,'marker-end':'url(#arrowR)'},detailSvg);
const fArr2=el('line',{x1:baseX+3*(detW+spacing)+4,y1:baseY+detH/2,x2:baseX+3*(detW+spacing)+18,y2:baseY+detH/2,
stroke:'var(--red)','stroke-width':2,'marker-end':'url(#arrowR)'},detailSvg);
// 箭头标记(细节视图内)
const dm=el('marker',{id:'arrowR2',markerWidth:8,markerHeight:6,refX:8,refY:3,orient:'auto'},detailSvg.querySelector('defs'));
el('polygon',{points:'0 0,8 3,0 6',fill:'var(--red)'},dm);
fArr1.setAttribute('marker-end','url(#arrowR2)');
fArr2.setAttribute('marker-end','url(#arrowR2)');
detailSvg._fArrs=[fArr1,fArr2];
}
// ============ 更新主视图 ============
function updateMain(){
const chain=computeChain(openness);
const {joints,segs,lastX,lastY}=chain;
// 更新节段位置
for(let i=0;i<C.N;i++){
const s=segs[i];
const g=segGroups[i];
g.setAttribute('transform',`translate(${s.x},${s.y}) rotate(${s.angle})`);
// 更新锯齿颜色
const eng=s.engage;
const teethColor=eng>0.5?
`rgba(255,179,0,${lerp(0.3,0.9,(eng-0.5)*2)})`:
`rgba(46,64,88,${lerp(0.5,0.3,eng*2)})`;
g.querySelectorAll('.tooth-l,.tooth-r').forEach(t=>t.setAttribute('fill',teethColor));
// 节段体边框
const body=g.querySelector('.seg-body');
if(eng>0.7){
body.setAttribute('stroke','#5a6a3c');
body.setAttribute('fill','#1e2a28');
}else if(eng<0.3){
body.setAttribute('stroke','#2e4058');
body.setAttribute('fill','#1a2636');
}else{
body.setAttribute('stroke','#3a5a5e');
body.setAttribute('fill','#1c2a30');
}
}
// 更新啮合高亮
for(let i=0;i<C.N-1;i++){
const j=joints[i+1];
const glow=jointGlows[i];
glow.setAttribute('cx',j.x);
glow.setAttribute('cy',j.y);
glow.setAttribute('opacity',openness>0.6?lerp(0,0.5,(openness-0.6)/0.4):0);
}
// 更新镍钛丝
let wd=`M ${C.FIXED_X} ${C.FIXED_Y}`;
for(let i=0;i<C.N;i++){
wd+=` L ${segs[i].x} ${segs[i].y}`;
}
wd+=` L ${lastX} ${lastY}`;
wirePath.setAttribute('d',wd);
wirePath.setAttribute('stroke',openness>0.5?'var(--accent)':'#2a4a5e');
wirePath.setAttribute('stroke-width',openness>0.5?2:1.5);
// 更新推块
pushBlock.setAttribute('transform',`translate(${lastX},${0})`);
pushBlock._label.setAttribute('x',lastX);
// 推杆
pushRod.setAttribute('x1',lastX+15);
pushRod.setAttribute('y1',C.RAIL_Y);
pushRod.setAttribute('x2',lastX+80);
pushRod.setAttribute('y2',C.RAIL_Y);
// 力方向箭头(压缩时显示)
const showForce=openness>0.3;
if(showForce){
const arrOpacity=lerp(0,0.7,(openness-0.3)/0.7);
// 沿链方向画3个箭头
for(let a=0;a<3;a++){
const idx=Math.floor((a+1)*C.N/4);
const s=segs[Math.min(idx,C.N-1)];
const rad=s.angle*Math.PI/180;
const ax=s.x-20*Math.cos(rad);
const ay=s.y-20*Math.sin(rad);
const bx=s.x+20*Math.cos(rad);
const by=s.y+20*Math.sin(rad);
forceArrows[a].setAttribute('x1',ax);
forceArrows[a].setAttribute('y1',ay);
forceArrows[a].setAttribute('x2',bx);
forceArrows[a].setAttribute('y2',by);
forceArrows[a].setAttribute('opacity',arrOpacity);
forceArrows[a].setAttribute('stroke','var(--red)');
forceArrows[a].setAttribute('marker-end','url(#arrowR)');
}
}else{
for(let a=0;a<3;a++) forceArrows[a].setAttribute('opacity',0);
}
// 张力箭头(拉力方向)
const showTension=openness<0.5;
if(showTension){
const tOp=lerp(0,0.6,(0.5-openness)/0.5);
forceArrows[3].setAttribute('x1',lastX+20);
forceArrows[3].setAttribute('y1',C.RAIL_Y);
forceArrows[3].setAttribute('x2',lastX+60);
forceArrows[3].setAttribute('y2',C.RAIL_Y);
forceArrows[3].setAttribute('opacity',tOp);
}else{
forceArrows[3].setAttribute('opacity',0);
}
// 状态标签
if(openness>0.75){
stateLabel.textContent='刚性锁定 RIGID LOCK';
stateLabel.setAttribute('fill','var(--gold)');
}else if(openness<0.25){
stateLabel.textContent='柔性释放 FLEXIBLE RELEASE';
stateLabel.setAttribute('fill','var(--red)');
}else{
stateLabel.textContent='过渡中 TRANSITIONING';
stateLabel.setAttribute('fill','var(--accent)');
}
}
// ============ 更新细节视图 ============
function updateDetail(){
const eng=openness;
const detW=90,detH=48,detTH=14;
const baseX=70,baseY=115,spacing=10;
// 节段间距随啮合度变化
const gap=lerp(12,2,eng);
for(let i=0;i<3;i++){
const bx=baseX+i*(detW+gap);
detSegGroups[i].g.setAttribute('transform',`translate(${bx},${baseY})`);
// 锯齿颜色
const teethCol=eng>0.5?`rgba(255,179,0,${lerp(0.4,1,(eng-0.5)*2)})`:'rgba(46,64,88,0.6)';
detTeethPaths[i].left.setAttribute('stroke',teethCol);
detTeethPaths[i].right.setAttribute('stroke',teethCol);
detTeethPaths[i].left.setAttribute('stroke-width',eng>0.5?2:1.2);
detTeethPaths[i].right.setAttribute('stroke-width',eng>0.5?2:1.2);
if(eng>0.6){
detTeethPaths[i].left.setAttribute('filter','url(#dGlow)');
detTeethPaths[i].right.setAttribute('filter','url(#dGlow)');
}else{
detTeethPaths[i].left.removeAttribute('filter');
detTeethPaths[i].right.removeAttribute('filter');
}
}
// 啮合指示框
const rects=detailSvg._engRects;
rects.forEach((r,idx)=>{
const rx=baseX+(idx+1)*(detW+gap)-2;
r.setAttribute('x',rx);
r.setAttribute('opacity',eng>0.5?lerp(0,0.8,(eng-0.5)*2):0);
});
// 啮合标签
const engLabel=detailSvg._engLabel;
if(eng>0.7){
engLabel.textContent='锯齿紧密啮合 → 刚性传递弯矩';
engLabel.setAttribute('fill','var(--gold)');
}else if(eng<0.3){
engLabel.textContent='锯齿脱开 → 链节自由旋转';
engLabel.setAttribute('fill','var(--red)');
}else{
engLabel.textContent='啮合度变化中...';
engLabel.setAttribute('fill','var(--accent)');
}
// 力箭头
const fArrs=detailSvg._fArrs;
fArrs[0].setAttribute('x1',baseX-18);
fArrs[0].setAttribute('x2',baseX-4);
fArrs[1].setAttribute('x1',baseX+2*(detW+gap)+detW+4);
fArrs[1].setAttribute('x2',baseX+2*(detW+gap)+detW+18);
const fOp=eng>0.4?lerp(0,0.8,(eng-0.4)/0.6):0;
fArrs.forEach(a=>a.setAttribute('opacity',fOp));
}
// ============ 更新信息面板 ============
function updateInfo(){
const eng=openness;
const stState=document.getElementById('stState');
const stEngage=document.getElementById('stEngage');
const stForce=document.getElementById('stForce');
const stWire=document.getElementById('stWire');
const stDof=document.getElementById('stDof');
if(eng>0.75){
stState.textContent='刚性锁定';stState.className='info-value lock';
}else if(eng<0.25){
stState.textContent='柔性释放';stState.className='info-value unlock';
}else{
stState.textContent='过渡中';stState.className='info-value trans';
}
stEngage.textContent=Math.round(eng*100)+'%';
stEngage.className='info-value '+(eng>0.5?'lock':'unlock');
if(eng>0.5){
stForce.textContent='压缩 (推块上顶)';stForce.className='info-value lock';
}else{
stForce.textContent='拉伸 (推块下拉)';stForce.className='info-value unlock';
}
stWire.textContent=eng>0.5?'张紧承压':'松弛随动';
stWire.className='info-value '+(eng>0.5?'lock':'unlock');
const dof=eng<0.1?360:Math.round(lerp(360,0,clamp(eng*1.5,0,1)));
stDof.textContent=dof>=350?'全自由度':dof+'°';
stDof.className='info-value '+(dof>10?'unlock':'lock');
}
// ============ 全量更新 ============
function updateAll(){
updateMain();
updateDetail();
updateInfo();
}
// ============ 动画循环 ============
let lastT=0;
function animate(ts){
if(autoPlay){
const dt=(ts-lastT)/1000;
autoTime+=dt*speed/100;
// 使用平滑的三角波
openness=(Math.cos(autoTime*Math.PI*2)*0.5+0.5);
document.getElementById('openSlider').value=Math.round(openness*100);
updateAll();
}
lastT=ts;
requestAnimationFrame(animate);
}
// ============ 事件绑定 ============
function bindEvents(){
const slider=document.getElementById('openSlider');
slider.addEventListener('input',e=>{
openness=parseInt(e.target.value)/100;
updateAll();
});
document.getElementById('btnAuto').addEventListener('click',function(){
autoPlay=!autoPlay;
this.classList.toggle('active',autoPlay);
this.innerHTML=autoPlay?'<i class="fa fa-pause"></i> 暂停演示':'<i class="fa fa-play"></i> 自动演示';
if(autoPlay) autoTime=Math.acos(openness*2-1)/(Math.PI*2);
});
document.getElementById('btnReset').addEventListener('click',()=>{
openness=1;autoPlay=false;
document.getElementById('openSlider').value=100;
document.getElementById('btnAuto').classList.remove('active');
document.getElementById('btnAuto').innerHTML='<i class="fa fa-play"></i> 自动演示';
updateAll();
});
document.getElementById('speedSlider').addEventListener('input',e=>{
speed=parseInt(e.target.value);
});
}
// ============ 初始化 ============
function init(){
createMainView();
createDetailView();
updateAll();
bindEvents();
requestAnimationFrame(animate);
}
document.addEventListener('DOMContentLoaded',init);
</script>
</body>
</html>
实现说明:
本动画完整呈现了连环体伞骨的 IFR 原理,核心亮点如下:
主视图动态链节:10 节钛合金连环体在 SVG 中实时计算位置与旋转角——开合度 100% 时锯齿啮合、链条笔直呈刚性杆;开合度降至 0% 时锯齿脱开、链条在模拟重力下自然悬垂,呈现全柔性链节形态。过渡过程平滑流畅,锯齿颜色从金色(啮合)渐变至灰蓝色(脱开),直观映射力学状态。
锯齿啮合细节面板:3 节放大视图清晰展示 120° 互锁锯齿的啮合/脱开微观过程——齿面偏移半齿距实现交错互锁,啮合时齿形发金光并带辉光滤镜,脱开时节段间距拉大、齿形变暗。
力的可视化引导:压缩态下沿链节绘制红色力箭头展示轴向压力传递路径;拉伸态下显示青色张力箭头指示超弹丝回拉方向,帮助理解"推力即资源"的 IFR 核心。
交互控制:滑块可手动无级调节开合度;自动演示按钮触发平滑周期动画;速度滑块控制演示节奏,便于深入观察过渡瞬态。
状态面板实时反馈:当前刚性/柔性状态、啮合百分比、轴向力方向、丝线张紧度、链节自由度等关键参数随开合度同步更新,将工程机理量化呈现。
<!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">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<style>
:root{
--bg:#060a10;--bg2:#0c1220;--card:#111a2c;--border:#1a2c44;
--text:#d0daea;--muted:#5a6e88;--accent:#00dce8;
--gold:#f0a800;--gold-dim:#4a3800;--red:#ff4444;--green:#40e070;
}
*{margin:0;padding:0;box-sizing:border-box}
body{
background:var(--bg);color:var(--text);font-family:'Share Tech Mono',monospace;
min-height:100vh;display:flex;flex-direction:column;align-items:center;
overflow-x:hidden;
}
header{text-align:center;padding:24px 20px 8px;width:100%;max-width:1100px}
header h1{
font-family:'Rajdhani',sans-serif;font-weight:700;font-size:2rem;letter-spacing:.1em;
background:linear-gradient(135deg,var(--accent),var(--gold));
-webkit-background-clip:text;-webkit-text-fill-color:transparent;
}
header p{font-size:.78rem;color:var(--muted);margin-top:2px;letter-spacing:.18em;text-transform:uppercase}
.wrap{width:100%;max-width:1100px;padding:0 12px;display:flex;flex-direction:column;gap:10px}
.svg-box{background:var(--bg2);border:1px solid var(--border);border-radius:10px;overflow:hidden}
.svg-box svg{display:block;width:100%;height:auto}
.row{display:grid;grid-template-columns:1fr 1fr;gap:10px}
@media(max-width:720px){.row{grid-template-columns:1fr}}
.panel{background:var(--card);border:1px solid var(--border);border-radius:8px;padding:14px;position:relative}
.panel::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,var(--accent),transparent);opacity:.35}
.pt{font-family:'Rajdhani',sans-serif;font-weight:600;font-size:.8rem;color:var(--accent);letter-spacing:.12em;text-transform:uppercase;margin-bottom:8px;display:flex;align-items:center;gap:6px}
.ir{display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid rgba(255,255,255,.03);font-size:.74rem}
.ir:last-child{border:none}
.il{color:var(--muted)}
.iv{font-weight:600}
.iv.gd{color:var(--gold)}.iv.rd{color:var(--red)}.iv.cy{color:var(--accent)}.iv.gn{color:var(--green)}
.ctrl{background:var(--card);border:1px solid var(--border);border-radius:8px;padding:14px 18px;display:flex;flex-wrap:wrap;align-items:center;gap:14px}
.sg{flex:1;min-width:180px;display:flex;flex-direction:column;gap:3px}
.sg label{font-size:.68rem;color:var(--muted);letter-spacing:.1em;text-transform:uppercase}
input[type=range]{-webkit-appearance:none;width:100%;height:5px;border-radius:3px;outline:none;cursor:pointer}
#openSlider{background:linear-gradient(90deg,var(--red),var(--accent),var(--gold))}
#speedSlider{background:linear-gradient(90deg,var(--muted),var(--accent))}
input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:18px;height:18px;border-radius:50%;background:var(--text);border:3px solid var(--accent);cursor:grab;box-shadow:0 0 8px rgba(0,220,232,.4)}
.btn{
font-family:'Rajdhani',sans-serif;font-weight:600;font-size:.8rem;letter-spacing:.06em;
padding:7px 16px;border:1px solid var(--border);border-radius:5px;background:var(--bg2);
color:var(--text);cursor:pointer;transition:all .15s;display:flex;align-items:center;gap:5px;
}
.btn:hover{border-color:var(--accent);color:var(--accent);background:rgba(0,220,232,.05)}
.btn.on{border-color:var(--gold);color:var(--gold);background:rgba(240,168,0,.07)}
.spd{display:flex;align-items:center;gap:6px;font-size:.68rem;color:var(--muted)}
.ifr{max-width:1100px;width:100%;padding:10px 18px 28px;font-size:.72rem;color:var(--muted);line-height:1.7}
.ifr strong{color:var(--gold)}
</style>
</head>
<body>
<header>
<h1>连环体伞骨 · 最终理想解原理动画</h1>
<p>Chain-Link Rib — Ideal Final Result</p>
</header>
<div class="wrap">
<div class="svg-box"><svg id="mSvg" viewBox="0 0 1060 420"></svg></div>
<div class="row">
<div class="panel">
<div class="pt"><i class="fa fa-search-plus"></i> 锯齿啮合细节</div>
<svg id="dSvg" viewBox="0 0 500 210"></svg>
</div>
<div class="panel">
<div class="pt"><i class="fa fa-tachometer-alt"></i> 机构状态</div>
<div id="info">
<div class="ir"><span class="il">当前状态</span><span class="iv" id="s1">刚性锁定</span></div>
<div class="ir"><span class="il">锯齿啮合度</span><span class="iv" id="s2">100%</span></div>
<div class="ir"><span class="il">轴向力方向</span><span class="iv" id="s3">压缩</span></div>
<div class="ir"><span class="il">镍钛超弹丝</span><span class="iv" id="s4">张紧承压</span></div>
<div class="ir"><span class="il">链节自由度</span><span class="iv" id="s5">0°</span></div>
<div class="ir"><span class="il">环体参数</span><span class="iv" style="color:var(--muted)">5mm × ⌀3mm Ti</span></div>
<div class="ir"><span class="il">丝径 / 齿高</span><span class="iv" style="color:var(--muted)">⌀1.0mm / 0.3mm</span></div>
<div class="ir"><span class="il">互锁角</span><span class="iv" style="color:var(--muted)">120°</span></div>
</div>
</div>
</div>
<div class="ctrl">
<div class="sg"><label>开合度 Openness</label><input type="range" id="openSlider" min="0" max="1000" value="1000"></div>
<button class="btn" id="bAuto"><i class="fa fa-play"></i> 自动演示</button>
<button class="btn" id="bReset"><i class="fa fa-undo"></i> 重置</button>
<div class="spd"><span>速度</span><input type="range" id="speedSlider" min="20" max="250" value="90" style="width:80px"></div>
</div>
</div>
<div class="ifr"><strong>IFR 核心原理:</strong>利用开合运动中推块自身的轴向推力驱动锯齿啮合,以零额外动力源、极小增重实现「受压刚化、卸载柔化」的可逆刚柔转换——矛盾在系统内部自消除,理想解即资源自足。</div>
<script>
(function(){
"use strict";
const NS='http://www.w3.org/2000/svg';
/* ===== 参数 ===== */
const N=10, SW=52, SH=22, TH=6, GMAX=5.5;
const FX=120, FY=200, RY=200;
/* ===== 状态 ===== */
let openV=1, autoOn=false, aTime=0, spd=90, prevTS=null;
/* ===== 工具 ===== */
function $(id){return document.getElementById(id)}
function ce(tag,at,p){const e=document.createElementNS(NS,tag);for(const k in at)e.setAttribute(k,at[k]);if(p)p.appendChild(e);return e}
function lerp(a,b,t){return a+(b-a)*t}
function clamp(v,lo,hi){return Math.max(lo,Math.min(hi,v))}
/* ===== 链节计算 ===== */
function calcChain(op){
const js=[{x:FX,y:FY}], ss=[];
let x=FX, y=FY;
for(let i=0;i<N;i++){
const p=i/(N-1);
const ang=(1-op)*80*p; // 角度沿链递增
const gap=(1-op)*GMAX;
const tot=SW+gap;
const rad=ang*Math.PI/180;
ss.push({x:x+tot/2*Math.cos(rad), y:y+tot/2*Math.sin(rad), a:ang, e:op});
x+=tot*Math.cos(rad);
y+=tot*Math.sin(rad);
js.push({x,y});
}
return {js,ss,ex:x,ey:y};
}
/* ===== 主视图引用 ===== */
let mSg=[], mJg=[], mWire, mPB, mPR, mPBL, mFA=[], mSL, mGlowDots=[];
function buildMain(){
const svg=$('mSvg');
/* defs */
const df=ce('defs',{},svg);
/* 发光滤镜 */
const gf=ce('filter',{id:'gw',x:'-50%',y:'-50%',width:'200%',height:'200%'},df);
ce('feGaussianBlur',{in:'SourceGraphic',stdDeviation:'5',result:'b'},gf);
const gm=ce('feMerge',{},gf); ce('feMergeNode',{in:'b'},gm); ce('feMergeNode',{in:'SourceGraphic'},gm);
/* 金色发光 */
const gf2=ce('filter',{id:'gwG',x:'-50%',y:'-50%',width:'200%',height:'200%'},df);
ce('feGaussianBlur',{in:'SourceGraphic',stdDeviation:'3',result:'b'},gf2);
const gm2=ce('feMerge',{},gf2); ce('feMergeNode',{in:'b'},gm2); ce('feMergeNode',{in:'SourceGraphic'},gm2);
/* 红色发光 */
const gf3=ce('filter',{id:'gwR',x:'-50%',y:'-50%',width:'200%',height:'200%'},df);
ce('feGaussianBlur',{in:'SourceGraphic',stdDeviation:'3',result:'b'},gf3);
const gm3=ce('feMerge',{},gf3); ce('feMergeNode',{in:'b'},gm3); ce('feMergeNode',{in:'SourceGraphic'},gm3);
/* 箭头标记 */
const mk1=ce('marker',{id:'aR',markerWidth:8,markerHeight:6,refX:8,refY:3,orient:'auto'},df);
ce('polygon',{points:'0 0,8 3,0 6',fill:'#ff4444'},mk1);
const mk2=ce('marker',{id:'aC',markerWidth:8,markerHeight:6,refX:8,refY:3,orient:'auto'},df);
ce('polygon',{points:'0 0,8 3,0 6',fill:'#00dce8'},mk2);
/* 背景网格 */
const gg=ce('g',{opacity:'.06'},svg);
for(let x=0;x<=1060;x+=50) ce('line',{x1:x,y1:0,x2:x,y2:420,stroke:'#40c0e0'},gg);
for(let y=0;y<=420;y+=50) ce('line',{x1:0,y1:y,x2:1060,y2:y,stroke:'#40c0e0'},gg);
/* 导轨 */
ce('line',{x1:70,y1:RY,x2:1030,y2:RY,stroke:'#162038','stroke-width':'2','stroke-dasharray':'8 5'},svg);
/* 固定端 */
ce('rect',{x:FX-16,y:RY-32,width:16,height:64,rx:3,fill:'#15202e',stroke:'#28405a','stroke-width':'1.5'},svg);
ce('polygon',{points:`${FX-8},${RY-40} ${FX-20},${RY-32} ${FX+4},${RY-32}`,fill:'#00dce8',opacity:'.5'},svg);
const ft=ce('text',{x:FX-8,y:RY+55,'text-anchor':'middle',fill:'#5a6e88','font-size':'9','font-family':'Share Tech Mono'},svg);
ft.textContent='固定端(伞尖)';
/* 推杆 */
mPR=ce('line',{x1:0,y1:RY,x2:0,y2:RY,stroke:'#2a3e58','stroke-width':'3'},svg);
/* 推块 */
mPB=ce('g',{},svg);
ce('rect',{x:-16,y:RY-30,width:32,height:60,rx:4,fill:'#15202e',stroke:'#00dce8','stroke-width':'1.5'},mPB);
ce('line',{x1:-8,y1:RY-10,x2:8,y2:RY-10,stroke:'#00dce8','stroke-width':'1.2',opacity:'.4'},mPB);
ce('line',{x1:-8,y1:RY,x2:8,y2:RY,stroke:'#00dce8','stroke-width':'1.2',opacity:'.4'},mPB);
ce('line',{x1:-8,y1:RY+10,x2:8,y2:RY+10,stroke:'#00dce8','stroke-width':'1.2',opacity:'.4'},mPB);
mPBL=ce('text',{x:0,y:RY+52,'text-anchor':'middle',fill:'#00dce8','font-size':'9','font-family':'Share Tech Mono'},mPB);
mPBL.textContent='推块';
/* 超弹丝 */
mWire=ce('path',{fill:'none',stroke:'#00dce8','stroke-width':'2','stroke-linecap':'round',opacity:'.7'},svg);
/* 链节 */
for(let i=0;i<N;i++){
const g=ce('g',{},svg);
ce('rect',{x:-SW/2,y:-SH/2,width:SW,height:SH,rx:3,fill:'#16222e',stroke:'#2a3e55','stroke-width':'1.2'},g);
/* 锯齿指示 - 左右各3个小三角 */
for(let t=0;t<3;t++){
const ty=-SH/2+SH*(t+.5)/3;
ce('polygon',{points:`${-SW/2},${ty-3} ${-SW/2-5},${ty} ${-SW/2},${ty+3}`,fill:'#2a3e55',opacity:'.7'},g);
ce('polygon',{points:`${SW/2},${ty-3} ${SW/2+5},${ty} ${SW/2},${ty+3}`,fill:'#2a3e55',opacity:'.7'},g);
}
ce('circle',{cx:0,cy:0,r:2.2,fill:'none',stroke:'#2a3e55','stroke-width':'.8'},g);
const nt=ce('text',{x:0,y:1.5,'text-anchor':'middle','dominant-baseline':'middle',fill:'#3a4e68','font-size':'7.5','font-family':'Share Tech Mono'},g);
nt.textContent=i+1;
mSg.push(g);
}
/* 啮合点发光 */
for(let i=0;i<N-1;i++){
const c=ce('circle',{r:'6',fill:'#f0a800',opacity:'0',filter:'url(#gwG)'},svg);
mJg.push(c);
}
/* 压力/拉力箭头 */
for(let i=0;i<4;i++){
const ln=ce('line',{'stroke-width':'2',opacity:'0'},svg);
mFA.push(ln);
}
/* 状态标签 */
mSL=ce('text',{x:530,y:36,'text-anchor':'middle','font-family':'Rajdhani, sans-serif','font-weight':'700','font-size':'20',fill:'#f0a800',letterSpacing:'2'},svg);
/* 伞形上下文图标 */
const ug=ce('g',{transform:'translate(950,70)',opacity:'.3'},svg);
ce('line',{x1:0,y1:-20,x2:0,y2:40,stroke:'#4a6a8a','stroke-width':'2'},ug);
ce('path',{d:'M-45 8 Q-45 -18 0 -26 Q45 -18 45 8',fill:'none',stroke:'#4a6a8a','stroke-width':'1.5'},ug);
ce('line',{x1:0,y1:-26,x2:-42,y2:6,stroke:'#4a6a8a','stroke-width':'1','stroke-dasharray':'3 2'},ug);
ce('line',{x1:0,y1:-26,x2:42,y2:6,stroke:'#4a6a8a','stroke-width':'1','stroke-dasharray':'3 2'},ug);
ce('line',{x1:0,y1:4,x2:-38,y2:5,stroke:'#f0a800','stroke-width':'2.5'},ug);
const ut=ce('text',{x:0,y:56,'text-anchor':'middle',fill:'#4a6a8a','font-size':'8.5','font-family':'Share Tech Mono'},ug);
ut.textContent='应用场景';
/* IFR 资源注释条 */
const nb=ce('g',{transform:'translate(530,390)'},svg);
ce('rect',{x:-240,y:-14,width:480,height:28,rx:5,fill:'rgba(0,220,232,.05)',stroke:'rgba(0,220,232,.12)','stroke-width':'1'},nb);
const nt2=ce('text',{x:0,y:2,'text-anchor':'middle',fill:'#00dce8','font-size':'10.5','font-family':'Share Tech Mono'},nb);
nt2.textContent='IFR: 推力即资源 → 受压刚化 · 卸载柔化 · 零额外驱动';
}
/* ===== 细节视图引用 ===== */
let dSg=[], dTP=[], dER=[], dEL, dFA=[];
function buildDetail(){
const svg=$('dSvg');
const df=ce('defs',{},svg);
const gf=ce('filter',{id:'dGw',x:'-50%',y:'-50%',width:'200%',height:'200%'},df);
ce('feGaussianBlur',{in:'SourceGraphic',stdDeviation:'2.5',result:'b'},gf);
const gm=ce('feMerge',{},gf); ce('feMergeNode',{in:'b'},gm); ce('feMergeNode',{in:'SourceGraphic'},gm);
const mk=ce('marker',{id:'dAr',markerWidth:8,markerHeight:6,refX:8,refY:3,orient:'auto'},df);
ce('polygon',{points:'0 0,8 3,0 6',fill:'#ff4444'},mk);
/* 标题 */
ce('text',{x:20,y:16,fill:'#5a6e88','font-size':'8.5','font-family':'Share Tech Mono'},svg).textContent='锯齿面(120°)';
ce('text',{x:200,y:16,fill:'#5a6e88','font-size':'8.5','font-family':'Share Tech Mono'},svg).textContent='镍钛诺超弹丝 ⌀1.0mm';
ce('text',{x:390,y:16,fill:'#5a6e88','font-size':'8.5','font-family':'Share Tech Mono'},svg).textContent='钛合金环体 5mm';
/* 3个放大的节段 */
const dW=88, dH=48, dTH=13;
const bx0=65, by0=105, sp=10;
for(let i=0;i<3;i++){
const g=ce('g',{},svg);
ce('rect',{x:0,y:0,width:dW,height:dH,rx:4,fill:'#16222e',stroke:'#2a3e55','stroke-width':'1.2'},g);
/* 中心丝 */
ce('circle',{cx:dW/2,cy:dH/2,r:3.5,fill:'none',stroke:'#2a3e55','stroke-width':'1'},g);
ce('line',{x1:-16,y1:dH/2,x2:dW+16,y2:dH/2,stroke:'#00dce8','stroke-width':'1.5',opacity:'.45','stroke-dasharray':'4 3'},g);
/* 锯齿路径 */
const rp=ce('path',{fill:'none',stroke:'#2a3e55','stroke-width':'1.5'},g);
const lp=ce('path',{fill:'none',stroke:'#2a3e55','stroke-width':'1.5'},g);
/* 生成锯齿 */
const nt=5, tw=dH/nt;
let rd='M'+dW+' 0';
for(let t=0;t<nt;t++){
rd+=` L${dW+dTH} ${t*tw+tw/2} L${dW} ${(t+1)*tw}`;
}
rp.setAttribute('d',rd);
let ld='M0 '+dH;
for(let t=0;t<nt;t++){
const y3=dH-t*tw, y2=y3-tw/2, y1=y3-tw;
ld+=` L${-dTH} ${y2} L0 ${y1}`;
}
lp.setAttribute('d',ld);
g.setAttribute('transform',`translate(${bx0+i*(dW+sp)},${by0})`);
svg.appendChild(g);
dSg.push({g,rp,lp,bx:bx0,by:by0,dW,dH,sp});
dTP.push({rp,lp});
}
/* 啮合指示框 */
for(let k=0;k<2;k++){
const r=ce('rect',{x:0,y:by0-6,width:sp+6,height:dH+12,rx:3,fill:'none',stroke:'#f0a800','stroke-width':'1.5','stroke-dasharray':'4 2',opacity:'0'},svg);
dER.push(r);
}
/* 力箭头 */
dFA.push(ce('line',{x1:bx0-20,y1:by0+dH/2,x2:bx0-4,y2:by0+dH/2,stroke:'#ff4444','stroke-width':'2','marker-end':'url(#dAr)',opacity:'0'},svg));
dFA.push(ce('line',{x1:0,y1:by0+dH/2,x2:0,y2:by0+dH/2,stroke:'#ff4444','stroke-width':'2','marker-end':'url(#dAr)',opacity:'0'},svg));
/* 标签 */
dEL=ce('text',{x:250,y:185,'text-anchor':'middle',fill:'#f0a800','font-size':'11','font-family':'Rajdhani, sans-serif','font-weight':'600'},svg);
}
/* ===== 更新主视图 ===== */
function updMain(){
const ch=calcChain(openV);
const {js,ss,ex,ey}=ch;
/* 链节 */
for(let i=0;i<N;i++){
const s=ss[i], g=mSg[i];
g.setAttribute('transform',`translate(${s.x.toFixed(1)},${s.y.toFixed(1)}) rotate(${s.a.toFixed(1)})`);
const eng=s.e;
const tc=eng>.5? `rgba(240,168,0,${lerp(.3,.95,(eng-.5)*2).toFixed(2)})` : `rgba(42,62,85,${lerp(.5,.25,eng*2).toFixed(2)})`;
g.querySelectorAll('polygon').forEach(p=>p.setAttribute('fill',tc));
const bd=g.querySelector('rect');
bd.setAttribute('stroke',eng>.6?'#4a6040':'#2a3e55');
bd.setAttribute('fill',eng>.6?'#182420':'#16222e');
}
/* 啮合点发光 */
for(let i=0;i<N-1;i++){
const j=js[i+1], c=mJg[i];
c.setAttribute('cx',j.x.toFixed(1));
c.setAttribute('cy',j.y.toFixed(1));
c.setAttribute('opacity',openV>.55? lerp(0,.55,(openV-.55)/.45).toFixed(2) : '0');
}
/* 超弹丝 */
let wd='M'+FX+' '+FY;
for(let i=0;i<N;i++) wd+=` L${ss[i].x.toFixed(1)} ${ss[i].y.toFixed(1)}`;
wd+=` L${ex.toFixed(1)} ${ey.toFixed(1)}`;
mWire.setAttribute('d',wd);
mWire.setAttribute('stroke',openV>.4?'#00dce8':'#1a3a4e');
mWire.setAttribute('stroke-width',openV>.4?'2':'1.5');
/* 推块 */
mPB.setAttribute('transform',`translate(${ex.toFixed(1)},0)`);
mPBL.setAttribute('x','0');
mPR.setAttribute('x1',(ex+16).toFixed(1));
mPR.setAttribute('x2',(ex+85).toFixed(1));
/* 力箭头 */
if(openV>.35){
const ao=lerp(0,.65,(openV-.35)/.65).toFixed(2);
for(let a=0;a<3;a++){
const idx=Math.floor((a+1)*N/4);
const s=ss[Math.min(idx,N-1)];
const rad=s.a*Math.PI/180;
const len=22;
const x1=s.x-len*Math.cos(rad), y1=s.y-len*Math.sin(rad);
const x2=s.x+len*Math.cos(rad), y2=s.y+len*Math.sin(rad);
mFA[a].setAttribute('x1',x1.toFixed(1)); mFA[a].setAttribute('y1',y1.toFixed(1));
mFA[a].setAttribute('x2',x2.toFixed(1)); mFA[a].setAttribute('y2',y2.toFixed(1));
mFA[a].setAttribute('opacity',ao);
mFA[a].setAttribute('stroke','#ff4444');
mFA[a].setAttribute('marker-end','url(#aR)');
}
} else {
mFA[0].setAttribute('opacity','0'); mFA[1].setAttribute('opacity','0'); mFA[2].setAttribute('opacity','0');
}
/* 拉力箭头 */
if(openV<.45){
const to=lerp(0,.6,(.45-openV)/.45).toFixed(2);
mFA[3].setAttribute('x1',(ex+18).toFixed(1)); mFA[3].setAttribute('y1',RY);
mFA[3].setAttribute('x2',(ex+55).toFixed(1)); mFA[3].setAttribute('y2',RY);
mFA[3].setAttribute('opacity',to);
mFA[3].setAttribute('stroke','#00dce8');
mFA[3].setAttribute('marker-end','url(#aC)');
} else {
mFA[3].setAttribute('opacity','0');
}
/* 状态标签 */
if(openV>.75){
mSL.textContent='RIGID LOCK · 刚性锁定'; mSL.setAttribute('fill','#f0a800');
} else if(openV<.25){
mSL.textContent='FLEXIBLE RELEASE · 柔性释放'; mSL.setAttribute('fill','#ff4444');
} else {
mSL.textContent='TRANSITIONING · 过渡中'; mSL.setAttribute('fill','#00dce8');
}
}
/* ===== 更新细节视图 ===== */
function updDetail(){
const eng=openV;
const gap=lerp(14,2,eng);
const bx0=65, by0=105;
for(let i=0;i<3;i++){
const d=dSg[i];
const bx=bx0+i*(d.dW+gap);
d.g.setAttribute('transform',`translate(${bx.toFixed(1)},${d.by})`);
const tc=eng>.5? `rgba(240,168,0,${lerp(.4,1,(eng-.5)*2).toFixed(2)})` : 'rgba(42,62,85,.6)';
dTP[i].rp.setAttribute('stroke',tc);
dTP[i].lp.setAttribute('stroke',tc);
dTP[i].rp.setAttribute('stroke-width',eng>.5?'2':'1.2');
dTP[i].lp.setAttribute('stroke-width',eng>.5?'2':'1.2');
if(eng>.6){dTP[i].rp.setAttribute('filter','url(#dGw)');dTP[i].lp.setAttribute('filter','url(#dGw)');}
else{dTP[i].rp.removeAttribute('filter');dTP[i].lp.removeAttribute('filter');}
}
dER.forEach((r,k)=>{
r.setAttribute('x',(bx0+(k+1)*(dSg[0].dW+gap)-2).toFixed(1));
r.setAttribute('opacity',eng>.5? lerp(0,.8,(eng-.5)*2).toFixed(2) : '0');
});
dFA[0].setAttribute('opacity',eng>.4? lerp(0,.7,(eng-.4)/.6).toFixed(2) : '0');
const fx2=bx0+2*(dSg[0].dW+gap)+dSg[0].dW+4;
dFA[1].setAttribute('x1',fx2.toFixed(1));
dFA[1].setAttribute('x2',(fx2+16).toFixed(1));
dFA[1].setAttribute('opacity',eng>.4? lerp(0,.7,(eng-.4)/.6).toFixed(2) : '0');
if(eng>.7) dEL.textContent='锯齿紧密啮合 → 刚性传递弯矩';
else if(eng<.3) dEL.textContent='锯齿脱开 → 链节自由旋转';
else dEL.textContent='啮合度变化中...';
dEL.setAttribute('fill',eng>.7?'#f0a800':eng<.3?'#ff4444':'#00dce8');
}
/* ===== 更新信息面板 ===== */
function updInfo(){
const e=openV;
const s1=$('s1'),s2=$('s2'),s3=$('s3'),s4=$('s4'),s5=$('s5');
if(e>.75){s1.textContent='刚性锁定';s1.className='iv gd';}
else if(e<.25){s1.textContent='柔性释放';s1.className='iv rd';}
else{s1.textContent='过渡中';s1.className='iv cy';}
s2.textContent=Math.round(e*100)+'%'; s2.className='iv '+(e>.5?'gd':'rd');
s3.textContent=e>.5?'压缩 (推块上顶)':'拉伸 (推块下拉)'; s3.className='iv '+(e>.5?'gd':'rd');
s4.textContent=e>.5?'张紧承压':'松弛随动'; s4.className='iv '+(e>.5?'gd':'rd');
const dof=e<.08?360:Math.round(lerp(360,0,clamp(e*1.6,0,1)));
s5.textContent=dof>=350?'全自由度':dof+'°'; s5.className='iv '+(dof>10?'rd':'gd');
}
/* ===== 全量更新 ===== */
function updAll(){updMain();updDetail();updInfo();}
/* ===== 动画主循环 ===== */
function tick(ts){
if(prevTS===null) prevTS=ts;
const dt=(ts-prevTS)/1000;
prevTS=ts;
if(autoOn){
aTime+=dt*spd/100;
openV=Math.cos(aTime*Math.PI*2)*.5+.5;
$('openSlider').value=Math.round(openV*1000);
updAll();
}
requestAnimationFrame(tick);
}
/* ===== 事件绑定 ===== */
function bind(){
$('openSlider').addEventListener('input',function(){
openV=parseInt(this.value)/1000;
updAll();
});
$('bAuto').addEventListener('click',function(){
autoOn=!autoOn;
this.classList.toggle('on',autoOn);
this.innerHTML=autoOn?'<i class="fa fa-pause"></i> 暂停演示':'<i class="fa fa-play"></i> 自动演示';
if(autoOn){
/* 从当前openV反算aTime,保证平滑衔接 */
var cv=clamp(openV*2-1,-1,1);
aTime=Math.acos(cv)/(Math.PI*2);
}
});
$('bReset').addEventListener('click',function(){
openV=1;autoOn=false;prevTS=null;
$('openSlider').value=1000;
$('bAuto').classList.remove('on');
$('bAuto').innerHTML='<i class="fa fa-play"></i> 自动演示';
updAll();
});
$('speedSlider').addEventListener('input',function(){spd=parseInt(this.value);});
}
/* ===== 启动 ===== */
buildMain();
buildDetail();
updAll();
bind();
requestAnimationFrame(tick);
})();
</script>
</body>
</html>
修复要点说明:
动画循环修复:将
prevTS初始值设为null,第一帧时才初始化,避免首帧dt巨大导致跳变;requestAnimationFrame(tick)放在函数末尾确保持续驱动。滑块精度提升:将
min/max改为0/1000(千分位精度),使拖动时链节过渡更丝滑,不会出现卡顿感。自动播放衔接:点击自动演示时,从当前
openV反推aTime(Math.acos(openV*2-1)),保证动画从当前状态平滑开始,不突兀跳变。视觉反馈增强:
- 刚性态:链节边框变暗绿、锯齿三角变金色、啮合点发金光
- 柔性态:链节变暗蓝灰、锯齿暗淡、红色拉力箭头出现
- 过渡态:青色标签提示"过渡中"
交互验证:拖动滑块即可立即看到链节从水平刚性杆逐节弯折下垂为柔性链;点击自动演示按钮后,开合度在 0↔1 之间平滑循环往复。
等待动画代码生成...
