独立渲染引擎就绪引擎就绪
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>热膨胀差动自锁机构原理演示</title>
<style>
:root {
--bg-color: #07090F;
--grid-color: rgba(30, 41, 59, 0.5);
--text-main: #E2E8F0;
--text-dim: #64748B;
--color-cold: #00F0FF;
--color-hot: #FF2A55;
--color-seat: #1E293B;
--color-reflector: #334155;
--font-tech: 'Courier New', Courier, monospace;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-color);
color: var(--text-main);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100vw;
}
#app-container {
position: relative;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
svg {
width: 100%;
height: 100%;
max-width: 1200px;
max-height: 800px;
}
/* 绝对定位的极简文字说明,置于边缘 */
.overlay-text {
position: absolute;
pointer-events: none;
z-index: 10;
}
.header-info {
top: 24px;
left: 32px;
}
.header-title {
font-size: 14px;
font-weight: 600;
letter-spacing: 2px;
color: #fff;
margin-bottom: 4px;
text-transform: uppercase;
}
.header-desc {
font-size: 11px;
color: var(--text-dim);
max-width: 300px;
line-height: 1.4;
}
.status-panel {
bottom: 32px;
right: 32px;
text-align: right;
font-family: var(--font-tech);
}
.temp-display {
font-size: 32px;
font-weight: bold;
color: var(--color-cold);
text-shadow: 0 0 10px rgba(0, 240, 255, 0.5);
transition: color 0.3s, text-shadow 0.3s;
}
.state-display {
font-size: 12px;
color: var(--text-main);
margin-top: 4px;
letter-spacing: 1px;
}
.legend-panel {
bottom: 32px;
left: 32px;
font-size: 11px;
color: var(--text-dim);
display: flex;
flex-direction: column;
gap: 6px;
}
.legend-item {
display: flex;
align-items: center;
gap: 8px;
}
.legend-color {
width: 12px;
height: 4px;
border-radius: 2px;
}
.triz-badge {
position: absolute;
top: 24px;
right: 32px;
font-size: 10px;
border: 1px solid rgba(255,255,255,0.2);
padding: 4px 8px;
border-radius: 4px;
color: #A0AABF;
letter-spacing: 1px;
background: rgba(0,0,0,0.5);
}
</style>
</head>
<body>
<div id="app-container">
<!-- 边缘文字信息 -->
<div class="overlay-text header-info">
<div class="header-title">热膨胀差动自锁机构</div>
<div class="header-desc">利用高/低膨胀合金的热变形差,实现无活动部件的温度自驱动锁紧与脱开。</div>
</div>
<div class="overlay-text triz-badge">
TRIZ: 最终理想解 (IFR) & 资源利用
</div>
<div class="overlay-text legend-panel">
<div class="legend-item">
<div class="legend-color" style="background: #334155;"></div>
<span>低膨胀锥形环座 (固定, CTE≈6×10⁻⁶/℃)</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background: linear-gradient(90deg, #00F0FF, #FF2A55);"></div>
<span>高膨胀分瓣锁环 (CTE≈17×10⁻⁶/℃)</span>
</div>
</div>
<div class="overlay-text status-panel">
<div class="temp-display" id="temp-val">150°C</div>
<div class="state-display" id="state-val">系统就绪 / 间隙态</div>
</div>
<!-- 主体SVG动画区域 -->
<svg viewBox="0 0 1000 600" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg">
<defs>
<!-- 网格背景图案 -->
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="var(--grid-color)" stroke-width="0.5"/>
</pattern>
<!-- 金属渐变材质 -->
<linearGradient id="grad-seat" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#0F172A" />
<stop offset="50%" stop-color="#1E293B" />
<stop offset="100%" stop-color="#0F172A" />
</linearGradient>
<linearGradient id="grad-reflector" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#1E293B" />
<stop offset="50%" stop-color="#475569" />
<stop offset="100%" stop-color="#1E293B" />
</linearGradient>
<!-- 锁环的动态颜色渐变 (冷态) -->
<linearGradient id="grad-ring-cold" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#0088AA" />
<stop offset="100%" stop-color="#00F0FF" />
</linearGradient>
<!-- 发光滤镜 -->
<filter id="glow-hot" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="8" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
<filter id="glow-cold" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="4" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
<!-- 箭头标记 -->
<marker id="arrowhead-red" markerWidth="6" markerHeight="6" refX="3" refY="3" orient="auto">
<polygon points="0 0, 6 3, 0 6" fill="#FF2A55" />
</marker>
<marker id="arrowhead-cyan" markerWidth="6" markerHeight="6" refX="3" refY="3" orient="auto">
<polygon points="0 0, 6 3, 0 6" fill="#00F0FF" />
</marker>
</defs>
<!-- 背景网格 -->
<rect width="100%" height="100%" fill="url(#grid)" />
<!-- ================= 主剖视图 (中心) ================= -->
<g transform="translate(500, 300)">
<!-- 中心线 -->
<line x1="0" y1="-250" x2="0" y2="250" stroke="rgba(255,255,255,0.1)" stroke-width="1" stroke-dasharray="10 5" />
<text x="5" y="-240" fill="rgba(255,255,255,0.3)" font-size="10" font-family="monospace">CL</text>
<!-- 固定的低膨胀锥形环座 (左右对称) -->
<!-- 角度被适度夸大以展示原理 (理论4度,视觉呈现约10度) -->
<path d="M -220,-150 L -120,-150 L -90,150 L -220,150 Z" fill="url(#grad-seat)" stroke="#475569" stroke-width="1"/>
<path d="M 220,-150 L 120,-150 L 90,150 L 220,150 Z" fill="url(#grad-seat)" stroke="#475569" stroke-width="1"/>
<!-- 环座标注 -->
<text x="-210" y="-130" fill="#64748B" font-size="10">固定支承</text>
<!-- === 动态组件组 (随提取动作上下移动) === -->
<g id="moving-assembly" transform="translate(0, 0)">
<!-- 中心反射体底部法兰 -->
<rect x="-70" y="-250" width="140" height="400" fill="url(#grad-reflector)" rx="2"/>
<!-- 限位挡台 -->
<rect x="-90" y="80" width="180" height="20" fill="#1E293B" stroke="#334155" stroke-width="1"/>
<!-- 高膨胀分瓣锁环 (左) -->
<!-- 初始状态:靠内,与锥座有间隙 -->
<g id="lock-ring-left" transform="translate(0, 0)">
<path d="M -70,-50 L -100,-50 L -78,110 L -70,110 Z" fill="#0088AA" id="ring-path-left" stroke="rgba(255,255,255,0.2)" stroke-width="1"/>
<!-- 周向收紧弹簧剖面示意 (圆点) -->
<circle cx="-88" cy="30" r="3" fill="#94A3B8" />
</g>
<!-- 高膨胀分瓣锁环 (右) -->
<g id="lock-ring-right" transform="translate(0, 0)">
<path d="M 70,-50 L 100,-50 L 78,110 L 70,110 Z" fill="#0088AA" id="ring-path-right" stroke="rgba(255,255,255,0.2)" stroke-width="1"/>
<circle cx="88" cy="30" r="3" fill="#94A3B8" />
</g>
</g>
<!-- 交互动态指示图元 -->
<g id="indicators">
<!-- 间隙指示 (冷态显示) -->
<g id="gap-indicator" opacity="1">
<line x1="-105" y1="0" x2="-85" y2="0" stroke="#00F0FF" stroke-width="1" marker-end="url(#arrowhead-cyan)" marker-start="url(#arrowhead-cyan)"/>
<text x="-140" y="4" fill="#00F0FF" font-size="10" font-family="monospace">0.10mm 间隙</text>
</g>
<!-- 过盈/压力指示 (热态显示) -->
<g id="force-indicator" opacity="0">
<!-- 楔入法向力指示 -->
<line x1="-120" y1="20" x2="-95" y2="25" stroke="#FF2A55" stroke-width="2" marker-end="url(#arrowhead-red)"/>
<line x1="120" y1="20" x2="95" y2="25" stroke="#FF2A55" stroke-width="2" marker-end="url(#arrowhead-red)"/>
<!-- 摩擦力/锁死指示 -->
<line x1="-110" y1="-10" x2="-110" y2="-40" stroke="#FF2A55" stroke-width="2" marker-end="url(#arrowhead-red)"/>
<line x1="110" y1="-10" x2="110" y2="-40" stroke="#FF2A55" stroke-width="2" marker-end="url(#arrowhead-red)"/>
<text x="-160" y="-20" fill="#FF2A55" font-size="11" font-weight="bold">自锁力 (IFR)</text>
</g>
</g>
</g>
<!-- ================= 俯视图小窗 (右侧) ================= -->
<!-- 用于展示8瓣分瓣结构和周向膨胀 -->
<g transform="translate(820, 150)">
<rect x="-80" y="-80" width="160" height="160" fill="rgba(15, 23, 42, 0.5)" rx="8" stroke="rgba(255,255,255,0.05)"/>
<text x="0" y="-60" fill="#64748B" font-size="10" text-anchor="middle">A-A 俯视切面 (8瓣结构)</text>
<!-- 固定外环座 -->
<circle cx="0" cy="0" r="50" fill="none" stroke="#334155" stroke-width="6"/>
<!-- 动态8瓣锁环组 -->
<g id="top-view-rings">
<!-- 通过JS动态生成8个扇形 -->
</g>
<!-- 中心轴 -->
<circle cx="0" cy="0" r="30" fill="#475569" />
</g>
<!-- ================= 能量/热量流指示 ================= -->
<g id="heat-waves" opacity="0">
<path d="M 300 450 Q 350 400 320 350" fill="none" stroke="#FF2A55" stroke-width="2" opacity="0.5" stroke-dasharray="5 5">
<animate attributeName="stroke-dashoffset" from="100" to="0" dur="2s" repeatCount="indefinite" />
</path>
<path d="M 700 450 Q 650 400 680 350" fill="none" stroke="#FF2A55" stroke-width="2" opacity="0.5" stroke-dasharray="5 5">
<animate attributeName="stroke-dashoffset" from="100" to="0" dur="2s" repeatCount="indefinite" />
</path>
</g>
</svg>
</div>
<script>
// 核心参数设定
const TEMP_MIN = 150;
const TEMP_MAX = 300;
const EXPANSION_MAX = 12; // 视觉上的最大径向膨胀量(像素)
const EXTRACT_Y = -180; // 拔出时的Y轴位移
// DOM 元素引用
const domTemp = document.getElementById('temp-val');
const domState = document.getElementById('state-val');
const assembly = document.getElementById('moving-assembly');
const ringLeft = document.getElementById('lock-ring-left');
const ringRight = document.getElementById('lock-ring-right');
const pathLeft = document.getElementById('ring-path-left');
const pathRight = document.getElementById('ring-path-right');
const gapIndicator = document.getElementById('gap-indicator');
const forceIndicator = document.getElementById('force-indicator');
const heatWaves = document.getElementById('heat-waves');
const topViewRings = document.getElementById('top-view-rings');
// 生成俯视图的8瓣结构
function initTopView() {
const segments = 8;
const angleStep = 360 / segments;
for(let i=0; i<segments; i++) {
const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
const rotation = i * angleStep;
group.setAttribute("transform", `rotate(${rotation})`);
// 绘制单个扇形 (简化的多边形表示)
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
// r_inner=32, r_outer=42, span=40deg
path.setAttribute("d", "M 6.4,-31 L 8.4,-41 L 28,-30 L 21,-22 Z"); // 近似参数
path.setAttribute("fill", "#0088AA");
path.classList.add('top-ring-segment');
path.setAttribute("stroke", "rgba(0,0,0,0.5)");
path.setAttribute("stroke-width", "1");
group.appendChild(path);
topViewRings.appendChild(group);
}
}
initTopView();
// 颜色插值辅助函数 (RGB)
function interpolateColor(color1, color2, factor) {
const result = color1.slice();
for (let i = 0; i < 3; i++) {
result[i] = Math.round(result[i] + factor * (color2[i] - color1[i]));
}
return `rgb(${result[0]}, ${result[1]}, ${result[2]})`;
}
const colorCyan = [0, 240, 255];
const colorRed = [255, 42, 85];
const colorCyanDark = [0, 136, 170];
const colorRedDark = [200, 30, 60];
// 动画时间轴定义
const timeline = [
{ time: 0, temp: 150, y: 0, state: "运行/冷态 (间隙存在)" },
{ time: 2000, temp: 150, y: 0, state: "开始升温..." },
{ time: 5000, temp: 300, y: 0, state: "高温膨胀楔入" },
{ time: 8000, temp: 300, y: 0, state: "热自锁状态 (最终理想解)" },
{ time: 10000, temp: 150, y: 0, state: "停堆降温..." },
{ time: 13000, temp: 150, y: 0, state: "冷态收缩 (间隙恢复)" },
{ time: 14000, temp: 150, y: 0, state: "准备拔出" },
{ time: 16000, temp: 150, y: EXTRACT_Y, state: "无干涉拔出" },
{ time: 18000, temp: 150, y: EXTRACT_Y, state: "拔出完成" },
{ time: 20000, temp: 150, y: 0, state: "重新装入" },
{ time: 21000, temp: 150, y: 0, state: "运行/冷态 (间隙存在)" } // 闭环
];
const TOTAL_DURATION = timeline[timeline.length - 1].time;
let startTime = null;
// 核心动画循环
function animate(timestamp) {
if (!startTime) startTime = timestamp;
let elapsed = (timestamp - startTime) % TOTAL_DURATION;
// 查找当前所处的时间段
let currentFrame = timeline[0];
let nextFrame = timeline[1];
for (let i = 0; i < timeline.length - 1; i++) {
if (elapsed >= timeline[i].time && elapsed < timeline[i+1].time) {
currentFrame = timeline[i];
nextFrame = timeline[i+1];
break;
}
}
// 计算插值因子 (0 到 1)
const progress = (elapsed - currentFrame.time) / (nextFrame.time - currentFrame.time);
// 缓动函数 (Ease-in-out)
const easeProgress = progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2;
// 计算当前属性值
const currentTemp = currentFrame.temp + (nextFrame.temp - currentFrame.temp) * easeProgress;
const currentY = currentFrame.y + (nextFrame.y - currentFrame.y) * easeProgress;
// 归一化温度系数 (0 = 150C, 1 = 300C)
const tempFactor = (currentTemp - TEMP_MIN) / (TEMP_MAX - TEMP_MIN);
// 径向膨胀量
const expansion = tempFactor * EXPANSION_MAX;
// 更新 DOM
// 1. 文字与状态
domTemp.innerText = `${Math.round(currentTemp)}°C`;
if (Math.round(currentTemp) > 220) {
domTemp.style.color = 'var(--color-hot)';
domTemp.style.textShadow = '0 0 10px rgba(255, 42, 85, 0.6)';
} else {
domTemp.style.color = 'var(--color-cold)';
domTemp.style.textShadow = '0 0 10px rgba(0, 240, 255, 0.5)';
}
domState.innerText = currentFrame.state;
// 2. 位置位移
assembly.setAttribute('transform', `translate(0, ${currentY})`);
ringLeft.setAttribute('transform', `translate(${-expansion}, 0)`);
ringRight.setAttribute('transform', `translate(${expansion}, 0)`);
// 3. 颜色与发光
const fillColor = interpolateColor(colorCyanDark, colorRedDark, tempFactor);
pathLeft.setAttribute('fill', fillColor);
pathRight.setAttribute('fill', fillColor);
if (tempFactor > 0.8) {
pathLeft.setAttribute('filter', 'url(#glow-hot)');
pathRight.setAttribute('filter', 'url(#glow-hot)');
heatWaves.setAttribute('opacity', '1');
} else {
pathLeft.setAttribute('filter', 'url(#glow-cold)');
pathRight.setAttribute('filter', 'url(#glow-cold)');
heatWaves.setAttribute('opacity', '0');
}
// 4. 指示器透明度切换
// 当温度升高,间隙消失,过盈力出现
gapIndicator.setAttribute('opacity', 1 - tempFactor);
// 只有当完全在底部且温度高时才显示力 (Y需接近0)
const isSeated = currentY > -10;
forceIndicator.setAttribute('opacity', isSeated ? tempFactor : 0);
// 5. 更新俯视图的8瓣展开
const segments = document.querySelectorAll('.top-ring-segment');
segments.forEach(seg => {
seg.setAttribute('fill', fillColor);
// 使用transform做微小向外平移模拟径向膨胀
seg.setAttribute('transform', `translate(0, ${-tempFactor * 3})`);
});
requestAnimationFrame(animate);
}
// 页面加载完成后自动触发动画
window.addEventListener('DOMContentLoaded', () => {
requestAnimationFrame(animate);
});
</script>
</body>
</html>
积分规则:每轮对话扣10分
等待动画代码生成...
