分享图
动画工坊
引擎就绪
<!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>
        :root {
            --bg-color: #0b0f19;
            --grid-color: rgba(30, 41, 59, 0.5);
            --text-main: #94a3b8;
            --text-accent: #38bdf8;
            --vessel-stroke: #475569;
            --vessel-fill: #1e293b;
            --liquid-color: #10b981; /* Emerald */
            --liquid-glow: rgba(16, 185, 129, 0.4);
            --gas-color: #fbbf24; /* Amber */
            --gas-glow: rgba(251, 191, 36, 0.6);
            --baffle-color: #64748b;
            --mesh-color: #334155;
            --font-mono: 'ui-monospace', 'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', 'Liberation Mono', 'Courier New', monospace;
        }

        body, html {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            background-color: var(--bg-color);
            display: flex;
            justify-content: center;
            align-items: center;
            font-family: var(--font-mono);
            overflow: hidden;
        }

        /* 核心动画容器 */
        .animation-container {
            position: relative;
            width: 100vw;
            height: 100vh;
            max-width: 1200px;
            max-height: 900px;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        /* SVG 样式 */
        svg {
            width: 90%;
            height: 90%;
            filter: drop-shadow(0 0 20px rgba(0,0,0,0.5));
        }

        /* 纯装饰性网格背景 */
        .bg-grid {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-image: 
                linear-gradient(to right, var(--grid-color) 1px, transparent 1px),
                linear-gradient(to bottom, var(--grid-color) 1px, transparent 1px);
            background-size: 40px 40px;
            z-index: -1;
            opacity: 0.3;
        }

        /* 信息面板 - 极简、边缘化、不遮挡 */
        .info-panel {
            position: absolute;
            bottom: 20px;
            right: 20px;
            background: rgba(15, 23, 42, 0.8);
            border: 1px solid #334155;
            padding: 12px 16px;
            border-radius: 4px;
            pointer-events: none;
            backdrop-filter: blur(4px);
        }

        .info-panel h1 {
            color: var(--text-accent);
            font-size: 14px;
            margin: 0 0 8px 0;
            text-transform: uppercase;
            letter-spacing: 1px;
        }

        .info-panel p {
            color: var(--text-main);
            font-size: 11px;
            margin: 4px 0;
            line-height: 1.4;
        }

        .legend {
            display: flex;
            gap: 12px;
            margin-top: 8px;
            border-top: 1px dashed #334155;
            padding-top: 8px;
        }

        .legend-item {
            display: flex;
            align-items: center;
            font-size: 10px;
            color: var(--text-main);
        }

        .legend-color {
            width: 8px;
            height: 8px;
            border-radius: 50%;
            margin-right: 6px;
        }

        /* 数据标签 - 悬浮在SVG上方 */
        .tech-label {
            font-size: 10px;
            fill: var(--text-main);
            user-select: none;
        }
        
        .tech-label.highlight {
            fill: var(--text-accent);
        }

        /* SVG 元素动画与样式 */
        .vessel-path {
            fill: var(--vessel-fill);
            stroke: var(--vessel-stroke);
            stroke-width: 3;
            stroke-linejoin: round;
        }

        .baffle {
            stroke: var(--baffle-color);
            stroke-width: 6;
            stroke-linecap: round;
        }

        .mesh-line {
            stroke: var(--mesh-color);
            stroke-width: 2;
            stroke-dasharray: 4 4;
        }

        /* 气阀排气动画 */
        .exhaust-line {
            stroke: var(--gas-color);
            stroke-width: 2;
            stroke-linecap: round;
            opacity: 0;
        }

        @keyframes exhaust {
            0% { transform: translateY(0); opacity: 0; }
            20% { opacity: 0.8; }
            100% { transform: translateY(-40px); opacity: 0; }
        }

        .exhaust-anim {
            animation: exhaust 1.5s infinite linear;
        }
        .exhaust-anim:nth-child(2) { animation-delay: 0.5s; }
        .exhaust-anim:nth-child(3) { animation-delay: 1.0s; }

        /* 浮球动画 (CSS 控制轻微浮动,JS控制主逻辑) */
        #float-ball {
            transition: transform 0.2s ease-out;
        }

    </style>
</head>
<body>

    <div class="bg-grid"></div>

    <div class="animation-container">
        <!-- SVG Canvas (ViewBox: 800x800) -->
        <svg viewBox="0 0 800 800" id="main-svg" preserveAspectRatio="xMidYMid meet">
            <defs>
                <!-- 滤镜: 发光效果 -->
                <filter id="glow-liquid" x="-20%" y="-20%" width="140%" height="140%">
                    <feGaussianBlur stdDeviation="3" result="blur" />
                    <feComposite in="SourceGraphic" in2="blur" operator="over" />
                </filter>
                <filter id="glow-gas" x="-50%" y="-50%" width="200%" height="200%">
                    <feGaussianBlur stdDeviation="4" result="blur" />
                    <feComposite in="SourceGraphic" in2="blur" operator="over" />
                </filter>

                <!-- 渐变: 金属感 -->
                <linearGradient id="metal-grad" x1="0%" y1="0%" x2="100%" y2="0%">
                    <stop offset="0%" stop-color="#1e293b" />
                    <stop offset="50%" stop-color="#334155" />
                    <stop offset="100%" stop-color="#1e293b" />
                </linearGradient>

                <!-- 渐变: 管道 -->
                <linearGradient id="pipe-grad" x1="0%" y1="0%" x2="0%" y2="100%">
                    <stop offset="0%" stop-color="#0f172a" />
                    <stop offset="50%" stop-color="#334155" />
                    <stop offset="100%" stop-color="#0f172a" />
                </linearGradient>

                <!-- 细目格栅图案 -->
                <pattern id="mesh-pattern" width="8" height="8" patternUnits="userSpaceOnUse">
                    <path d="M 8 0 L 0 8 M 0 0 L 8 8" fill="none" stroke="#475569" stroke-width="1" />
                </pattern>
            </defs>

            <!-- ================= 背景与壳体 ================= -->
            
            <!-- 缓冲罐主体 (下半部分) -->
            <path d="M 200,600 L 200,800 L 600,800 L 600,600 Z" class="vessel-path" fill="url(#metal-grad)" opacity="0.3" />
            <line x1="200" y1="600" x2="200" y2="800" stroke="#475569" stroke-width="3" />
            <line x1="600" y1="600" x2="600" y2="800" stroke="#475569" stroke-width="3" />
            
            <!-- 气液分离腔主体 -->
            <path d="M 200,150 
                     L 400,150 
                     L 400,50 
                     L 500,50 
                     L 500,150 
                     L 600,150 
                     L 600,600 
                     L 200,600 Z" 
                  class="vessel-path" fill="url(#metal-grad)" opacity="0.8" />

            <!-- 进料口管道 (左侧水平) -->
            <rect x="0" y="250" width="200" height="80" fill="url(#pipe-grad)" stroke="#475569" stroke-width="3" />
            <path d="M 200,250 L 200,330" stroke="#0f172a" stroke-width="5" /> <!-- 打通连接处 -->

            <!-- ================= 内部构件 ================= -->
            
            <!-- 细目除气格栅 (底部) -->
            <rect x="203" y="550" width="394" height="20" fill="url(#mesh-pattern)" />
            <line x1="200" y1="550" x2="600" y2="550" class="mesh-line" />
            <line x1="200" y1="570" x2="600" y2="570" class="mesh-line" />

            <!-- 折流挡板 (核心创新点) -->
            <!-- 挡板1: 从右侧墙壁向左下倾斜 -->
            <line x1="600" y1="280" x2="350" y2="380" class="baffle" />
            <!-- 挡板2: 从左侧墙壁向右下倾斜 -->
            <line x1="200" y1="400" x2="450" y2="500" class="baffle" />
            
            <!-- 标注: 折流挡板间距 -->
            <g opacity="0.6">
                <line x1="430" y1="360" x2="360" y2="440" stroke="var(--text-accent)" stroke-width="1" stroke-dasharray="2 2" />
                <circle cx="430" cy="360" r="2" fill="var(--text-accent)" />
                <circle cx="360" cy="440" r="2" fill="var(--text-accent)" />
                <text x="395" y="395" class="tech-label highlight" transform="rotate(-48 395 395)" text-anchor="middle" dominant-baseline="bottom">间距 100mm</text>
            </g>

            <!-- 浮球式自动排气阀 (顶部) -->
            <g id="vent-valve" transform="translate(450, 80)">
                <!-- 阀座 -->
                <path d="M -30,-30 L 30,-30 L 30,20 L -30,20 Z" fill="#334155" stroke="#475569" stroke-width="2" />
                <path d="M -10,-50 L 10,-50 L 10,-30 L -10,-30 Z" fill="#1e293b" stroke="#475569" stroke-width="2" />
                <!-- 浮球连杆机构 -->
                <line x1="0" y1="-30" x2="0" y2="40" stroke="#94a3b8" stroke-width="3" id="float-rod" />
                <!-- 浮球 -->
                <circle cx="0" cy="40" r="18" fill="#fbbf24" stroke="#d97706" stroke-width="2" id="float-ball" />
                <!-- 排气孔动画 -->
                <g id="exhaust-particles">
                    <line x1="-5" y1="-50" x2="-5" y2="-70" class="exhaust-line exhaust-anim" />
                    <line x1="0" y1="-50" x2="0" y2="-65" class="exhaust-line exhaust-anim" />
                    <line x1="5" y1="-50" x2="5" y2="-75" class="exhaust-line exhaust-anim" />
                </g>
                <!-- 标注: 排量 -->
                <text x="45" y="-10" class="tech-label">排气阀排量</text>
                <text x="45" y="5" class="tech-label highlight">50L/min</text>
            </g>

            <!-- ================= 粒子容器 ================= -->
            <!-- 将在 JS 中动态填充 -->
            <g id="liquid-layer"></g>
            <g id="gas-layer"></g>

            <!-- ================= 文字标注 ================= -->
            <text x="30" y="235" class="tech-label">含气浆料入口</text>
            <text x="30" y="248" class="tech-label" fill="#64748b">(高流速混合态)</text>
            
            <text x="620" y="320" class="tech-label">折流减速区</text>
            <text x="620" y="335" class="tech-label" fill="#64748b">流向急变促使气液分离</text>

            <text x="620" y="565" class="tech-label">细目除气格栅</text>
            <text x="620" y="580" class="tech-label" fill="#64748b">破碎微小气泡</text>

            <text x="220" y="700" class="tech-label">脱气钻井液</text>
            <text x="220" y="715" class="tech-label" fill="#64748b">平稳进入缓冲罐,无液位波动</text>

        </svg>
    </div>

    <!-- 悬浮信息面板 -->
    <div class="info-panel">
        <h1>系统状态: IFR 理想解运行中</h1>
        <p>机制: 利用挡板物理折流进行重力/惯性分离,<br>气上浮排空,液沉降入罐,彻底消除泵抽空隐患。</p>
        <div class="legend">
            <div class="legend-item">
                <div class="legend-color" style="background: var(--liquid-color); box-shadow: 0 0 5px var(--liquid-color);"></div>
                钻井液
            </div>
            <div class="legend-item">
                <div class="legend-color" style="background: var(--gas-color); box-shadow: 0 0 5px var(--gas-color);"></div>
                游离气
            </div>
        </div>
    </div>

    <script>
        /**
         * 粒子系统与物理仿真逻辑
         * 不依赖外部库,纯 Vanilla JS 实现高性能 SVG 动画
         */
        document.addEventListener('DOMContentLoaded', () => {
            const liquidLayer = document.getElementById('liquid-layer');
            const gasLayer = document.getElementById('gas-layer');
            const floatBall = document.getElementById('float-ball');
            const floatRod = document.getElementById('float-rod');
            
            // 物理常量与边界
            const BOUNDS = {
                inletX: 0, inletY_min: 260, inletY_max: 320,
                chamberLeft: 210, chamberRight: 590,
                meshY: 550,
                tankBottom: 800
            };
            
            // 对象池
            const particles = [];
            const LIQUID_COUNT = 150;
            const GAS_COUNT = 80;

            // 阀门状态模拟
            let gasAccumulation = 0;

            class Particle {
                constructor(type) {
                    this.type = type; // 'liquid' or 'gas'
                    this.element = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
                    this.reset();
                    
                    if (this.type === 'liquid') {
                        this.element.setAttribute('fill', 'var(--liquid-color)');
                        this.element.setAttribute('filter', 'url(#glow-liquid)');
                        liquidLayer.appendChild(this.element);
                    } else {
                        this.element.setAttribute('fill', 'var(--gas-color)');
                        this.element.setAttribute('filter', 'url(#glow-gas)');
                        gasLayer.appendChild(this.element);
                    }
                }

                reset() {
                    this.x = Math.random() * 50; // 从入口左侧产生
                    this.y = BOUNDS.inletY_min + Math.random() * (BOUNDS.inletY_max - BOUNDS.inletY_min);
                    this.vx = 3 + Math.random() * 2; // 初速度向右
                    this.vy = (Math.random() - 0.5) * 0.5;
                    
                    if (this.type === 'liquid') {
                        this.r = 3 + Math.random() * 3;
                        this.mass = 1.0;
                    } else {
                        this.r = 2 + Math.random() * 4;
                        this.mass = -0.8; // 负质量代表浮力
                    }
                    
                    this.element.setAttribute('r', this.r);
                    this.active = true;
                    this.state = 'inlet'; // inlet, chamber, tank, venting
                }

                update() {
                    if (!this.active) return;

                    // 1. 入口阶段
                    if (this.x < BOUNDS.chamberLeft && this.y > 250 && this.y < 330) {
                        this.vx = 4 + Math.random();
                        // 约束在管道内
                        if (this.y < BOUNDS.inletY_min + 5) this.vy += 0.5;
                        if (this.y > BOUNDS.inletY_max - 5) this.vy -= 0.5;
                    } 
                    // 2. 进入分离腔
                    else {
                        // 物理受力模型
                        if (this.type === 'liquid') {
                            this.vy += 0.15; // 重力
                            this.vx *= 0.98; // 阻力
                        } else {
                            this.vy -= 0.12; // 浮力 (气体上浮)
                            this.vx *= 0.95; // 阻力
                            
                            // 气体微小抖动
                            this.vx += (Math.random() - 0.5) * 0.5;
                        }

                        // --- 碰撞检测与折流挡板 ---
                        // 挡板1方程: y - 280 = -0.4 * (x - 600) => y = -0.4x + 240 + 280 = -0.4x + 520
                        // 挡板2方程: y - 400 = 0.4 * (x - 200) => y = 0.4x - 80 + 400 = 0.4x + 320
                        
                        // 简化碰撞:定义多边形排斥区域
                        
                        // 挡板1 (右上) 影响区
                        if (this.x > 350 && this.x < 600 && this.y > 280 && this.y < 420) {
                            let expectedY = -0.4 * (this.x - 600) + 280;
                            if (this.y > expectedY - 10 && this.y < expectedY + 20) {
                                // 发生碰撞
                                if (this.type === 'liquid') {
                                    this.vx = -2 - Math.random() * 2; // 向左下反弹
                                    this.vy = 2 + Math.random();
                                } else {
                                    // 气体在此处容易分离上浮
                                    this.vx = -1;
                                    this.vy = -3;
                                }
                            }
                        }

                        // 挡板2 (左下) 影响区
                        if (this.x > 200 && this.x < 450 && this.y > 400 && this.y < 520) {
                            let expectedY = 0.4 * (this.x - 200) + 400;
                            if (this.y > expectedY - 20 && this.y < expectedY + 10) {
                                if (this.type === 'liquid') {
                                    this.vx = 2 + Math.random() * 2; // 向右下反弹
                                    this.vy = 2 + Math.random();
                                } else {
                                    this.vx = 1;
                                    this.vy = -3;
                                }
                            }
                        }

                        // --- 边界约束 ---
                        // 侧壁
                        if (this.x < BOUNDS.chamberLeft && this.y > 330) {
                            this.x = BOUNDS.chamberLeft;
                            this.vx = Math.abs(this.vx) * 0.5;
                        }
                        if (this.x > BOUNDS.chamberRight) {
                            this.x = BOUNDS.chamberRight;
                            this.vx = -Math.abs(this.vx) * 0.5;
                        }

                        // 格栅区 (y=550)
                        if (this.y > BOUNDS.meshY - 10 && this.y < BOUNDS.meshY + 10) {
                            if (this.type === 'liquid') {
                                this.vy *= 0.8; // 减速通过格栅
                                this.vx *= 0.5;
                            } else {
                                // 气体极难通过格栅,强制上浮
                                this.vy = -2;
                            }
                        }

                        // 顶部气室与排气阀
                        if (this.y < 150) {
                            if (this.type === 'gas') {
                                // 引导向排气阀 (x=450)
                                if (this.x < 440) this.vx += 0.2;
                                if (this.x > 460) this.vx -= 0.2;
                                
                                if (this.y < 100 && this.x > 420 && this.x < 480) {
                                    // 被排气阀捕获
                                    gasAccumulation += 1;
                                    this.reset();
                                    return;
                                }
                                // 顶部盖子反弹
                                if (this.y < 60) {
                                    this.y = 60;
                                    this.vy = 0.5;
                                }
                            }
                        }
                    }

                    // 位置更新
                    this.x += this.vx;
                    this.y += this.vy;

                    // 越界重置
                    if (this.y > BOUNDS.tankBottom || this.x > 800 || this.x < -50 || this.y < -50) {
                        this.reset();
                    }

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

            // 初始化粒子
            for (let i = 0; i < LIQUID_COUNT; i++) {
                // 错开初始位置避免开局一坨
                let p = new Particle('liquid');
                p.x = Math.random() * 400;
                if(p.x > 100) p.y = 250 + Math.random()*200;
                particles.push(p);
            }
            for (let i = 0; i < GAS_COUNT; i++) {
                let p = new Particle('gas');
                p.x = Math.random() * 400;
                if(p.x > 100) p.y = 250 + Math.random()*200;
                particles.push(p);
            }

            // 动画主循环
            let lastTime = 0;
            function animate(timestamp) {
                // 控制帧率或平滑度 (可选)
                const deltaTime = timestamp - lastTime;
                lastTime = timestamp;

                // 更新粒子
                particles.forEach(p => p.update());

                // 模拟浮球阀门动态响应
                // 气体积累越多,浮球被“挤”得越往下,模拟排气开度
                if (gasAccumulation > 0) {
                    gasAccumulation -= 0.5; // 排气消耗
                }
                if (gasAccumulation < 0) gasAccumulation = 0;
                if (gasAccumulation > 20) gasAccumulation = 20;

                // 浮球位置: 默认40,随气体积累下沉 (模拟气体顶端聚集挤压液面)
                let floatTargetY = 40 + (gasAccumulation * 0.5);
                floatBall.setAttribute('cy', floatTargetY);
                floatRod.setAttribute('y2', floatTargetY);

                requestAnimationFrame(animate);
            }

            // 启动动画
            requestAnimationFrame(animate);
        });
    </script>
</body>
</html>
积分规则:每轮对话扣10分