独立渲染引擎就绪引擎就绪
<!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分
等待动画代码生成...
