分享图
动画工坊
引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>蜂窝整流器流体动力学原理</title>
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Jura:wght@400;600;700&display=swap');

        :root {
            --bg-color: #070a10;
            --grid-color: rgba(41, 61, 90, 0.15);
            --machine-fill: #121822;
            --machine-stroke: #2a3f5a;
            --highlight: #00ffcc;
            --fluid-chaos: #0077ff;
            --fluid-laminar: #00ffcc;
            --text-main: #8ba3c0;
            --text-accent: #ffffff;
        }

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

        body {
            background-color: var(--bg-color);
            color: var(--text-main);
            font-family: 'Jura', sans-serif;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            overflow: hidden;
            background-image: 
                linear-gradient(var(--grid-color) 1px, transparent 1px),
                linear-gradient(90deg, var(--grid-color) 1px, transparent 1px);
            background-size: 30px 30px;
            background-position: center center;
        }

        #canvas-container {
            position: relative;
            width: 90vw;
            height: 90vh;
            max-width: 1400px;
            max-height: 900px;
            box-shadow: 0 0 100px rgba(0, 255, 204, 0.05) inset, 
                        0 0 0 1px rgba(42, 63, 90, 0.5);
            background: radial-gradient(circle at center, #0a101a 0%, #05070a 100%);
            border-radius: 4px;
        }

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

        /* Overlay Text Styling - Kept strictly to the edges, small size */
        .annotation {
            position: absolute;
            font-size: 12px;
            letter-spacing: 1px;
            line-height: 1.4;
            pointer-events: none;
        }

        .anno-title {
            color: var(--highlight);
            font-weight: 700;
            font-size: 14px;
            margin-bottom: 4px;
            text-transform: uppercase;
        }

        .anno-top-left { top: 30px; left: 30px; }
        .anno-middle-right { top: 50%; right: 30px; transform: translateY(-50%); text-align: right; }
        .anno-bottom-left { bottom: 30px; left: 30px; }

        .stat-box {
            display: inline-block;
            border: 1px solid rgba(0, 255, 204, 0.3);
            background: rgba(0, 255, 204, 0.05);
            padding: 4px 8px;
            margin-top: 5px;
            border-radius: 2px;
            font-family: monospace;
            color: var(--text-accent);
        }

        /* Animations */
        @keyframes vibrate {
            0% { transform: translate(0, 0) rotate(-15deg); }
            25% { transform: translate(-1px, 1px) rotate(-15deg); }
            50% { transform: translate(1px, -1px) rotate(-15deg); }
            75% { transform: translate(-1px, -1px) rotate(-15deg); }
            100% { transform: translate(0, 0) rotate(-15deg); }
        }

        .vibrating-screen {
            transform-origin: center;
            animation: vibrate 0.1s infinite linear;
        }

        @keyframes flowPulse {
            0% { opacity: 0.6; }
            50% { opacity: 1; }
            100% { opacity: 0.6; }
        }

        .glow-effect {
            animation: flowPulse 3s infinite ease-in-out;
        }
    </style>
</head>
<body>

    <div id="canvas-container">
        <!-- UI Overlays (Strictly constrained to corners/edges) -->
        <div class="annotation anno-top-left">
            <div class="anno-title">01 / 高能扰动区</div>
            钻井液夹带高动能进入进料箱<br>
            呈现高雷诺数无序湍流状态
        </div>

        <div class="annotation anno-middle-right">
            <div class="anno-title">02 / IFR 整流核心</div>
            <span style="color: #fff">蜂窝管束结构</span><br>
            流体被迫细分,横向动能被管壁吸收<br>
            实现从湍流向层流的强制转换<br>
            <div class="stat-box">D=20mm | L=200mm</div>
        </div>

        <div class="annotation anno-bottom-left">
            <div class="anno-title">03 / 理想均布液幕</div>
            动能消散,均压流出<br>
            零冲击落在振动筛面<br>
            最大化筛网寿命与分离效率
        </div>

        <!-- Main SVG Animation -->
        <svg viewBox="0 0 1200 800" preserveAspectRatio="xMidYMid meet">
            <defs>
                <!-- Glow Filters -->
                <filter id="glow-cyan" x="-20%" y="-20%" width="140%" height="140%">
                    <feGaussianBlur stdDeviation="8" result="blur" />
                    <feComposite in="SourceGraphic" in2="blur" operator="over" />
                </filter>
                <filter id="glow-blue" x="-20%" y="-20%" width="140%" height="140%">
                    <feGaussianBlur stdDeviation="12" result="blur" />
                    <feComposite in="SourceGraphic" in2="blur" operator="over" />
                </filter>

                <!-- Gradients -->
                <linearGradient id="fluid-gradient" x1="0%" y1="0%" x2="0%" y2="100%">
                    <stop offset="0%" stop-color="var(--fluid-chaos)" stop-opacity="0.8"/>
                    <stop offset="40%" stop-color="var(--fluid-chaos)" stop-opacity="0.9"/>
                    <stop offset="60%" stop-color="var(--fluid-laminar)" stop-opacity="0.9"/>
                    <stop offset="100%" stop-color="var(--fluid-laminar)" stop-opacity="0.4"/>
                </linearGradient>

                <linearGradient id="metal-grad" x1="0%" y1="0%" x2="100%" y2="0%">
                    <stop offset="0%" stop-color="#1a2535"/>
                    <stop offset="50%" stop-color="#2a3f5a"/>
                    <stop offset="100%" stop-color="#1a2535"/>
                </linearGradient>

                <!-- Patterns -->
                <pattern id="honeycomb-pattern" width="16" height="30" patternUnits="userSpaceOnUse">
                    <path d="M 8 0 L 16 15 L 8 30 L 0 15 Z" fill="none" stroke="#2a3f5a" stroke-width="1.5" opacity="0.3"/>
                </pattern>
                
                <!-- Screen Mesh Pattern -->
                <pattern id="mesh-pattern" width="6" height="6" patternUnits="userSpaceOnUse" patternTransform="rotate(15)">
                    <rect width="6" height="6" fill="none" stroke="#4a5f7a" stroke-width="0.5"/>
                </pattern>

                <clipPath id="rectifier-clip">
                    <rect x="400" y="300" width="400" height="150" />
                </clipPath>
            </defs>

            <!-- ================= BACKGROUND TECHNICAL ELEMENTS ================= -->
            <!-- Blueprint structural lines -->
            <path d="M 600 0 L 600 800 M 0 400 L 1200 400" stroke="rgba(42, 63, 90, 0.3)" stroke-width="1" stroke-dasharray="10 10"/>
            <circle cx="600" cy="400" r="300" fill="none" stroke="rgba(42, 63, 90, 0.1)" stroke-width="1"/>
            
            <!-- Dimension Lines & Leader Lines for Annotations -->
            <g stroke="var(--text-main)" stroke-width="1" opacity="0.5">
                <!-- Top Left Leader -->
                <polyline points="200,60 380,60 450,150" fill="none" />
                <circle cx="450" cy="150" r="3" fill="var(--text-main)" />
                
                <!-- Middle Right Leader -->
                <polyline points="1000,400 850,400 800,375" fill="none" />
                <circle cx="800" cy="375" r="3" fill="var(--highlight)" />

                <!-- Bottom Left Leader -->
                <polyline points="200,740 380,740 500,650" fill="none" />
                <circle cx="500" cy="650" r="3" fill="var(--text-main)" />
                
                <!-- Rectifier Dimensions (L=200) visual cue -->
                <line x1="820" y1="300" x2="820" y2="450" stroke="var(--highlight)" stroke-dasharray="4 4"/>
                <line x1="810" y1="300" x2="830" y2="300" stroke="var(--highlight)"/>
                <line x1="810" y1="450" x2="830" y2="450" stroke="var(--highlight)"/>
            </g>

            <!-- ================= STATIC MACHINERY ================= -->
            
            <!-- Feed Box Housing Top -->
            <path d="M 450 0 L 450 150 L 350 250 L 350 300 L 850 300 L 850 250 L 750 150 L 750 0" 
                  fill="none" stroke="var(--machine-stroke)" stroke-width="3" />
            
            <!-- Fluid background mass (the chaotic volume) -->
            <path d="M 452 0 L 452 150 L 352 250 L 352 300 L 848 300 L 848 250 L 748 150 L 748 0 Z" 
                  fill="rgba(0, 119, 255, 0.1)"/>

            <!-- The Honeycomb Rectifier Component (IFR Core) -->
            <g transform="translate(400, 300)">
                <!-- Casing -->
                <rect x="0" y="0" width="400" height="150" fill="url(#metal-grad)" stroke="var(--machine-stroke)" stroke-width="4"/>
                <!-- Honeycomb front texture -->
                <rect x="2" y="2" width="396" height="146" fill="url(#honeycomb-pattern)"/>
                
                <!-- Grid division lines (representing tubes) -->
                <g stroke="#1a2535" stroke-width="2">
                    <line x1="40" y1="0" x2="40" y2="150"/>
                    <line x1="80" y1="0" x2="80" y2="150"/>
                    <line x1="120" y1="0" x2="120" y2="150"/>
                    <line x1="160" y1="0" x2="160" y2="150"/>
                    <line x1="200" y1="0" x2="200" y2="150"/>
                    <line x1="240" y1="0" x2="240" y2="150"/>
                    <line x1="280" y1="0" x2="280" y2="150"/>
                    <line x1="320" y1="0" x2="320" y2="150"/>
                    <line x1="360" y1="0" x2="360" y2="150"/>
                </g>
                <!-- Glow indication at exit -->
                <rect x="0" y="145" width="400" height="5" fill="var(--highlight)" filter="url(#glow-cyan)" opacity="0.7"/>
            </g>

            <!-- Lower Housing -->
            <path d="M 400 450 L 400 500 L 350 550" fill="none" stroke="var(--machine-stroke)" stroke-width="3" />
            <path d="M 800 450 L 800 500 L 850 550" fill="none" stroke="var(--machine-stroke)" stroke-width="3" />

            <!-- Vibrating Screen -->
            <!-- Wrapped in a group for CSS vibration animation -->
            <g class="vibrating-screen" transform="translate(600, 650) rotate(-15) translate(-600, -650)">
                <!-- Support frame -->
                <rect x="300" y="630" width="600" height="40" rx="4" fill="var(--machine-fill)" stroke="var(--machine-stroke)" stroke-width="3"/>
                <!-- Screen Mesh -->
                <rect x="310" y="625" width="580" height="10" fill="url(#mesh-pattern)" stroke="var(--highlight)" stroke-width="1"/>
                <!-- Structural ribs -->
                <path d="M 400 630 L 400 670 M 500 630 L 500 670 M 600 630 L 600 670 M 700 630 L 700 670 M 800 630 L 800 670" stroke="var(--machine-stroke)" stroke-width="4"/>
            </g>


            <!-- ================= DYNAMIC FLUID SYSTEM ================= -->
            <!-- Base background curtain for the lower part -->
            <path d="M 400 450 L 800 450 L 800 600 Q 600 650 400 550 Z" 
                  fill="url(#fluid-gradient)" class="glow-effect" opacity="0.3"/>

            <!-- Canvas for JS Particle System -->
            <g id="particle-system"></g>

            <!-- Foreground technical overlays (to hide particles clipping out) -->
            <rect x="390" y="290" width="420" height="10" fill="var(--bg-color)" />
            <path d="M 390 300 L 810 300" stroke="var(--machine-stroke)" stroke-width="4"/>
        </svg>
    </div>

    <script>
        /**
         * Fluid Dynamics Particle System
         * Illustrates the TRIZ IFR: Chaotic kinetic energy -> Orderly laminar flow
         */
        const svgNS = "http://www.w3.org/2000/svg";
        const particleContainer = document.getElementById('particle-system');
        
        // System Parameters
        const NUM_PARTICLES = 400;
        const TUBE_WIDTH = 40;
        const TUBES_START_X = 400;
        const TUBES_START_Y = 300;
        const TUBES_END_Y = 450;
        const SCREEN_Y_BASE = 650;
        
        let particles = [];

        // Particle Class
        class Particle {
            constructor() {
                this.element = document.createElementNS(svgNS, 'circle');
                particleContainer.appendChild(this.element);
                this.reset();
                // Randomize start delay
                this.y = Math.random() * -400; 
            }

            reset() {
                // Start at top
                this.x = 450 + Math.random() * 300;
                this.y = -20;
                this.size = Math.random() * 2.5 + 1.5;
                this.element.setAttribute('r', this.size);
                
                // Turbulent Phase Variables
                this.baseVx = (Math.random() - 0.5) * 8;
                this.vy = Math.random() * 3 + 2;
                this.phase = Math.random() * Math.PI * 2;
                this.state = 'turbulent'; // 'turbulent', 'rectifying', 'laminar', 'screen'
                this.targetTubeX = null;
                
                this.updateStyle();
            }

            updateStyle() {
                if (this.state === 'turbulent') {
                    this.element.setAttribute('fill', 'var(--fluid-chaos)');
                    this.element.style.filter = 'url(#glow-blue)';
                    this.element.setAttribute('opacity', Math.random() * 0.5 + 0.3);
                } else if (this.state === 'rectifying') {
                    this.element.setAttribute('fill', 'var(--highlight)');
                    this.element.style.filter = 'url(#glow-cyan)';
                    this.element.setAttribute('opacity', 0.8);
                } else if (this.state === 'laminar') {
                    this.element.setAttribute('fill', 'var(--fluid-laminar)');
                    this.element.style.filter = 'url(#glow-cyan)';
                    this.element.setAttribute('opacity', 0.9);
                }
            }

            update() {
                // State Machine based on Y position
                
                if (this.y < TUBES_START_Y) {
                    // 1. Turbulent Zone (Inlet)
                    if (this.state !== 'turbulent') {
                        this.state = 'turbulent';
                        this.updateStyle();
                    }
                    
                    // Add chaotic movement via sine waves
                    this.phase += 0.1;
                    const chaos = Math.sin(this.phase) * 4;
                    this.x += this.baseVx + chaos;
                    
                    // Shape constraint (funneling into box)
                    if (this.y > 150) {
                        const progress = (this.y - 150) / 150;
                        const leftBound = 450 - (100 * progress);
                        const rightBound = 750 + (100 * progress);
                        
                        if (this.x < leftBound) { this.x = leftBound; this.baseVx = Math.abs(this.baseVx); }
                        if (this.x > rightBound) { this.x = rightBound; this.baseVx = -Math.abs(this.baseVx); }
                    } else {
                        if (this.x < 450) { this.x = 450; this.baseVx *= -1; }
                        if (this.x > 750) { this.x = 750; this.baseVx *= -1; }
                    }
                    
                    this.vy += 0.05; // Gravity acceleration

                } else if (this.y >= TUBES_START_Y && this.y < TUBES_END_Y) {
                    // 2. Rectifying Zone (Inside Honeycomb)
                    if (this.state !== 'rectifying') {
                        this.state = 'rectifying';
                        this.updateStyle();
                        
                        // Assign to a specific tube channel
                        const relativeX = this.x - TUBES_START_X;
                        const tubeIndex = Math.floor(relativeX / TUBE_WIDTH);
                        // Center particle in its respective tube
                        this.targetTubeX = TUBES_START_X + (tubeIndex * TUBE_WIDTH) + (TUBE_WIDTH / 2);
                        
                        // Kill horizontal velocity, standardize vertical velocity (low Reynolds number simulation)
                        this.baseVx = 0;
                        this.vy = 4; // Constant, controlled speed
                    }
                    
                    // Smoothly snap to center of tube
                    if (this.targetTubeX !== null) {
                        this.x += (this.targetTubeX - this.x) * 0.2;
                    }

                } else if (this.y >= TUBES_END_Y && this.state !== 'screen') {
                    // 3. Laminar Curtain Zone (Falling)
                    if (this.state !== 'laminar') {
                        this.state = 'laminar';
                        this.updateStyle();
                        // Slight spread after exiting
                        this.baseVx = (Math.random() - 0.5) * 0.5;
                    }
                    
                    this.x += this.baseVx;
                    this.vy += 0.1; // Gravity resumes, but uniformly
                    
                    // Check collision with angled screen (Angle is approx 15 deg)
                    // Line equation for screen: y - 650 = tan(-15deg) * (x - 600)
                    // y = -0.267 * (x - 600) + 650
                    const screenCollisionY = -0.267 * (this.x - 600) + 650;
                    
                    if (this.y >= screenCollisionY) {
                        this.state = 'screen';
                        this.y = screenCollisionY;
                        // Calculate vector along the screen
                        const speed = Math.sqrt(this.baseVx*this.baseVx + this.vy*this.vy) * 0.6; // lose energy on impact
                        this.vx = Math.cos(-15 * Math.PI / 180) * speed;
                        this.vy = Math.sin(-15 * Math.PI / 180) * speed;
                    }

                } else if (this.state === 'screen') {
                    // 4. Flowing down the screen
                    this.x -= 5; // Move left along the angled screen
                    this.y += 5 * 0.267; // Follow the angle

                    this.element.setAttribute('opacity', Math.max(0, this.element.getAttribute('opacity') - 0.02));
                    
                    // Reset if off screen
                    if (this.x < 250 || this.element.getAttribute('opacity') <= 0) {
                        this.reset();
                        return; // skip coordinate update this frame
                    }
                }

                this.y += this.vy;
                
                // Final bounds check
                if (this.y > 850) {
                    this.reset();
                }

                // Render
                this.element.setAttribute('cx', this.x);
                this.element.setAttribute('cy', this.y);
            }
        }

        // Initialize particles
        for (let i = 0; i < NUM_PARTICLES; i++) {
            particles.push(new Particle());
        }

        // Animation Loop
        function animate() {
            for (let i = 0; i < particles.length; i++) {
                particles[i].update();
            }
            requestAnimationFrame(animate);
        }

        // Start animation immediately on load
        window.addEventListener('DOMContentLoaded', () => {
            animate();
        });

    </script>
</body>
</html>
积分规则:每轮对话扣10分