独立渲染引擎就绪引擎就绪
<!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=Noto+Sans+SC:wght@300;400;600&display=swap" rel="stylesheet">
<style>
:root {
--bg: #060b18;
--fg: #d8e2ec;
--accent: #00d4ff;
--fluid-liq: #00b4d8;
--fluid-sol: #ff8c00;
--bead: #ff2d55;
--coil: #7b68ee;
--muted: #5a6a80;
--card: rgba(255,255,255,0.03);
--border: rgba(255,255,255,0.06);
}
*{margin:0;padding:0;box-sizing:border-box;}
body{
background:var(--bg);
color:var(--fg);
font-family:'Noto Sans SC',sans-serif;
min-height:100vh;
display:flex;flex-direction:column;
align-items:center;justify-content:center;
overflow:hidden;
background-image:
radial-gradient(ellipse 80% 60% at 30% 40%, rgba(0,212,255,0.04) 0%, transparent 70%),
radial-gradient(ellipse 60% 50% at 75% 65%, rgba(255,140,0,0.03) 0%, transparent 70%);
}
.wrapper{width:100%;max-width:1440px;padding:0.5rem 1rem;display:flex;flex-direction:column;align-items:center;}
.top-bar{text-align:center;margin-bottom:0.3rem;}
.top-bar h1{
font-family:'Rajdhani',sans-serif;font-weight:700;font-size:1.6rem;
letter-spacing:0.12em;color:var(--accent);
text-shadow:0 0 20px rgba(0,212,255,0.3);
}
.top-bar .sub{font-size:0.78rem;color:var(--muted);letter-spacing:0.05em;}
.svg-container{width:100%;display:flex;justify-content:center;}
.svg-container svg{width:100%;max-width:1440px;height:auto;}
.controls{
display:flex;align-items:center;gap:1rem;margin-top:0.5rem;
padding:0.6rem 1.5rem;background:var(--card);
border:1px solid var(--border);border-radius:10px;flex-wrap:wrap;justify-content:center;
}
.controls label{font-size:0.8rem;color:var(--muted);white-space:nowrap;}
.controls input[type=range]{
width:180px;accent-color:var(--accent);cursor:pointer;
}
.ctrl-btn{
background:transparent;border:1px solid var(--border);color:var(--accent);
padding:0.3rem 0.9rem;border-radius:6px;cursor:pointer;
font-family:'Rajdhani',sans-serif;font-size:0.85rem;font-weight:600;
letter-spacing:0.06em;transition:all 0.2s;
}
.ctrl-btn:hover{background:rgba(0,212,255,0.1);border-color:var(--accent);}
.ctrl-btn.active{background:rgba(0,212,255,0.15);border-color:var(--accent);}
.state-label{
font-family:'Rajdhani',sans-serif;font-weight:600;font-size:0.95rem;
min-width:110px;text-align:center;transition:color 0.3s;
}
@media(max-width:640px){
.top-bar h1{font-size:1.1rem;}
.controls{gap:0.5rem;padding:0.4rem 0.8rem;}
.controls input[type=range]{width:120px;}
}
</style>
</head>
<body>
<div class="wrapper">
<header class="top-bar">
<h1>MAGNETORHEOLOGICAL UMBRELLA RIB</h1>
<p class="sub">磁流变液智能伞骨 — TRIZ 最终理想解 (IFR) 原理演示</p>
</header>
<div class="svg-container">
<svg id="scene" viewBox="0 0 1400 860" xmlns="http://www.w3.org/2000/svg">
<defs>
<!-- 辉光滤镜 -->
<filter id="glow-cyan" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceGraphic" stdDeviation="5" result="b"/>
<feFlood flood-color="#00d4ff" flood-opacity="0.55"/><feComposite in2="b" operator="in"/>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
<filter id="glow-amber" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceGraphic" stdDeviation="5" result="b"/>
<feFlood flood-color="#ff8c00" flood-opacity="0.55"/><feComposite in2="b" operator="in"/>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
<filter id="glow-red" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceGraphic" stdDeviation="3.5" result="b"/>
<feFlood flood-color="#ff2d55" flood-opacity="0.5"/><feComposite in2="b" operator="in"/>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
<filter id="glow-coil" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceGraphic" stdDeviation="6" result="b"/>
<feFlood flood-color="#7b68ee" flood-opacity="0.6"/><feComposite in2="b" operator="in"/>
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
<filter id="soft-shadow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="b"/>
<feOffset dx="0" dy="2"/><feFlood flood-color="#000" flood-opacity="0.4"/>
<feComposite in2="b" operator="in"/><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
<!-- 网格图案 -->
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="rgba(255,255,255,0.025)" stroke-width="0.5"/>
</pattern>
<!-- 磁流变液渐变 -->
<linearGradient id="fluid-grad" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#00b4d8" stop-opacity="0.65"/>
<stop offset="100%" stop-color="#00b4d8" stop-opacity="0.65"/>
</linearGradient>
</defs>
<!-- 背景 -->
<rect width="1400" height="860" fill="#060b18"/>
<rect width="1400" height="860" fill="url(#grid)"/>
<!-- 动态图层 (JS 填充) -->
<g id="field-lines-g"></g>
<g id="coil-g"></g>
<g id="rib-g"></g>
<g id="beads-g"></g>
<g id="umbrella-g" transform="translate(70,100)"></g>
<g id="annot-g"></g>
<g id="state-g"></g>
</svg>
</div>
<div class="controls">
<label>电磁场强度</label>
<input type="range" id="fieldSlider" min="0" max="100" value="0">
<span id="fieldVal" style="font-family:Rajdhani;font-weight:600;min-width:40px;">0%</span>
<button id="autoBtn" class="ctrl-btn active">AUTO</button>
<span id="stateLabel" class="state-label" style="color:#00b4d8;">柔性卷曲</span>
</div>
</div>
<script>
(function(){
'use strict';
/* ============ 配置 ============ */
const RIB_PTS = 60;
const RIB_SX = 310, RIB_SY = 400;
const RIB_EX = 1300, RIB_EY = 310;
const RIB_THICK = 38;
const N_BEADS = 14;
const BEAD_R = 5.5;
const LOOP_SEC = 15; // 整个循环秒数
/* ============ 状态 ============ */
let fs = 0; // 场强 0-1
let autoPlay = true;
let t0 = null;
let manualFs = 0;
/* ============ DOM ============ */
const svgNS = 'http://www.w3.org/2000/svg';
const slider = document.getElementById('fieldSlider');
const fVal = document.getElementById('fieldVal');
const autoBtn = document.getElementById('autoBtn');
const stLabel = document.getElementById('stateLabel');
const gField = document.getElementById('field-lines-g');
const gCoil = document.getElementById('coil-g');
const gRib = document.getElementById('rib-g');
const gBeads = document.getElementById('beads-g');
const gUmb = document.getElementById('umbrella-g');
const gAnnot = document.getElementById('annot-g');
const gState = document.getElementById('state-g');
/* ============ 工具 ============ */
function lerp(a,b,t){return a+(b-a)*t;}
function easeIO(t){return t<.5?4*t*t*t:1-Math.pow(-2*t+2,3)/2;}
function clamp01(v){return Math.max(0,Math.min(1,v));}
function lerpColor(c1,c2,t){
// c1,c2 = [r,g,b]
return `rgb(${Math.round(lerp(c1[0],c2[0],t))},${Math.round(lerp(c1[1],c2[1],t))},${Math.round(lerp(c1[2],c2[2],t))})`;
}
const COL_LIQ = [0,180,216];
const COL_SOL = [255,140,0];
function svgEl(tag,attrs){
const el = document.createElementNS(svgNS,tag);
for(const k in attrs) el.setAttribute(k,attrs[k]);
return el;
}
/* ============ 几何:伞骨中心线 ============ */
function centerline(fieldStr){
const pts=[];
for(let i=0;i<=RIB_PTS;i++){
const t=i/RIB_PTS;
// 刚化:微上扬直线
const rx = lerp(RIB_SX, RIB_EX, t);
const ry = lerp(RIB_SY, RIB_EY, t);
// 柔性:下垂+波动
const comp = 0.58;
const fx = lerp(RIB_SX, RIB_EX, t)*comp + RIB_SX*(1-comp);
const droop = t*t*200;
const wave = Math.sin(t*Math.PI*2.8)*35*t;
const fy = RIB_SY + droop + wave;
const ff = 1-fieldStr;
pts.push({ x: lerp(rx,fx,ff), y: lerp(ry,fy,ff) });
}
return pts;
}
/* ============ 几何:管道路径 ============ */
function tubePath(cl, thick){
const ht=thick/2, top=[], bot=[];
for(let i=0;i<cl.length;i++){
let dx,dy;
if(i===0){dx=cl[1].x-cl[0].x;dy=cl[1].y-cl[0].y;}
else if(i===cl.length-1){dx=cl[i].x-cl[i-1].x;dy=cl[i].y-cl[i-1].y;}
else{dx=cl[i+1].x-cl[i-1].x;dy=cl[i+1].y-cl[i-1].y;}
const len=Math.sqrt(dx*dx+dy*dy)||1;
const nx=-dy/len, ny=dx/len;
top.push({x:cl[i].x+nx*ht, y:cl[i].y+ny*ht});
bot.push({x:cl[i].x-nx*ht, y:cl[i].y-ny*ht});
}
let d=`M${top[0].x.toFixed(1)},${top[0].y.toFixed(1)}`;
for(let i=1;i<top.length;i++) d+=` L${top[i].x.toFixed(1)},${top[i].y.toFixed(1)}`;
d+=` A${ht},${ht} 0 0 1 ${bot[bot.length-1].x.toFixed(1)},${bot[bot.length-1].y.toFixed(1)}`;
for(let i=bot.length-2;i>=0;i--) d+=` L${bot[i].x.toFixed(1)},${bot[i].y.toFixed(1)}`;
d+=` A${ht},${ht} 0 0 1 ${top[0].x.toFixed(1)},${top[0].y.toFixed(1)} Z`;
return d;
}
/* ============ 磁珠位置 ============ */
function beadPos(cl, fieldStr){
const beads=[];
for(let i=0;i<N_BEADS;i++){
const t=(i+0.5)/N_BEADS;
const idx=Math.min(Math.floor(t*(cl.length-1)),cl.length-2);
const frac=t*(cl.length-1)-idx;
const cx=lerp(cl[idx].x,cl[idx+1].x,frac);
const cy=lerp(cl[idx].y,cl[idx+1].y,frac);
const seed=i*137.508;
const scatter=14*(1-fieldStr);
const ox=Math.cos(seed)*scatter;
const oy=Math.sin(seed)*scatter;
beads.push({x:cx+ox, y:cy+oy});
}
return beads;
}
/* ============ 创建静态元素 ============ */
// 管道填充 (MR流体)
const ribFluid = svgEl('path',{id:'ribFluid',fill:'url(#fluid-grad)',stroke:'none'});
gRib.appendChild(ribFluid);
// 管道壁
const ribWall = svgEl('path',{id:'ribWall',fill:'none',stroke:'rgba(180,200,220,0.35)',
'stroke-width':'2.5','stroke-linejoin':'round'});
gRib.appendChild(ribWall);
// 管道高光
const ribHighlight = svgEl('path',{id:'ribHL',fill:'none',stroke:'rgba(255,255,255,0.08)',
'stroke-width':'8','stroke-linecap':'round'});
gRib.appendChild(ribHighlight);
// 磁珠
const beadEls=[];
for(let i=0;i<N_BEADS;i++){
const g=svgEl('g',{});
// 磁珠辉光底层
const glow=svgEl('circle',{r:BEAD_R+3,fill:'none',stroke:'#ff2d55','stroke-width':'1',opacity:'0'});
g.appendChild(glow);
// 磁珠本体
const c=svgEl('circle',{r:BEAD_R,fill:'#ff2d55',stroke:'#cc1144','stroke-width':'0.8'});
g.appendChild(c);
// 高光点
const hl=svgEl('circle',{r:1.8,fill:'rgba(255,255,255,0.7)'});
g.appendChild(hl);
gBeads.appendChild(g);
beadEls.push({g,glow,c,hl});
}
// 电磁线圈
function buildCoil(){
gCoil.innerHTML='';
const cx=270, cy=RIB_SY, w=55, h=80, loops=8;
// 线圈外壳
const housing=svgEl('rect',{x:cx-w/2,y:cy-h/2,width:w,height:h,rx:6,
fill:'rgba(40,30,80,0.6)',stroke:'#7b68ee','stroke-width':'1.5'});
gCoil.appendChild(housing);
// 线圈绕组
for(let i=0;i<loops;i++){
const yy=cy-h/2+8+i*(h-16)/(loops-1);
const line=svgEl('line',{x1:cx-w/2+4,y1:yy,x2:cx+w/2-4,y2:yy,
stroke:'#9b88ff','stroke-width':'1.2',opacity:'0.6'});
gCoil.appendChild(line);
}
// 线圈辉光
const coilGlow=svgEl('rect',{id:'coilGlow',x:cx-w/2-4,y:cy-h/2-4,width:w+8,height:h+8,rx:10,
fill:'none',stroke:'#7b68ee','stroke-width':'2',opacity:'0',filter:'url(#glow-coil)'});
gCoil.appendChild(coilGlow);
// 连接线 (线圈到伞骨)
const conn=svgEl('line',{x1:cx+w/2,y1:cy,x2:RIB_SX,y2:RIB_SY,
stroke:'#7b68ee','stroke-width':'1.5','stroke-dasharray':'4,3',opacity:'0.4'});
gCoil.appendChild(conn);
}
buildCoil();
// 磁场线
const fieldLineEls=[];
const N_FLINES=7;
for(let i=0;i<N_FLINES;i++){
const p=svgEl('path',{fill:'none',stroke:'#00d4ff','stroke-width':'1.2',
'stroke-dasharray':'8,6',opacity:'0',filter:'url(#glow-cyan)'});
gField.appendChild(p);
fieldLineEls.push(p);
}
// 伞图示
function buildUmbrella(){
gUmb.innerHTML='';
const sc=0.55;
// 伞面
const canopy=svgEl('path',{id:'umbCanopy',d:'',fill:'rgba(0,180,216,0.15)',
stroke:'#00b4d8','stroke-width':'1.5'});
gUmb.appendChild(canopy);
// 伞骨线
const ribLines=[];
for(let i=0;i<5;i++){
const l=svgEl('line',{stroke:'rgba(180,200,220,0.4)','stroke-width':'1'});
gUmb.appendChild(l);
ribLines.push(l);
}
// 伞柄
const handle=svgEl('line',{id:'umbHandle',x1:0,y1:0,x2:0,y2:120,
stroke:'rgba(180,200,220,0.5)','stroke-width':'2','stroke-linecap':'round'});
gUmb.appendChild(handle);
// 标签
const lbl=svgEl('text',{x:0,y:180,fill:'#5a6a80','font-size':'11',
'text-anchor':'middle','font-family':'Noto Sans SC'});
lbl.textContent='整体伞态';
gUmb.appendChild(lbl);
return {canopy,ribLines,handle};
}
const umbEls=buildUmbrella();
// 标注
function buildAnnotations(){
gAnnot.innerHTML='';
const annots=[
{text:'硅胶软管', tx:800, ty:280, px:800, py:360},
{text:'磁流变液', tx:750, ty:450, px:750, py:400},
{text:'钕铁硼磁珠', tx:950, ty:500, px:950, py:410},
{text:'电磁线圈', tx:180, ty:330, px:260, py:390},
{text:'磁场线', tx:600, ty:230, px:600, py:340},
];
annots.forEach(a=>{
const line=svgEl('line',{x1:a.tx,y1:a.ty+6,x2:a.px,y2:a.py,
stroke:'rgba(255,255,255,0.12)','stroke-width':'0.8','stroke-dasharray':'3,2'});
gAnnot.appendChild(line);
const dot=svgEl('circle',{cx:a.px,cy:a.py,r:2.5,fill:'rgba(255,255,255,0.2)'});
gAnnot.appendChild(dot);
const t=svgEl('text',{x:a.tx,y:a.ty,fill:'#7a8a9e','font-size':'12',
'text-anchor':'middle','font-family':'Noto Sans SC','font-weight':'400'});
t.textContent=a.text;
gAnnot.appendChild(t);
});
}
buildAnnotations();
// 状态面板
function buildStatePanel(){
gState.innerHTML='';
const bx=950, by=680;
const items=[
{id:'stField', label:'电磁场', x:bx, y:by},
{id:'stFluid', label:'磁流变液', x:bx, y:by+36},
{id:'stBead', label:'磁珠链', x:bx, y:by+72},
{id:'stRib', label:'伞骨', x:bx, y:by+108},
];
items.forEach(it=>{
const lbl=svgEl('text',{x:it.x,y:it.y,fill:'#5a6a80','font-size':'13',
'font-family':'Noto Sans SC','font-weight':'400'});
lbl.textContent=it.label;
gState.appendChild(lbl);
const val=svgEl('text',{id:it.id,x:it.x+90,y:it.y,fill:'#00b4d8','font-size':'13',
'font-family':'Rajdhani','font-weight':'600'});
val.textContent='—';
gState.appendChild(val);
});
}
buildStatePanel();
/* ============ 更新函数 ============ */
function updateScene(fieldStr, elapsed){
const cl = centerline(fieldStr);
const tp = tubePath(cl, RIB_THICK);
// --- 流体填充 ---
ribFluid.setAttribute('d', tp);
// 更新渐变色
const fluidCol = lerpColor(COL_LIQ, COL_SOL, fieldStr);
const fluidAlpha = lerp(0.55, 0.82, fieldStr);
const grad = document.getElementById('fluid-grad');
const stops = grad.querySelectorAll('stop');
stops.forEach(s=>{ s.setAttribute('stop-color', fluidCol); s.setAttribute('stop-opacity', fluidAlpha); });
// --- 管道壁 ---
ribWall.setAttribute('d', tp);
// 高光线 (沿中心线上方偏移)
const hlThick = RIB_THICK*0.35;
const hlCl = cl.map(p=>({x:p.x, y:p.y - RIB_THICK*0.22}));
let hlD=`M${hlCl[0].x.toFixed(1)},${hlCl[0].y.toFixed(1)}`;
// 取每隔几个点做平滑
for(let i=3;i<hlCl.length;i+=3){
hlD+=` L${hlCl[i].x.toFixed(1)},${hlCl[i].y.toFixed(1)}`;
}
ribHighlight.setAttribute('d', hlD);
// --- 磁珠 ---
const beads = beadPos(cl, fieldStr);
beads.forEach((b,i)=>{
const el=beadEls[i];
el.c.setAttribute('cx', b.x); el.c.setAttribute('cy', b.y);
el.glow.setAttribute('cx', b.x); el.glow.setAttribute('cy', b.y);
el.hl.setAttribute('cx', b.x-1.5); el.hl.setAttribute('cy', b.y-1.5);
// 磁珠辉光随场强
const glowOp = fieldStr > 0.6 ? (fieldStr-0.6)/0.4 * 0.5 : 0;
el.glow.setAttribute('opacity', glowOp);
// 磁珠颜色随场强微微偏亮
const br = Math.round(lerp(255,255,fieldStr));
const bg = Math.round(lerp(45,80,fieldStr));
const bb = Math.round(lerp(85,60,fieldStr));
el.c.setAttribute('fill', `rgb(${br},${bg},${bb})`);
});
// --- 磁场线 ---
fieldLineEls.forEach((fl,fi)=>{
const offset = (fi - (N_FLINES-1)/2) * 18;
let d='';
const step = Math.max(1, Math.floor(cl.length/30));
for(let i=0;i<cl.length;i+=step){
const p=cl[i];
// 计算法线偏移
let dx,dy;
if(i===0){dx=cl[1].x-cl[0].x;dy=cl[1].y-cl[0].y;}
else if(i>=cl.length-1){dx=cl[i].x-cl[i-1].x;dy=cl[i].y-cl[i-1].y;}
else{dx=cl[i+1].x-cl[i-1].x;dy=cl[i+1].y-cl[i-1].y;}
const len=Math.sqrt(dx*dx+dy*dy)||1;
const nx=-dy/len, ny=dx/len;
const px=p.x+nx*offset, py=p.y+ny*offset;
d += (i===0?'M':' L') + px.toFixed(1)+','+py.toFixed(1);
}
fl.setAttribute('d', d);
const fOp = fieldStr * 0.55 * (0.7 + 0.3*Math.sin(elapsed*3 + fi*0.8));
fl.setAttribute('opacity', clamp01(fOp));
// 流动动画
const dashOff = -elapsed * 40;
fl.setAttribute('stroke-dashoffset', dashOff.toFixed(1));
});
// --- 电磁线圈辉光 ---
const coilGlow = document.getElementById('coilGlow');
if(coilGlow){
const cgOp = fieldStr * (0.5 + 0.3*Math.sin(elapsed*4));
coilGlow.setAttribute('opacity', clamp01(cgOp).toFixed(2));
}
// --- 伞图示 ---
updateUmbrella(fieldStr);
// --- 状态面板 ---
updateStatePanel(fieldStr);
// --- UI ---
fVal.textContent = Math.round(fieldStr*100)+'%';
if(fieldStr > 0.7){
stLabel.textContent = '刚化支撑';
stLabel.style.color = '#ff8c00';
} else if(fieldStr < 0.3){
stLabel.textContent = '柔性卷曲';
stLabel.style.color = '#00b4d8';
} else {
stLabel.textContent = '相态切换中';
stLabel.style.color = '#7b68ee';
}
}
function updateUmbrella(fieldStr){
const cx=110, cy=120;
const openW=100, closedW=12;
const openH=70, closedH=50;
const w = lerp(closedW, openW, fieldStr);
const h = lerp(closedH, openH, fieldStr);
// 伞面弧线
const d=`M${cx-w},${cy} Q${cx},${cy-h*2} ${cx+w},${cy}`;
umbEls.canopy.setAttribute('d', d);
// 伞面填充色随场强
const umbFill = lerpColor([0,180,216],[255,140,0], fieldStr);
umbEls.canopy.setAttribute('fill', umbFill.replace('rgb','rgba').replace(')',',0.12)'));
umbEls.canopy.setAttribute('stroke', umbFill);
// 伞骨线
umbEls.ribLines.forEach((l,i)=>{
const angle = lerp(Math.PI/2, (i/(umbEls.ribLines.length-1))*Math.PI*0.8 + Math.PI*0.1, fieldStr);
const ribLen = lerp(15, w*0.9, fieldStr);
l.setAttribute('x1', cx);
l.setAttribute('y1', cy);
l.setAttribute('x2', cx + Math.cos(angle-Math.PI)*ribLen);
l.setAttribute('y2', cy - Math.sin(angle)*ribLen*0.6);
l.setAttribute('stroke', umbFill);
l.setAttribute('opacity', 0.4+fieldStr*0.3);
});
// 伞柄
const handleDrop = lerp(60, 100, fieldStr);
umbEls.handle.setAttribute('x1', cx);
umbEls.handle.setAttribute('y1', cy);
umbEls.handle.setAttribute('x2', cx);
umbEls.handle.setAttribute('y2', cy + handleDrop);
}
function updateStatePanel(fieldStr){
const stField = document.getElementById('stField');
const stFluid = document.getElementById('stFluid');
const stBead = document.getElementById('stBead');
const stRib = document.getElementById('stRib');
if(stField){
stField.textContent = fieldStr > 0.5 ? 'ON 激活' : 'OFF 关闭';
stField.setAttribute('fill', fieldStr > 0.5 ? '#00d4ff' : '#5a6a80');
}
if(stFluid){
if(fieldStr > 0.7) { stFluid.textContent = '固态 · 刚化'; stFluid.setAttribute('fill','#ff8c00'); }
else if(fieldStr < 0.3) { stFluid.textContent = '液态 · 流动'; stFluid.setAttribute('fill','#00b4d8'); }
else { stFluid.textContent = '相变中...'; stFluid.setAttribute('fill','#7b68ee'); }
}
if(stBead){
if(fieldStr > 0.7) { stBead.textContent = '耦合锁定'; stBead.setAttribute('fill','#ff2d55'); }
else if(fieldStr < 0.3) { stBead.textContent = '解耦散布'; stBead.setAttribute('fill','#5a6a80'); }
else { stBead.textContent = '链化中...'; stBead.setAttribute('fill','#9b88ff'); }
}
if(stRib){
if(fieldStr > 0.7) { stRib.textContent = '刚性支撑'; stRib.setAttribute('fill','#ff8c00'); }
else if(fieldStr < 0.3) { stRib.textContent = '柔性卷曲'; stRib.setAttribute('fill','#00b4d8'); }
else { stRib.textContent = '刚化中...'; stRib.setAttribute('fill','#7b68ee'); }
}
}
/* ============ 粒子效果(磁流变液内部微粒) ============ */
const particles=[];
const N_PARTICLES=40;
for(let i=0;i<N_PARTICLES;i++){
const c=svgEl('circle',{r:1.2+Math.random()*1.2, fill:'rgba(255,255,255,0.15)',opacity:'0'});
gRib.appendChild(c);
particles.push({
el:c,
t: Math.random(), // 沿伞骨的位置 0-1
offset: (Math.random()-0.5)*0.7, // 横向偏移 -0.5~0.5
speed: 0.02+Math.random()*0.04,
phase: Math.random()*Math.PI*2
});
}
function updateParticles(cl, fieldStr, elapsed){
const ht=RIB_THICK/2-4;
particles.forEach(p=>{
// 液态时粒子流动,固态时粒子冻结
if(fieldStr < 0.7){
p.t += p.speed * (1-fieldStr) * 0.016; // 大约60fps
if(p.t > 1) p.t -= 1;
}
const idx = Math.min(Math.floor(p.t*(cl.length-1)), cl.length-2);
const frac = p.t*(cl.length-1)-idx;
const cx = lerp(cl[idx].x, cl[idx+1].x, frac);
const cy = lerp(cl[idx].y, cl[idx+1].y, frac);
// 法线方向
let dx,dy;
if(idx===0){dx=cl[1].x-cl[0].x;dy=cl[1].y-cl[0].y;}
else{dx=cl[idx+1].x-cl[idx-1].x;dy=cl[idx+1].y-cl[idx-1].y;}
const len=Math.sqrt(dx*dx+dy*dy)||1;
const nx=-dy/len, ny=dx/len;
const lateralOff = p.offset * ht * (1-fieldStr*0.8);
const wobble = Math.sin(elapsed*2+p.phase)*3*(1-fieldStr);
const px = cx + nx*(lateralOff+wobble);
const py = cy + ny*(lateralOff+wobble);
p.el.setAttribute('cx', px.toFixed(1));
p.el.setAttribute('cy', py.toFixed(1));
// 粒子可见度:液态时可见,固态时微弱
const vis = lerp(0.25, 0.05, fieldStr);
p.el.setAttribute('opacity', vis.toFixed(2));
// 固态时粒子颜色偏暖
const pCol = lerpColor([200,230,255],[255,200,120],fieldStr);
p.el.setAttribute('fill', pCol);
});
}
/* ============ 磁链连线效果 ============ */
const chainLine = svgEl('path',{id:'chainLine',fill:'none',stroke:'#ff2d55',
'stroke-width':'1.5','stroke-dasharray':'4,3',opacity:'0'});
gBeads.insertBefore(chainLine, gBeads.firstChild);
function updateChainLine(beads, fieldStr){
if(fieldStr < 0.3){
chainLine.setAttribute('opacity','0');
return;
}
let d='';
beads.forEach((b,i)=>{
d += (i===0?'M':'L') + b.x.toFixed(1)+','+b.y.toFixed(1);
});
chainLine.setAttribute('d', d);
const op = lerp(0, 0.6, (fieldStr-0.3)/0.7);
chainLine.setAttribute('opacity', clamp01(op).toFixed(2));
}
/* ============ 磁珠间引力线效果 ============ */
const attractLines=[];
for(let i=0;i<N_BEADS-1;i++){
const l=svgEl('line',{stroke:'#ff2d55','stroke-width':'0.8',opacity:'0',
'stroke-dasharray':'2,4'});
gBeads.insertBefore(l, gBeads.firstChild);
attractLines.push(l);
}
function updateAttractLines(beads, fieldStr){
attractLines.forEach((l,i)=>{
if(i >= beads.length-1) return;
l.setAttribute('x1', beads[i].x);
l.setAttribute('y1', beads[i].y);
l.setAttribute('x2', beads[i+1].x);
l.setAttribute('y2', beads[i+1].y);
const op = fieldStr > 0.5 ? lerp(0, 0.4, (fieldStr-0.5)/0.5) : 0;
l.setAttribute('opacity', op.toFixed(2));
});
}
/* ============ 动画主循环 ============ */
function animate(ts){
if(t0===null) t0=ts;
const elapsed=(ts-t0)/1000;
if(autoPlay){
const t=elapsed%LOOP_SEC;
if(t<2) fs=0;
else if(t<5) fs=easeIO((t-2)/3);
else if(t<8) fs=1;
else if(t<11) fs=1-easeIO((t-8)/3);
else fs=0;
slider.value=Math.round(fs*100);
} else {
fs=manualFs;
}
const cl=centerline(fs);
const beads=beadPos(cl, fs);
updateScene(fs, elapsed);
updateParticles(cl, fs, elapsed);
updateChainLine(beads, fs);
updateAttractLines(beads, fs);
requestAnimationFrame(animate);
}
/* ============ 事件 ============ */
slider.addEventListener('input', e=>{
autoPlay=false;
manualFs=e.target.value/100;
autoBtn.classList.remove('active');
autoBtn.textContent='MANUAL';
});
autoBtn.addEventListener('click', ()=>{
autoPlay=!autoPlay;
if(autoPlay){
t0=null;
autoBtn.classList.add('active');
autoBtn.textContent='AUTO';
} else {
manualFs=fs;
autoBtn.classList.remove('active');
autoBtn.textContent='MANUAL';
}
});
/* ============ 启动 ============ */
requestAnimationFrame(animate);
})();
</script>
</body>
</html>
实现说明
本动画聚焦展示磁流变液智能伞骨的 TRIZ 最终理想解原理,核心视觉逻辑如下:
双态切换动画:页面加载后自动循环播放「电磁场关闭 → 激活 → 刚化撑伞 → 关闭 → 柔性卷曲」的完整时序,场强由
easeInOutCubic缓动驱动,所有视觉元素(管道形态、流体色彩、磁珠排列、场线可见度)均随场强 0→1 连续插值。伞骨管道形变:刚化态为微上扬直线,柔性态为下垂+正弦波动的鞭状曲线,60 个采样点保证路径平滑,管壁通过法线偏移生成封闭轮廓。
磁流变液相变:填充色从冷调青蓝(液态)平滑过渡至暖调琥珀橙(固态),透明度同步变化;40 个微粒在液态时沿管内流动、固态时冻结,直观呈现"液态 ↔ 固态"的宏观可控切换。
钕铁硼磁珠链锁:14 颗磁珠在场强上升时从散布状态逐步归位至中心线一条直链,链连线与珠间引力线渐显,辅以红色辉光强调"链锁刚化"这一破除矛盾的关键动作。
电磁场可视化:7 条磁场线沿管道法向分布,通过
stroke-dashoffset持续流动并脉动透明度,线圈外壳同步辉光,清晰展示"电磁场驱动相变"的资源利用逻辑。交互控制:底部滑块可手动接管场强,AUTO/MANUAL 按钮切换自动/手动模式,状态面板实时标注电磁场、磁流变液、磁珠链、伞骨的四维状态。
积分规则:第一轮对话扣减8分,后续每轮扣6分
等待动画代码生成...
