分享图
动画工坊
引擎就绪
<!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">&lt; 15%</text>
                <text x="0" y="135" class="hud-text">最小曲率半径 (Rmin):</text>
                <text x="160" y="135" class="hud-value" id="val-radius">&gt; 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分