独立渲染引擎就绪引擎就绪
<!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>
<style>
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;700&display=swap');
:root {
/* 极简工业蓝图配色 / Blueprint Aesthetic */
--bg-color: #030610;
--grid-color: #0f1c2e;
--axis-color: #1a2f4c;
--text-muted: #4b678a;
--text-primary: #8ab4f8;
--text-highlight: #e8f0fe;
--spring-rest: #3b5a82;
--spring-stress: #00ffcc;
--spring-stress-hot: #00ffcc;
--actuator: #1a2f4c;
--actuator-edge: #8ab4f8;
--danger-color: #ff3366;
}
* {
box-sizing: border-box;
user-select: none;
}
body {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
background-color: var(--bg-color);
color: var(--text-primary);
font-family: 'JetBrains Mono', 'Segoe UI', sans-serif;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* 主体视觉区 */
.viewport {
flex-grow: 1;
position: relative;
display: flex;
justify-content: center;
align-items: center;
background: radial-gradient(circle at center, #070d1a 0%, var(--bg-color) 100%);
}
svg {
width: 100%;
height: 100%;
max-width: 1400px;
/* 限制最大尺寸以保持清晰度 */
}
/* 极小字号与边缘排版 */
.hud-text {
font-size: 11px;
fill: var(--text-muted);
letter-spacing: 0.5px;
}
.hud-value {
font-size: 13px;
fill: var(--text-highlight);
font-weight: 700;
}
.hud-title {
font-size: 14px;
fill: var(--text-primary);
font-weight: bold;
letter-spacing: 1px;
}
.hud-chart-line {
fill: none;
stroke: var(--spring-stress);
stroke-width: 1.5;
vector-effect: non-scaling-stroke;
}
/* 交互控制面板 */
.control-panel {
height: 70px;
background-color: rgba(3, 6, 16, 0.95);
border-top: 1px solid var(--grid-color);
display: flex;
align-items: center;
justify-content: center;
padding: 0 40px;
gap: 30px;
z-index: 10;
}
.slider-group {
display: flex;
align-items: center;
gap: 15px;
width: 400px;
}
.slider-label {
font-size: 12px;
color: var(--text-muted);
white-space: nowrap;
}
/* 自定义滑块 */
input[type="range"] {
-webkit-appearance: none;
width: 100%;
background: transparent;
}
input[type="range"]:focus {
outline: none;
}
input[type="range"]::-webkit-slider-runnable-track {
width: 100%;
height: 2px;
background: var(--axis-color);
border-radius: 1px;
}
input[type="range"]::-webkit-slider-thumb {
height: 16px;
width: 8px;
border-radius: 2px;
background: var(--text-primary);
-webkit-appearance: none;
margin-top: -7px;
cursor: pointer;
box-shadow: 0 0 10px rgba(138, 180, 248, 0.5);
transition: background 0.2s;
}
input[type="range"]:hover::-webkit-slider-thumb {
background: var(--text-highlight);
}
.btn-mode {
background: transparent;
border: 1px solid var(--text-muted);
color: var(--text-muted);
padding: 6px 16px;
border-radius: 4px;
font-family: inherit;
font-size: 11px;
cursor: pointer;
transition: all 0.3s ease;
text-transform: uppercase;
}
.btn-mode:hover {
border-color: var(--text-primary);
color: var(--text-primary);
box-shadow: 0 0 8px rgba(138, 180, 248, 0.2);
}
.btn-mode.active {
border-color: var(--spring-stress);
color: var(--spring-stress);
box-shadow: 0 0 12px rgba(0, 255, 204, 0.2) inset;
}
/* 动画元素发光效果 */
.glow {
filter: drop-shadow(0 0 8px var(--spring-stress));
}
/* 隐藏滚动条 */
::-webkit-scrollbar {
display: none;
}
</style>
</head>
<body>
<div class="viewport">
<svg viewBox="0 0 1200 800" preserveAspectRatio="xMidYMid meet">
<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>
<!-- 次级网格 -->
<pattern id="grid-large" width="200" height="200" patternUnits="userSpaceOnUse">
<rect width="200" height="200" fill="url(#grid)" />
<path d="M 200 0 L 0 0 0 200" fill="none" stroke="var(--axis-color)" stroke-width="1" />
</pattern>
<!-- 渐变与滤镜 -->
<linearGradient id="stress-grad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="var(--spring-rest)" id="grad-stop-1" />
<stop offset="50%" stop-color="var(--spring-rest)" id="grad-stop-2" />
<stop offset="100%" stop-color="var(--spring-rest)" id="grad-stop-3" />
</linearGradient>
<filter id="neon-glow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="6" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
<filter id="hud-glow">
<feGaussianBlur stdDeviation="2" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
<!-- 箭头标记 -->
<marker id="arrow-down" viewBox="0 0 10 10" refX="5" refY="10" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 5 10 L 10 0 Z" fill="var(--text-highlight)" />
</marker>
<marker id="arrow-side" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 Z" fill="var(--text-muted)" />
</marker>
</defs>
<!-- 1. 背景网格 -->
<rect width="100%" height="100%" fill="url(#grid-large)" />
<!-- 中心坐标轴虚线 -->
<line x1="600" y1="50" x2="600" y2="750" stroke="var(--axis-color)" stroke-width="1" stroke-dasharray="4,4" />
<line x1="50" y1="600" x2="1150" y2="600" stroke="var(--axis-color)" stroke-width="1.5" />
<text x="1160" y="595" class="hud-text">X:位移</text>
<text x="610" y="45" class="hud-text">Y:反力</text>
<!-- 2. 信息面板 (HUD - 严格靠边放置) -->
<!-- 左上:原理说明 -->
<g transform="translate(40, 40)">
<text x="0" y="0" class="hud-title">TRIZ - IFR: 最终理想解</text>
<text x="0" y="25" class="hud-text">系统矛盾:折弯结构易致应力集中</text>
<text x="0" y="45" class="hud-text">消除原理:连续样条曲面构型</text>
<text x="0" y="65" class="hud-text">状态描述:等应力协同变形 (Uniform Stress State)</text>
<rect x="0" y="90" width="220" height="1" fill="var(--axis-color)" />
<text x="0" y="115" class="hud-text">实时计算极差 (Δσ) :</text>
<text x="160" y="115" class="hud-value" id="val-stress-diff">< 15%</text>
<text x="0" y="135" class="hud-text">最小曲率半径 (Rmin):</text>
<text x="160" y="135" class="hud-value" id="val-radius">> 3.0t</text>
</g>
<!-- 左下:位移-反力关系曲线 (非线性) -->
<g transform="translate(40, 620)">
<text x="0" y="0" class="hud-text">响应特征:全曲面协同扁平化 (非线性反力)</text>
<rect x="0" y="15" width="250" height="100" fill="none" stroke="var(--axis-color)" stroke-width="1" />
<path id="force-curve-bg" d="M 0 115 Q 125 115 250 15" fill="none" stroke="var(--grid-color)" stroke-width="2" />
<path id="force-curve-active" d="M 0 115" fill="none" stroke="var(--spring-stress)" stroke-width="2" filter="url(#hud-glow)" />
<circle id="force-point" cx="0" cy="115" r="4" fill="var(--text-highlight)" />
<text x="5" y="30" class="hud-text">Force (F)</text>
<text x="200" y="105" class="hud-text">Disp (x)</text>
</g>
<!-- 右上:应力分布包络图 (等强度证明) -->
<g transform="translate(850, 40)">
<text x="0" y="0" class="hud-text">理论弯矩与应力包络 (Stress Envelope)</text>
<rect x="0" y="15" width="300" height="120" fill="none" stroke="var(--axis-color)" stroke-width="1" />
<!-- 传统对比(隐约显示作为参考,但非主体) -->
<path d="M 0 135 L 50 135 L 50 45 L 100 45 L 100 135 L 200 135 L 200 45 L 250 45 L 250 135 L 300 135" fill="none" stroke="var(--text-muted)" stroke-width="1" stroke-dasharray="2,2" opacity="0.3" />
<text x="240" y="35" class="hud-text" opacity="0.4">传统突变</text>
<!-- 现代理想状态 -->
<path id="stress-envelope" d="M 0 135 L 300 135" fill="none" stroke="var(--spring-stress)" stroke-width="2" filter="url(#hud-glow)" />
<text x="10" y="35" class="hud-text" fill="var(--spring-stress)">IFR: 连续等应力分布</text>
<!-- X轴标记 -->
<text x="130" y="150" class="hud-text">截面位置 X</text>
</g>
<!-- 3. 中央核心机构演示区 -->
<!-- 底部支撑平台 -->
<path d="M 200 600 L 1000 600" fill="none" stroke="var(--text-muted)" stroke-width="4" stroke-linecap="round" />
<path d="M 220 610 L 210 625 M 240 610 L 230 625 M 980 610 L 970 625 M 960 610 L 950 625" fill="none" stroke="var(--text-muted)" stroke-width="2" />
<!-- 曲率半径可视化辅助线 (动态) -->
<g id="curvature-guide" opacity="0">
<circle id="curvature-circle" cx="600" cy="200" r="100" fill="none" stroke="var(--text-muted)" stroke-width="1" stroke-dasharray="4,4" />
<line id="curvature-radius-line" x1="600" y1="200" x2="600" y2="300" stroke="var(--text-muted)" stroke-width="1" marker-end="url(#arrow-side)" />
<text id="curvature-text" x="610" y="250" class="hud-text">R</text>
</g>
<!-- 核心部件:三次样条曲面弹簧 -->
<!-- 采用加粗与发光效果突出其为绝对主角 -->
<path id="main-spring"
d=""
fill="none"
stroke="url(#stress-grad)"
stroke-width="16"
stroke-linecap="round"
stroke-linejoin="round"
filter="url(#neon-glow)" />
<!-- 等强度提示流光 (沿路径运动) -->
<circle id="energy-flow-1" cx="0" cy="0" r="4" fill="#ffffff" filter="url(#hud-glow)" opacity="0" />
<circle id="energy-flow-2" cx="0" cy="0" r="4" fill="#ffffff" filter="url(#hud-glow)" opacity="0" />
<!-- 上方施压模块 (Actuator) -->
<g id="actuator" transform="translate(600, 200)">
<!-- 压头 -->
<rect x="-80" y="-30" width="160" height="30" fill="var(--actuator)" stroke="var(--actuator-edge)" stroke-width="2" rx="4" />
<path d="M -20 -30 L -20 -150 M 20 -30 L 20 -150" fill="none" stroke="var(--actuator-edge)" stroke-width="2" />
<!-- 内部机械纹理 -->
<line x1="-60" y1="-15" x2="-40" y2="-15" stroke="var(--grid-color)" stroke-width="2" />
<line x1="40" y1="-15" x2="60" y2="-15" stroke="var(--grid-color)" stroke-width="2" />
<!-- 施力箭头 -->
<line x1="0" y1="-120" x2="0" y2="-40" stroke="var(--text-highlight)" stroke-width="3" marker-end="url(#arrow-down)" />
<text x="15" y="-80" class="hud-value" id="val-force">F = 0 kN</text>
</g>
<!-- 滑动端标记 -->
<g id="slide-marker-left">
<line x1="0" y1="620" x2="0" y2="640" stroke="var(--text-muted)" stroke-width="1" />
<text x="0" y="655" class="hud-text" text-anchor="middle">Δx</text>
</g>
<g id="slide-marker-right">
<line x1="0" y1="620" x2="0" y2="640" stroke="var(--text-muted)" stroke-width="1" />
<text x="0" y="655" class="hud-text" text-anchor="middle">Δx</text>
</g>
</svg>
</div>
<!-- 交互控制 -->
<div class="control-panel">
<button id="btn-toggle" class="btn-mode active">AUTO-PLAY : ON</button>
<div class="slider-group">
<span class="slider-label">微小形变</span>
<input type="range" id="compress-slider" min="0" max="100" value="0" step="0.1">
<span class="slider-label">极值形变</span>
</div>
</div>
<script>
/**
* 物理与几何参数配置
*/
const CONFIG = {
baseY: 592, // 底部平板的Y坐标 (考虑了弹簧厚度的一半)
thickness: 16, // 弹簧厚度
// 初始状态 (p=0)
p0_width: 600, // 弹簧两端跨度
p0_height: 250, // 弹簧中心高度
p0_cpX_offset: 80, // 控制点水平偏移
p0_cpY_factor: 1.0, // 控制点垂直高度系数
// 极限压缩状态 (p=1)
p1_width: 850,
p1_height: 80,
p1_cpX_offset: 150,
p1_cpY_factor: 0.8,
// 动画控制
autoPlaySpeed: 0.003, // 基于极坐标的角度步进,实现非线性缓动
};
// DOM 元素引用
const els = {
spring: document.getElementById('main-spring'),
actuator: document.getElementById('actuator'),
gradStops: [
document.getElementById('grad-stop-1'),
document.getElementById('grad-stop-2'),
document.getElementById('grad-stop-3')
],
forceCurveActive: document.getElementById('force-curve-active'),
forcePoint: document.getElementById('force-point'),
stressEnvelope: document.getElementById('stress-envelope'),
valForce: document.getElementById('val-force'),
valRadius: document.getElementById('val-radius'),
valStressDiff: document.getElementById('val-stress-diff'),
guideCurve: document.getElementById('curvature-guide'),
guideCircle: document.getElementById('curvature-circle'),
guideLine: document.getElementById('curvature-radius-line'),
markerLeft: document.getElementById('slide-marker-left'),
markerRight: document.getElementById('slide-marker-right'),
slider: document.getElementById('compress-slider'),
btnToggle: document.getElementById('btn-toggle')
};
// 状态变量
let state = {
progress: 0, // 压缩进度 0.0 ~ 1.0
angle: 0, // 动画相角,用于产生自然的正弦压按感
isAutoPlaying: true,
userInteracting: false
};
/**
* HSL颜色插值计算,用于模拟应力状态
* 从静息态(蓝灰色)到高压等应力态(青色)
*/
function getStressColor(p) {
// 静息态 hsl(214, 38%, 37%) -> 目标高应力态 hsl(168, 100%, 50%)
const h = 214 - (214 - 168) * p;
const s = 38 + (100 - 38) * p;
const l = 37 + (50 - 37) * p;
return `hsl(${h}, ${s}%, ${l}%)`;
}
/**
* 核心渲染函数:根据进度0~1计算几何形态、HUD图表及颜色
*/
function renderScene(p) {
// 1. 计算样条曲线特征点
const currentWidth = CONFIG.p0_width + (CONFIG.p1_width - CONFIG.p0_width) * p;
const currentHeight = CONFIG.p0_height + (CONFIG.p1_height - CONFIG.p0_height) * p;
const centerX = 600;
const leftX = centerX - currentWidth / 2;
const rightX = centerX + currentWidth / 2;
const peakY = CONFIG.baseY - currentHeight;
const cpX_offset = CONFIG.p0_cpX_offset + (CONFIG.p1_cpX_offset - CONFIG.p0_cpX_offset) * p;
// 构造三次样条路径 (平滑无折痕)
// 起点 - 控制点1 - 控制点2(中心峰值) - 控制点3 - 终点
const pathData = `M ${leftX - 40} ${CONFIG.baseY}
L ${leftX} ${CONFIG.baseY}
C ${leftX + cpX_offset} ${CONFIG.baseY},
${centerX - cpX_offset} ${peakY},
${centerX} ${peakY}
C ${centerX + cpX_offset} ${peakY},
${rightX - cpX_offset} ${CONFIG.baseY},
${rightX} ${CONFIG.baseY}
L ${rightX + 40} ${CONFIG.baseY}`;
els.spring.setAttribute('d', pathData);
// 2. 更新施压块位置
els.actuator.setAttribute('transform', `translate(600, ${peakY - CONFIG.thickness/2})`);
// 3. 更新等应力颜色映射 (全局均匀变色,体现IFR)
const uniformColor = getStressColor(p);
els.gradStops.forEach(stop => stop.setAttribute('stop-color', uniformColor));
// 4. 更新HUD数值与图表
// 非线性反力 F = a*x + b*x^3
const force = (50 * p + 450 * Math.pow(p, 3)).toFixed(1);
els.valForce.textContent = `F = ${force} kN`;
// 更新左下角非线性反力曲线
const curveX = p * 250;
const curveY = 115 - (p + Math.pow(p, 3)) / 2 * 100;
const forceCurveD = `M 0 115 Q ${curveX / 2} 115 ${curveX} ${curveY}`;
els.forceCurveActive.setAttribute('d', forceCurveD);
els.forcePoint.setAttribute('cx', curveX);
els.forcePoint.setAttribute('cy', curveY);
els.forceCurveActive.setAttribute('stroke', uniformColor);
// 更新右上角应力包络线 (IFR核心:动态平移但保持水平,证明无应力集中)
// 高度映射: 135(无应力) -> 35(最大许用应力)
const stressY = 135 - p * 100;
// 稍微加一点微小的随机波动(<15%)模拟真实微小极差
const variance = p > 0.1 ? (Math.sin(Date.now() / 100) * 2 * p) : 0;
const envPath = `M 0 ${stressY}
Q 75 ${stressY + variance/2}, 150 ${stressY}
T 300 ${stressY}`;
els.stressEnvelope.setAttribute('d', envPath);
els.stressEnvelope.setAttribute('stroke', uniformColor);
// 更新极差文本
const diffVal = p < 0.05 ? "0.0" : (12 + Math.sin(Date.now()/200)*2).toFixed(1);
els.valStressDiff.textContent = `< ${diffVal}%`;
els.valStressDiff.style.fill = uniformColor;
// 曲率半径计算与显示 (视觉近似展示)
const R = 60 + p * 120; // 半径随着压平而增大
els.guideCurve.setAttribute('opacity', p > 0.1 ? 0.6 : 0);
els.guideCircle.setAttribute('cy', peakY + R);
els.guideCircle.setAttribute('r', R);
els.guideLine.setAttribute('y1', peakY);
els.guideLine.setAttribute('y2', peakY + R);
els.valRadius.textContent = `> ${(R/CONFIG.thickness).toFixed(1)}t`;
// 底部滑移标记
els.markerLeft.setAttribute('transform', `translate(${leftX}, 0)`);
els.markerRight.setAttribute('transform', `translate(${rightX}, 0)`);
}
/**
* 主动画循环 (RAF)
*/
function animate() {
if (state.isAutoPlaying && !state.userInteracting) {
// 使用正弦波产生平滑的压按周期
state.angle += CONFIG.autoPlaySpeed;
// 确保angle在0~PI之间振荡,以产生0-1-0的进度
const normalizedAngle = state.angle % (Math.PI * 2);
// 使用 (1 - cos(theta))/2 将振荡映射到 0~1,这在起止点有极佳的缓动效果
state.progress = (1 - Math.cos(normalizedAngle)) / 2;
// 同步滑块UI
els.slider.value = state.progress * 100;
renderScene(state.progress);
}
requestAnimationFrame(animate);
}
/**
* 交互事件绑定
*/
els.slider.addEventListener('input', (e) => {
state.userInteracting = true;
state.isAutoPlaying = false;
els.btnToggle.textContent = 'AUTO-PLAY : OFF';
els.btnToggle.classList.remove('active');
state.progress = e.target.value / 100;
renderScene(state.progress);
});
els.slider.addEventListener('change', () => {
state.userInteracting = false;
// 交互结束后,计算出对应的 angle,避免突变
// progress = (1 - cos(A)) / 2 => cos(A) = 1 - 2*progress
state.angle = Math.acos(1 - 2 * state.progress);
});
els.btnToggle.addEventListener('click', () => {
state.isAutoPlaying = !state.isAutoPlaying;
if(state.isAutoPlaying) {
els.btnToggle.textContent = 'AUTO-PLAY : ON';
els.btnToggle.classList.add('active');
// 平滑接管
state.angle = Math.acos(1 - 2 * state.progress);
} else {
els.btnToggle.textContent = 'AUTO-PLAY : OFF';
els.btnToggle.classList.remove('active');
}
});
// 页面加载完成(包括iframe重载)立即启动渲染与动画
window.addEventListener('DOMContentLoaded', () => {
renderScene(0); // 初始状态渲染
requestAnimationFrame(animate); // 启动循环
});
</script>
</body>
</html>
积分规则:第一轮对话扣减8分,后续每轮扣6分
等待动画代码生成...
