分享图
动画工坊
引擎就绪

以下是为您设计的高保真 SVG 交互式原理动画。

该设计采用了工业蓝图与赛博朋克融合的暗色高保真美学 (Cyber-Blueprint Aesthetics),以极致的视觉对比度和精确的机械运动,直观展现 TRIZ 中“最终理想解 (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>
    <style>
        @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&family=Noto+Sans+SC:wght@400;700&display=swap');

        :root {
            --bg-color: #060b13;
            --grid-color: rgba(56, 189, 248, 0.05);
            --hub-color: #111827;
            --hub-stroke: #334155;
            --shaft-color: #0f172a;
            --shaft-stroke: #475569;
            --inner-cone: #ff7e67;
            --outer-cone: #00f0ff;
            --bolt-color: #cbd5e1;
            --text-muted: #64748b;
            --text-glow: #e0f2fe;
            --force-radial: #00f0ff;
            --force-axial: #ff5580;
        }

        body, html {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            background-color: var(--bg-color);
            font-family: 'JetBrains Mono', 'Noto Sans SC', monospace;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            overflow: hidden;
            color: var(--text-glow);
        }

        #animation-container {
            position: relative;
            width: 90vw;
            max-width: 1200px;
            aspect-ratio: 16 / 9;
            background: radial-gradient(circle at center, #0a1122 0%, #03060a 100%);
            border: 1px solid rgba(56, 189, 248, 0.2);
            border-radius: 8px;
            box-shadow: 0 0 40px rgba(0, 0, 0, 0.8), inset 0 0 20px rgba(56, 189, 248, 0.05);
            display: flex;
            flex-direction: column;
        }

        svg {
            width: 100%;
            height: 100%;
            display: block;
        }

        /* 文字排版严格遵循边缘化、小型化,确保不遮挡核心动画 */
        .text-sm { font-size: 13px; fill: var(--text-muted); }
        .text-md { font-size: 16px; font-weight: bold; fill: var(--text-glow); }
        .text-data { font-size: 14px; fill: var(--outer-cone); font-weight: bold; }
        .text-title { font-size: 20px; font-weight: bold; fill: #fff; letter-spacing: 1px; }

        /* 控制面板 */
        .controls {
            position: absolute;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            display: flex;
            align-items: center;
            gap: 15px;
            background: rgba(15, 23, 42, 0.8);
            backdrop-filter: blur(8px);
            padding: 10px 24px;
            border-radius: 30px;
            border: 1px solid rgba(56, 189, 248, 0.3);
            z-index: 10;
        }

        input[type=range] {
            -webkit-appearance: none;
            width: 200px;
            background: transparent;
        }
        input[type=range]::-webkit-slider-runnable-track {
            width: 100%;
            height: 4px;
            background: #334155;
            border-radius: 2px;
        }
        input[type=range]::-webkit-slider-thumb {
            -webkit-appearance: none;
            height: 16px;
            width: 16px;
            border-radius: 50%;
            background: var(--outer-cone);
            box-shadow: 0 0 10px var(--outer-cone);
            margin-top: -6px;
            cursor: pointer;
            transition: transform 0.1s;
        }
        input[type=range]::-webkit-slider-thumb:hover {
            transform: scale(1.2);
        }

        #mode-status {
            font-size: 12px;
            color: var(--outer-cone);
            min-width: 80px;
            text-align: center;
        }

        .ifr-badge {
            opacity: 0;
            transition: opacity 0.3s;
        }
        .ifr-badge.active {
            opacity: 1;
        }
    </style>
</head>
<body>

<div id="animation-container">
    <svg viewBox="0 0 1000 600" 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="1"/>
            </pattern>
            
            <!-- 材质截面剖面线 -->
            <pattern id="hatch-hub" width="8" height="8" patternTransform="rotate(45)" patternUnits="userSpaceOnUse">
                <line x1="0" y1="0" x2="0" y2="8" stroke="rgba(255,255,255,0.05)" stroke-width="2" />
            </pattern>
            <pattern id="hatch-shaft" width="10" height="10" patternTransform="rotate(-45)" patternUnits="userSpaceOnUse">
                <line x1="0" y1="0" x2="0" y2="10" stroke="rgba(255,255,255,0.08)" stroke-width="1.5" />
            </pattern>

            <!-- 渐变质感 -->
            <linearGradient id="inner-grad" x1="0%" y1="0%" x2="0%" y2="100%">
                <stop offset="0%" stop-color="#ff7e67"/>
                <stop offset="100%" stop-color="#c44d3a"/>
            </linearGradient>
            <linearGradient id="outer-grad" x1="0%" y1="0%" x2="0%" y2="100%">
                <stop offset="0%" stop-color="#00f0ff"/>
                <stop offset="100%" stop-color="#008a99"/>
            </linearGradient>
            <linearGradient id="bolt-grad" x1="0%" y1="0%" x2="0%" y2="100%">
                <stop offset="0%" stop-color="#ffffff"/>
                <stop offset="50%" stop-color="#94a3b8"/>
                <stop offset="100%" stop-color="#475569"/>
            </linearGradient>

            <!-- 发光滤镜 -->
            <filter id="neon-glow" x="-20%" y="-20%" width="140%" height="140%">
                <feGaussianBlur stdDeviation="5" result="blur" />
                <feMerge>
                    <feMergeNode in="blur" />
                    <feMergeNode in="SourceGraphic" />
                </feMerge>
            </filter>

            <!-- 箭头标记 -->
            <marker id="arrow-radial-up" viewBox="0 0 10 10" refX="5" refY="0" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
                <path d="M 0 10 L 5 0 L 10 10 Z" fill="var(--force-radial)" />
            </marker>
            <marker id="arrow-axial-left" viewBox="0 0 10 10" refX="0" refY="5" markerWidth="5" markerHeight="5" orient="auto-start-reverse">
                <path d="M 10 0 L 0 5 L 10 10 Z" fill="var(--force-axial)" />
            </marker>
        </defs>

        <!-- 背景 -->
        <rect width="100%" height="100%" fill="url(#grid)" />

        <!-- 静态标识与文字 (避开中心动画区) -->
        <g transform="translate(40, 40)">
            <text class="text-title" x="0" y="0">双锥面胀紧套原理动画</text>
            <text class="text-sm" x="0" y="25">TRIZ IFR (理想最终解) 演示:消除间隙配合的矛盾</text>
            <line x1="0" y1="40" x2="350" y2="40" stroke="rgba(255,255,255,0.2)" stroke-width="1" />
        </g>

        <!-- 图例 -->
        <g transform="translate(40, 520)">
            <rect x="0" y="0" width="12" height="12" fill="#111827" stroke="#334155" />
            <text class="text-sm" x="20" y="11">轮毂/轴 (孔与轴)</text>
            
            <rect x="140" y="0" width="12" height="12" fill="url(#outer-grad)" />
            <text class="text-sm" x="160" y="11">外环 (内锥面)</text>
            
            <rect x="280" y="0" width="12" height="12" fill="url(#inner-grad)" />
            <text class="text-sm" x="300" y="11">内环 (外锥面)</text>
        </g>

        <!-- 遥测数据面板 (右上角) -->
        <g transform="translate(780, 50)" class="telemetry">
            <rect x="-15" y="-20" width="200" height="130" fill="rgba(15, 23, 42, 0.8)" rx="4" stroke="rgba(56,189,248,0.3)"/>
            <text class="text-sm" x="0" y="0">实时状态监测 / STATUS</text>
            <line x1="0" y1="10" x2="170" y2="10" stroke="rgba(56,189,248,0.3)" />
            
            <text class="text-sm" x="0" y="35">预紧扭矩: <tspan id="data-torque" class="text-data">0.0</tspan> N·m</text>
            <text class="text-sm" x="0" y="60">相对位移: <tspan id="data-disp" class="text-data">0.0</tspan> mm</text>
            <text class="text-sm" x="0" y="85">配合间隙: <tspan id="data-gap" class="text-data">0.15</tspan> mm</text>
            
            <!-- IFR 徽章 -->
            <g id="ifr-badge" class="ifr-badge" transform="translate(0, 100)">
                <rect x="0" y="-12" width="165" height="20" fill="rgba(0, 240, 255, 0.1)" rx="2" stroke="#00f0ff" stroke-width="1"/>
                <text class="text-sm" x="82" y="2" fill="#00f0ff" text-anchor="middle" font-weight="bold">IFR 达成: 无隙过盈锁死</text>
            </g>
        </g>

        <!-- 核心机械结构容器 (中心对齐) -->
        <g id="mechanism" transform="translate(0, 0)">
            
            <!-- 中心线 -->
            <line x1="50" y1="300" x2="950" y2="300" stroke="#475569" stroke-width="1.5" stroke-dasharray="15, 5, 4, 5" />
            <text class="text-sm" x="960" y="304" fill="#475569">CL</text>

            <!-- 1. 外部轮毂 (Hub) 剖面 - 上半部分 -->
            <path d="M 150 60 L 850 60 L 850 140 L 150 140 Z" fill="var(--hub-color)" stroke="var(--hub-stroke)" stroke-width="2" />
            <path d="M 150 60 L 850 60 L 850 140 L 150 140 Z" fill="url(#hatch-hub)" />
            
            <!-- 1. 外部轮毂 (Hub) 剖面 - 下半部分 -->
            <path d="M 150 540 L 850 540 L 850 460 L 150 460 Z" fill="var(--hub-color)" stroke="var(--hub-stroke)" stroke-width="2" />
            <path d="M 150 540 L 850 540 L 850 460 L 150 460 Z" fill="url(#hatch-hub)" />

            <!-- 2. 内部轴 (Shaft) 剖面 - 上下完整 -->
            <path d="M 100 240 L 900 240 L 900 360 L 100 360 Z" fill="var(--shaft-color)" stroke="var(--shaft-stroke)" stroke-width="2" />
            <path d="M 100 240 L 900 240 L 900 360 L 100 360 Z" fill="url(#hatch-shaft)" />

            <!-- 间隙高亮指示 (未锁紧时显示) -->
            <g id="gap-indicators" stroke="#ffcc00" stroke-width="2" opacity="1">
                <line x1="380" y1="144" x2="620" y2="144" stroke-dasharray="4,4" />
                <line x1="380" y1="236" x2="620" y2="236" stroke-dasharray="4,4" />
                <line x1="380" y1="364" x2="620" y2="364" stroke-dasharray="4,4" />
                <line x1="380" y1="456" x2="620" y2="456" stroke-dasharray="4,4" />
            </g>

            <!-- 3. 外环 (Inner Cone) -->
            <g id="outer-ring-top">
                <!-- 外环法兰在左侧, 上方平面, 下方斜面 -->
                <path d="M 330 148 L 650 148 L 650 216 L 380 162 L 380 230 L 330 230 Z" fill="url(#outer-grad)" stroke="#00b8c4" stroke-width="1" />
            </g>
            <g id="outer-ring-bottom">
                <path d="M 330 452 L 650 452 L 650 384 L 380 438 L 380 370 L 330 370 Z" fill="url(#outer-grad)" stroke="#00b8c4" stroke-width="1" />
            </g>

            <!-- 4. 内环 (Outer Cone) -->
            <g id="inner-ring-top">
                <!-- 内环斜面贴合, 底部平面 -->
                <path d="M 380 232 L 650 232 L 650 216 L 380 162 Z" fill="url(#inner-grad)" stroke="#c44d3a" stroke-width="1" />
                <line id="wedge-glow-top" x1="380" y1="162" x2="650" y2="216" stroke="#00f0ff" stroke-width="3" filter="url(#neon-glow)" opacity="0"/>
            </g>
            <g id="inner-ring-bottom">
                <path d="M 380 368 L 650 368 L 650 384 L 380 438 Z" fill="url(#inner-grad)" stroke="#c44d3a" stroke-width="1" />
                <line id="wedge-glow-bottom" x1="380" y1="438" x2="650" y2="384" stroke="#00f0ff" stroke-width="3" filter="url(#neon-glow)" opacity="0"/>
            </g>

            <!-- 5. 高强度螺栓 (Bolt) -->
            <g id="bolt-top">
                <!-- 螺栓头 -->
                <rect x="290" y="180" width="40" height="20" rx="2" fill="url(#bolt-grad)" stroke="#334155"/>
                <!-- 螺柱穿过外环法兰进入内环 -->
                <rect x="330" y="186" width="180" height="8" fill="url(#bolt-grad)" stroke="#334155"/>
                <!-- 螺纹标识 -->
                <path d="M 420 186 L 420 194 M 430 186 L 430 194 M 440 186 L 440 194 M 450 186 L 450 194 M 460 186 L 460 194 M 470 186 L 470 194 M 480 186 L 480 194 M 490 186 L 490 194 M 500 186 L 500 194" stroke="#475569" stroke-width="1"/>
            </g>
            <g id="bolt-bottom">
                <!-- 螺栓头 -->
                <rect x="290" y="400" width="40" height="20" rx="2" fill="url(#bolt-grad)" stroke="#334155"/>
                <!-- 螺柱 -->
                <rect x="330" y="406" width="180" height="8" fill="url(#bolt-grad)" stroke="#334155"/>
                <!-- 螺纹标识 -->
                <path d="M 420 406 L 420 414 M 430 406 L 430 414 M 440 406 L 440 414 M 450 406 L 450 414 M 460 406 L 460 414 M 470 406 L 470 414 M 480 406 L 480 414 M 490 406 L 490 414 M 500 406 L 500 414" stroke="#475569" stroke-width="1"/>
            </g>

            <!-- 6. 力学指示箭头 (受力时显现) -->
            <g id="force-arrows" opacity="0">
                <!-- 轴向预紧力 (螺栓拉力) -->
                <line x1="380" y1="170" x2="310" y2="170" stroke="var(--force-axial)" stroke-width="2" marker-end="url(#arrow-axial-left)" filter="url(#neon-glow)"/>
                <line x1="380" y1="430" x2="310" y2="430" stroke="var(--force-axial)" stroke-width="2" marker-end="url(#arrow-axial-left)" filter="url(#neon-glow)"/>
                <text class="text-sm" x="290" y="160" fill="var(--force-axial)">F_axial (拉扯内环)</text>

                <!-- 径向正压力 (胀紧孔壁与轴壁) -->
                <!-- 上轮毂压紧 -->
                <g stroke="var(--force-radial)" stroke-width="2" marker-start="url(#arrow-radial-up)" filter="url(#neon-glow)">
                    <line x1="420" y1="130" x2="420" y2="148" />
                    <line x1="500" y1="130" x2="500" y2="148" />
                    <line x1="580" y1="130" x2="580" y2="148" />
                </g>
                <!-- 上轴壁压紧 -->
                <g stroke="var(--force-radial)" stroke-width="2" marker-start="url(#arrow-radial-up)" filter="url(#neon-glow)">
                    <line x1="420" y1="250" x2="420" y2="232" />
                    <line x1="500" y1="250" x2="500" y2="232" />
                    <line x1="580" y1="250" x2="580" y2="232" />
                </g>
                <!-- 下轴壁压紧 -->
                <g stroke="var(--force-radial)" stroke-width="2" marker-start="url(#arrow-radial-up)" filter="url(#neon-glow)">
                    <line x1="420" y1="350" x2="420" y2="368" />
                    <line x1="500" y1="350" x2="500" y2="368" />
                    <line x1="580" y1="350" x2="580" y2="368" />
                </g>
                <!-- 下轮毂压紧 -->
                <g stroke="var(--force-radial)" stroke-width="2" marker-start="url(#arrow-radial-up)" filter="url(#neon-glow)">
                    <line x1="420" y1="470" x2="420" y2="452" />
                    <line x1="500" y1="470" x2="500" y2="452" />
                    <line x1="580" y1="470" x2="580" y2="452" />
                </g>
                <text class="text-sm" x="600" y="125" fill="var(--force-radial)">P_radial (径向贴合锁死)</text>
            </g>

        </g>
    </svg>

    <!-- 底部交互控制 -->
    <div class="controls">
        <input type="range" id="manual-slider" min="0" max="1" step="0.001" value="0">
        <span id="mode-status">自动播放中...</span>
    </div>
</div>

<script>
    document.addEventListener("DOMContentLoaded", () => {
        // 核心动画参数
        const CONFIG = {
            maxDisplacementX: -45, // 内环向左最大位移
            maxDisplacementY: 8,   // 径向最大膨胀位移(单侧)
            maxTorque: 30,         // N·m
            initialGap: 0.15       // mm
        };

        // DOM 元素引用
        const els = {
            innerTop: document.getElementById('inner-ring-top'),
            innerBottom: document.getElementById('inner-ring-bottom'),
            outerTop: document.getElementById('outer-ring-top'),
            outerBottom: document.getElementById('outer-ring-bottom'),
            boltTop: document.getElementById('bolt-top'),
            boltBottom: document.getElementById('bolt-bottom'),
            gapIndicators: document.getElementById('gap-indicators'),
            forceArrows: document.getElementById('force-arrows'),
            wedgeGlowTop: document.getElementById('wedge-glow-top'),
            wedgeGlowBottom: document.getElementById('wedge-glow-bottom'),
            slider: document.getElementById('manual-slider'),
            statusText: document.getElementById('mode-status'),
            dataTorque: document.getElementById('data-torque'),
            dataDisp: document.getElementById('data-disp'),
            dataGap: document.getElementById('data-gap'),
            ifrBadge: document.getElementById('ifr-badge')
        };

        // 动画状态
        let state = {
            progress: 0,
            direction: 1,
            isAutoPlaying: true,
            speed: 0.004
        };

        // 缓动函数 (平滑加减速)
        const easeInOutCubic = t => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;

        // 核心渲染逻辑
        function updateVisuals(p) {
            const eased = easeInOutCubic(p);
            
            // 物理位移计算 (楔形效应转换)
            // 内环向左(X)移动,由于锥面作用,内环被迫向下(Y)移动,外环被迫向上(Y)移动,实现双向抱死
            const dx = CONFIG.maxDisplacementX * eased;
            const dy = CONFIG.maxDisplacementY * eased;

            // 应用 Transform
            els.innerTop.setAttribute('transform', `translate(${dx}, ${dy/2})`);
            els.outerTop.setAttribute('transform', `translate(0, ${-dy/2})`);
            
            els.innerBottom.setAttribute('transform', `translate(${dx}, ${-dy/2})`);
            els.outerBottom.setAttribute('transform', `translate(0, ${dy/2})`);

            // 螺栓虽内环旋进视觉上相对外环向左移动
            els.boltTop.setAttribute('transform', `translate(${dx*0.2}, 0)`);
            els.boltBottom.setAttribute('transform', `translate(${dx*0.2}, 0)`);

            // 视觉特效与数据更新
            const isTight = p > 0.8;
            const tightRatio = isTight ? (p - 0.8) * 5 : 0; // 0 to 1

            els.gapIndicators.setAttribute('opacity', 1 - eased);
            els.forceArrows.setAttribute('opacity', tightRatio);
            els.wedgeGlowTop.setAttribute('opacity', tightRatio * 0.8);
            els.wedgeGlowBottom.setAttribute('opacity', tightRatio * 0.8);

            // 更新遥测数据
            els.dataTorque.textContent = (CONFIG.maxTorque * tightRatio).toFixed(1);
            els.dataDisp.textContent = Math.abs(dx * 0.05).toFixed(2);
            
            const currentGap = Math.max(0, CONFIG.initialGap - (dy * 0.02));
            els.dataGap.textContent = currentGap.toFixed(2);

            // IFR 状态徽章切换
            if (currentGap <= 0.01 && !els.ifrBadge.classList.contains('active')) {
                els.ifrBadge.classList.add('active');
                els.dataGap.style.fill = "#00f0ff";
            } else if (currentGap > 0.01 && els.ifrBadge.classList.contains('active')) {
                els.ifrBadge.classList.remove('active');
                els.dataGap.style.fill = "var(--outer-cone)";
            }

            // 同步滑块位置
            if(state.isAutoPlaying) {
                els.slider.value = p;
            }
        }

        // 自动播放循环
        function animate() {
            if (state.isAutoPlaying) {
                state.progress += state.speed * state.direction;
                
                // 在两端停留片刻
                if (state.progress > 1.3) {
                    state.progress = 1.3;
                    state.direction = -1;
                } else if (state.progress < -0.2) {
                    state.progress = -0.2;
                    state.direction = 1;
                }

                // 限制传入更新函数的范围在 0-1
                updateVisuals(Math.max(0, Math.min(1, state.progress)));
            }
            requestAnimationFrame(animate);
        }

        // 交互事件绑定
        els.slider.addEventListener('input', (e) => {
            state.isAutoPlaying = false;
            els.statusText.textContent = "手动控制中";
            els.statusText.style.color = "#ff7e67";
            updateVisuals(parseFloat(e.target.value));
        });

        // 点击背景恢复自动播放
        document.getElementById('animation-container').addEventListener('dblclick', () => {
            if(!state.isAutoPlaying) {
                state.isAutoPlaying = true;
                state.progress = parseFloat(els.slider.value);
                els.statusText.textContent = "自动播放中...";
                els.statusText.style.color = "var(--outer-cone)";
            }
        });

        // 启动
        requestAnimationFrame(animate);
    });
</script>

</body>
</html>
积分规则:第一轮对话扣减8分,后续每轮扣6分