分享图
动画工坊
引擎就绪
<!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>
        :root {
            --bg-base: #050914;
            --panel-bg: rgba(10, 16, 29, 0.85);
            --border-color: #1e293b;
            --text-main: #94a3b8;
            --text-highlight: #f8fafc;
            --fluid-normal: #00f0ff;
            --fluid-alert: #39ff14;
            --struct-main: #334155;
            --struct-light: #475569;
        }

        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body, html {
            width: 100%;
            height: 100%;
            background-color: var(--bg-base);
            font-family: 'JetBrains Mono', 'Fira Code', 'SF Mono', Consolas, monospace;
            overflow: hidden;
            display: flex;
            justify-content: center;
            align-items: center;
            color: var(--text-main);
        }

        /* 核心视图容器 */
        .viewport {
            position: relative;
            width: 100%;
            height: 100%;
            max-width: 1600px;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        svg {
            width: 100%;
            height: 100%;
            max-height: 90vh;
        }

        /* 绝对定位的浮动面板:极简、边缘化、不遮挡 */
        .overlay-panel {
            position: absolute;
            background: var(--panel-bg);
            border: 1px solid var(--border-color);
            backdrop-filter: blur(8px);
            -webkit-backdrop-filter: blur(8px);
            padding: 16px;
            border-radius: 8px;
            z-index: 10;
        }

        .panel-top-left {
            top: 24px;
            left: 24px;
            max-width: 280px;
        }

        .panel-bottom-right {
            bottom: 24px;
            right: 24px;
            min-width: 260px;
        }

        .panel-title {
            font-size: 14px;
            font-weight: bold;
            color: var(--text-highlight);
            margin-bottom: 8px;
            letter-spacing: 1px;
            border-bottom: 1px solid var(--border-color);
            padding-bottom: 6px;
        }

        .panel-desc {
            font-size: 11px;
            line-height: 1.6;
            color: var(--text-main);
        }

        .highlight-triz {
            color: var(--fluid-alert);
            font-weight: bold;
        }

        /* 滑块交互组件 */
        .control-group {
            display: flex;
            flex-direction: column;
            gap: 12px;
            margin-top: 8px;
        }

        .control-label {
            display: flex;
            justify-content: space-between;
            font-size: 11px;
            color: var(--text-highlight);
        }

        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: 4px;
            cursor: pointer;
            background: var(--struct-main);
            border-radius: 2px;
        }

        input[type=range]::-webkit-slider-thumb {
            height: 16px;
            width: 8px;
            border-radius: 2px;
            background: var(--fluid-alert);
            cursor: pointer;
            -webkit-appearance: none;
            margin-top: -6px;
            box-shadow: 0 0 8px rgba(57, 255, 20, 0.6);
        }

        /* 状态指示器 */
        .status-indicator {
            display: flex;
            align-items: center;
            gap: 8px;
            font-size: 11px;
            margin-top: 12px;
        }

        .status-dot {
            width: 8px;
            height: 8px;
            border-radius: 50%;
            background-color: var(--fluid-normal);
            box-shadow: 0 0 8px var(--fluid-normal);
            transition: all 0.3s ease;
        }

        .status-dot.active {
            background-color: var(--fluid-alert);
            box-shadow: 0 0 12px var(--fluid-alert);
        }

        .svg-text {
            font-family: inherit;
            font-size: 11px;
            fill: #64748b;
            pointer-events: none;
        }

        .svg-value {
            font-size: 12px;
            fill: #e2e8f0;
            font-weight: bold;
        }
    </style>
</head>
<body>

    <div class="viewport">
        <!-- 信息面板 (左上) -->
        <div class="overlay-panel panel-top-left">
            <div class="panel-title">无源溢流自动分流系统</div>
            <div class="panel-desc">
                基于 TRIZ <span class="highlight-triz">最终理想解 (IFR)</span> 设计:<br><br>
                无需传感器与动力介入,利用重力势能与几何高度差,当液位超越临界阈值时自动实现分流泄压。<br><br>
                系统附带 U 型液封,满足气液隔离要求,在极简结构下实现核心矛盾的突破。
            </div>
        </div>

        <!-- 控制面板 (右下) -->
        <div class="overlay-panel panel-bottom-right">
            <div class="panel-title">系统参数实时控制</div>
            <div class="control-group">
                <div class="control-label">
                    <span>溢流堰设定高度</span>
                    <span id="weir-val-display">250 mm</span>
                </div>
                <input type="range" id="weir-slider" min="200" max="300" value="250" step="5">
                
                <div class="status-indicator">
                    <div class="status-dot" id="status-led"></div>
                    <span id="status-text">系统状态:正常运行中</span>
                </div>
                
                <div style="display: flex; justify-content: space-between; font-size: 10px; color: #64748b; margin-top: 4px;">
                    <span>旁通流量: <span id="bypass-flow-display" style="color: var(--fluid-alert);">0.0</span> m³/h</span>
                </div>
            </div>
        </div>

        <!-- 核心动画 SVG -->
        <svg viewBox="0 0 1200 850" 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="rgba(255,255,255,0.03)" stroke-width="1"/>
                </pattern>

                <!-- 流体发光滤镜 -->
                <filter id="glow-normal" x="-20%" y="-20%" width="140%" height="140%">
                    <feGaussianBlur stdDeviation="4" result="blur" />
                    <feComposite in="SourceGraphic" in2="blur" operator="over"/>
                </filter>
                <filter id="glow-alert" x="-50%" y="-50%" width="200%" height="200%">
                    <feGaussianBlur stdDeviation="6" result="blur" />
                    <feComposite in="SourceGraphic" in2="blur" operator="over"/>
                </filter>

                <!-- 流体渐变 -->
                <linearGradient id="fluid-grad-normal" x1="0" y1="0" x2="0" y2="1">
                    <stop offset="0%" stop-color="#00f0ff" stop-opacity="0.9"/>
                    <stop offset="100%" stop-color="#0284c7" stop-opacity="0.7"/>
                </linearGradient>
                <linearGradient id="fluid-grad-alert" x1="0" y1="0" x2="0" y2="1">
                    <stop offset="0%" stop-color="#39ff14" stop-opacity="0.9"/>
                    <stop offset="100%" stop-color="#16a34a" stop-opacity="0.7"/>
                </linearGradient>

                <!-- 管道剪裁蒙版 -->
                <clipPath id="seal-clip">
                    <rect x="0" y="650" width="1200" height="200" />
                </clipPath>
                
                <clipPath id="tank-clip">
                    <rect x="255" y="100" width="285" height="595" />
                </clipPath>
            </defs>

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

            <!-- ================= 静止背景层与标注 ================= -->
            <g id="annotations">
                <!-- 尺寸线:溢流堰高度范围 -->
                <path d="M 570 250 L 590 250 M 580 250 L 580 450 M 570 450 L 590 450" fill="none" stroke="#475569" stroke-width="1" stroke-dasharray="2,2"/>
                <text x="600" y="340" class="svg-text">调节范围</text>
                <text x="600" y="360" class="svg-text">200-300mm</text>

                <!-- 液封标注 -->
                <path d="M 620 780 L 550 780 L 500 750" fill="none" stroke="#475569" stroke-width="1"/>
                <circle cx="500" cy="750" r="3" fill="#475569"/>
                <text x="630" y="775" class="svg-text" fill="#94a3b8">核心组件: U型液封</text>
                <text x="630" y="795" class="svg-text" style="font-size: 10px;">阻断气流,允许超压流体自流通过</text>

                <!-- 重力自流标注 -->
                <g transform="translate(680, 520)">
                    <path d="M 0 0 L 0 50 M -5 40 L 0 50 L 5 40" fill="none" stroke="#39ff14" stroke-width="1.5" opacity="0.6"/>
                    <text x="15" y="25" class="svg-text" fill="#39ff14" opacity="0.8">IFR 特性: 重力自流 (≥40m³/h)</text>
                    <text x="15" y="40" class="svg-text" opacity="0.6">无需外部动力 / 零能耗自动响应</text>
                </g>

                <!-- 进出料标注 -->
                <text x="310" y="140" class="svg-text">主进料口</text>
                <path d="M 330 150 L 330 180 M 325 175 L 330 180 L 335 175" fill="none" stroke="#64748b" stroke-width="1.5"/>

                <text x="310" y="770" class="svg-text">正常排料口</text>
                <path d="M 330 710 L 330 740 M 325 735 L 330 740 L 335 735" fill="none" stroke="#64748b" stroke-width="1.5"/>
            </g>


            <!-- ================= 设备结构层 ================= -->
            <g id="structures" stroke="var(--struct-main)" stroke-width="10" stroke-linejoin="round" fill="none">
                <!-- 主进料箱与溢流收集室外壳 -->
                <!-- 左壁、底壁、底排料口 -->
                <path d="M 250 150 L 250 700 M 250 700 L 300 700 M 360 700 L 650 700 M 650 700 L 650 450" />
                <!-- 底部排料管道 -->
                <path d="M 300 700 L 300 780 M 360 700 L 360 780" />
                <!-- 进料管道 -->
                <path d="M 300 50 L 300 150 M 360 50 L 360 150" />
                
                <!-- 内部隔板(固定基座) -->
                <path d="M 540 700 L 540 450" />
                
                <!-- 旁通管道 DN150 (中心线向外扩展) 
                     从收集室(x=595, y=700) 向下,经过U型弯,向右排出
                -->
                <!-- 管道外壁 -->
                <path d="M 570 700 L 570 760 A 60 60 0 0 0 690 760 L 690 680 A 20 20 0 0 1 730 660 L 950 660" />
                <path d="M 620 700 L 620 760 A 10 10 0 0 0 640 760 L 640 680 A 70 70 0 0 1 780 610 L 950 610" />
            </g>

            <!-- ================= 动态液位层 ================= -->
            <!-- 1. 静态液封流体 (始终存在于U型弯中) -->
            <path d="M 595 700 L 595 760 A 35 35 0 0 0 665 760 L 665 680 A 45 45 0 0 1 755 635 L 950 635" 
                  fill="none" stroke="url(#fluid-grad-normal)" stroke-width="48" clip-path="url(#seal-clip)" filter="url(#glow-normal)"/>

            <!-- 2. 主进料箱液位 -->
            <rect id="main-tank-fluid" x="255" y="500" width="285" height="200" fill="url(#fluid-grad-normal)" filter="url(#glow-normal)" clip-path="url(#tank-clip)"/>
            
            <!-- 进料流动动画 (虚线模拟下落) -->
            <path d="M 330 50 L 330 650" fill="none" stroke="#00f0ff" stroke-width="40" stroke-dasharray="20 15" opacity="0.6">
                <animate attributeName="stroke-dashoffset" from="70" to="0" dur="0.8s" repeatCount="indefinite" />
            </path>
            <!-- 正常排料流动 -->
            <path d="M 330 700 L 330 800" fill="none" stroke="#00f0ff" stroke-width="40" stroke-dasharray="15 10" opacity="0.6">
                <animate attributeName="stroke-dashoffset" from="25" to="0" dur="0.8s" repeatCount="indefinite" />
            </path>

            <!-- ================= 核心:可调节溢流堰与溢流动画 ================= -->
            <!-- 溢流堰活动挡板 -->
            <rect id="weir-plate" x="536" y="250" width="8" height="200" fill="#f59e0b" stroke="#b45309" stroke-width="1" rx="2">
                <!-- 微小的高光效果 -->
                <rect x="537" y="251" width="2" height="198" fill="rgba(255,255,255,0.3)" />
            </rect>

            <!-- 3. 溢流流体 (绿色警示态,仅在超限时显示) -->
            <g id="overflow-group" opacity="0">
                <!-- 翻越堰口的流体 (动态生成的 path) -->
                <path id="spill-path" d="" fill="url(#fluid-grad-alert)" filter="url(#glow-alert)"/>
                
                <!-- 旁通管道中的高速泄压水流 -->
                <path d="M 595 700 L 595 760 A 35 35 0 0 0 665 760 L 665 680 A 45 45 0 0 1 755 635 L 950 635" 
                      fill="none" stroke="url(#fluid-grad-alert)" stroke-width="44" 
                      stroke-dasharray="60 30" stroke-linecap="round" filter="url(#glow-alert)">
                    <animate attributeName="stroke-dashoffset" from="90" to="0" dur="0.5s" repeatCount="indefinite" />
                </path>
                
                <!-- U型弯内液封被替换为绿色的视觉反馈 -->
                <path d="M 595 700 L 595 760 A 35 35 0 0 0 665 760 L 665 680 A 45 45 0 0 1 755 635 L 950 635" 
                      fill="none" stroke="url(#fluid-grad-alert)" stroke-width="48" clip-path="url(#seal-clip)" opacity="0.8"/>
            </g>

            <!-- 数据实时展示浮层 (跟随在液位旁边) -->
            <g transform="translate(265, 200)">
                <text x="0" y="0" class="svg-text">当前液位高度:</text>
                <text id="level-display" x="90" y="0" class="svg-value">0 mm</text>
                
                <text x="0" y="20" class="svg-text">系统进料波形:</text>
                <text id="inflow-display" x="90" y="20" class="svg-value">0.0 m³/h</text>
            </g>
        </svg>
    </div>

    <script>
        /**
         * 物理/逻辑仿真核心
         * 严格遵守自动播放规则,利用 requestAnimationFrame 实现连续的视觉反馈。
         * 无需任何手动触发即可观看完整的“涌浪 -> 溢流泄压 -> 恢复”循环。
         */
        
        document.addEventListener('DOMContentLoaded', () => {
            // DOM 元素引用
            const tankFluid = document.getElementById('main-tank-fluid');
            const weirPlate = document.getElementById('weir-plate');
            const overflowGroup = document.getElementById('overflow-group');
            const spillPath = document.getElementById('spill-path');
            const levelDisplay = document.getElementById('level-display');
            const inflowDisplay = document.getElementById('inflow-display');
            const bypassFlowDisplay = document.getElementById('bypass-flow-display');
            const weirSlider = document.getElementById('weir-slider');
            const weirValDisplay = document.getElementById('weir-val-display');
            const statusLed = document.getElementById('status-led');
            const statusText = document.getElementById('status-text');

            // 基础坐标常量
            const TANK_BOTTOM_Y = 700;
            const WEIR_MAX_Y = 450;  // 对应 slider 200mm (较低的堰)
            const WEIR_MIN_Y = 250;  // 对应 slider 300mm (较高的堰)
            
            // 系统状态变量
            let time = 0;
            let currentLevel = 0; // 液位抽象值 0-500
            
            // 映射函数:滑块值 (200-300) 到 堰板 Y 坐标 (450-250)
            function getWeirY(val) {
                // val: 200 -> Y: 450 (堰低,容易溢流)
                // val: 300 -> Y: 250 (堰高,难溢流)
                const ratio = (val - 200) / 100;
                return WEIR_MAX_Y - ratio * (WEIR_MAX_Y - WEIR_MIN_Y);
            }

            // 主循环
            function animate() {
                time += 0.012; // 时间步长控制进料波形频率

                // 1. 模拟不受控的进料涌浪 (正弦波叠加基础流量)
                // 确保进料量在正常排料能力上下波动,强制触发 IFR 溢流
                const baseInflow = 4.0;
                const surge = Math.sin(time) * 3.5 + Math.sin(time * 0.4) * 2.0; 
                let actualInflow = baseInflow + surge;
                if (actualInflow < 0.5) actualInflow = 0.5; // 保持最小进料

                const normalOutflow = 3.5; // 恒定底排能力

                // 2. 更新液位
                let deltaLevel = actualInflow - normalOutflow;
                currentLevel += deltaLevel * 0.8; // 0.8是系统惯性系数

                if (currentLevel < 0) currentLevel = 0;

                // 3. 溢流判定与计算 (核心无源控制逻辑)
                const sliderVal = parseFloat(weirSlider.value);
                const currentWeirY = getWeirY(sliderVal);
                
                // 计算当前液位对应的屏幕 Y 坐标
                // 满量程(500) 对应 y=150
                let fluidY = TANK_BOTTOM_Y - currentLevel; 
                
                let overflowRate = 0;
                let isOverflowing = false;

                // 如果液位高于堰口 (Y坐标小于堰口Y坐标)
                if (fluidY < currentWeirY) {
                    isOverflowing = true;
                    // 超出的水头高度
                    const head = currentWeirY - fluidY; 
                    // 基于水头的自流泄压能力 (非线性,模拟流体力学)
                    overflowRate = Math.pow(head, 1.2) * 0.15; 
                    
                    // 泄压导致液位下降
                    currentLevel -= overflowRate;
                    // 重新计算修正后的 fluidY
                    fluidY = TANK_BOTTOM_Y - currentLevel;
                }

                // 防护:绝对最大液位限制
                if (fluidY < 150) {
                    fluidY = 150;
                    currentLevel = TANK_BOTTOM_Y - 150;
                }

                // 4. 更新 SVG 渲染
                // 4.1 主液位
                tankFluid.setAttribute('y', fluidY);
                tankFluid.setAttribute('height', TANK_BOTTOM_Y - fluidY);

                // 4.2 溢流堰位置
                weirPlate.setAttribute('y', currentWeirY);
                weirPlate.setAttribute('height', TANK_BOTTOM_Y - currentWeirY);

                // 4.3 溢流动画表现
                if (isOverflowing && overflowRate > 0.1) {
                    // 平滑过渡不透明度
                    let targetOpacity = Math.min(overflowRate / 5, 0.95);
                    let currentOp = parseFloat(overflowGroup.getAttribute('opacity') || 0);
                    overflowGroup.setAttribute('opacity', currentOp + (targetOpacity - currentOp) * 0.1);
                    
                    // 动态绘制溢流抛物线
                    // 从堰口上方流出,落入收集室
                    const startX = 540;
                    const startY = fluidY;
                    const controlX = 570;
                    const controlY = fluidY - (overflowRate * 1.5); // 溢出量越大,抛物线越高
                    const endX = 595;
                    const endY = TANK_BOTTOM_Y;

                    // 生成平滑的填充形状 (模拟水幕)
                    const d = `M ${startX},${currentWeirY} 
                               L ${startX},${startY} 
                               Q ${controlX},${controlY} ${endX},${currentWeirY + 20} 
                               L ${endX},${endY} 
                               L 550,${endY} Z`;
                    spillPath.setAttribute('d', d);

                    // 更新状态UI
                    statusLed.classList.add('active');
                    statusText.textContent = "系统状态:超限!自动泄压中";
                    statusText.style.color = "var(--fluid-alert)";
                } else {
                    // 衰减不透明度
                    let currentOp = parseFloat(overflowGroup.getAttribute('opacity') || 0);
                    if (currentOp > 0.01) {
                        overflowGroup.setAttribute('opacity', currentOp * 0.9);
                    } else {
                        overflowGroup.setAttribute('opacity', 0);
                    }

                    statusLed.classList.remove('active');
                    statusText.textContent = "系统状态:正常运行中";
                    statusText.style.color = "var(--text-main)";
                }

                // 5. 更新数据面板
                // 将 Y 坐标差转换为抽象的 mm 物理量
                const displayMm = Math.max(0, Math.round((TANK_BOTTOM_Y - fluidY) * 0.66));
                levelDisplay.textContent = `${displayMm} mm`;
                
                // 如果出现溢流,显示红色警示颜色
                if(isOverflowing) {
                    levelDisplay.style.fill = "var(--fluid-alert)";
                } else {
                    levelDisplay.style.fill = "#e2e8f0";
                }

                inflowDisplay.textContent = `${actualInflow.toFixed(1)} m³/h`;
                
                // 转换 overflowRate 为显示的流量,保证 >= 40 容易达到
                let displayBypass = overflowRate * 8.5; 
                bypassFlowDisplay.textContent = displayBypass.toFixed(1);

                // 请求下一帧
                requestAnimationFrame(animate);
            }

            // 监听滑块变化更新 UI 数值
            weirSlider.addEventListener('input', (e) => {
                weirValDisplay.textContent = `${e.target.value} mm`;
            });

            // 启动自动播放循环
            animate();
        });
    </script>
</body>
</html>
积分规则:每轮对话扣10分