独立渲染引擎就绪引擎就绪
<!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: #060b15;
--grid-color: rgba(43, 90, 165, 0.15);
--tank-edge: #1a3258;
--tank-fill: rgba(12, 25, 45, 0.8);
--fluid-base: #00d2ff;
--fluid-glow: #3a7bd5;
--text-main: #e2f1ff;
--text-dim: #749bc2;
--alert-color: #ff4757;
--success-color: #2ed573;
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "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: 'Helvetica Neue', Helvetica, Arial, sans-serif;
overflow: hidden;
}
#animation-container {
width: 100%;
max-width: 1200px;
aspect-ratio: 16 / 9;
position: relative;
box-shadow: 0 0 50px rgba(0, 0, 0, 0.5) inset;
}
svg {
width: 100%;
height: 100%;
display: block;
}
/* 绝对定位的说明文本区域,严格控制在边缘 */
.hud-panel {
position: absolute;
background: rgba(6, 11, 21, 0.75);
border: 1px solid var(--tank-edge);
backdrop-filter: blur(4px);
padding: 12px 16px;
border-radius: 6px;
pointer-events: none;
}
.hud-top-left { top: 20px; left: 20px; }
.hud-top-right { top: 20px; right: 20px; }
.hud-bottom-left { bottom: 20px; left: 20px; }
.hud-title {
color: var(--fluid-base);
font-size: 14px;
font-weight: bold;
letter-spacing: 1px;
margin-bottom: 6px;
text-transform: uppercase;
}
.hud-text {
color: var(--text-dim);
font-size: 12px;
line-height: 1.5;
margin: 0;
font-family: var(--font-mono);
}
.hud-value {
color: var(--text-main);
font-weight: bold;
}
.status-indicator {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 6px;
background: var(--text-dim);
box-shadow: 0 0 8px currentColor;
}
.status-filling { color: var(--text-dim); background: var(--text-dim); }
.status-priming { color: #ffa502; background: #ffa502; }
.status-siphoning { color: var(--fluid-base); background: var(--fluid-base); }
.status-broken { color: var(--alert-color); background: var(--alert-color); }
/* SVG 内部样式 */
.pipe-base {
fill: none;
stroke: #16243d;
stroke-width: 24;
stroke-linecap: round;
stroke-linejoin: round;
}
.pipe-inner {
fill: none;
stroke: #0a111f;
stroke-width: 16;
stroke-linecap: round;
stroke-linejoin: round;
}
.pipe-fluid {
fill: none;
stroke: var(--fluid-base);
stroke-width: 16;
stroke-linecap: round;
stroke-linejoin: round;
filter: drop-shadow(0 0 6px var(--fluid-glow));
transition: stroke-dashoffset 0.1s linear;
}
.pipe-flow-lines {
fill: none;
stroke: #ffffff;
stroke-width: 4;
stroke-linecap: round;
stroke-dasharray: 8 24;
opacity: 0;
}
@keyframes flowAnimation {
to { stroke-dashoffset: -32; }
}
.flowing .pipe-flow-lines {
opacity: 0.8;
animation: flowAnimation 0.5s linear infinite;
}
.tank-glass {
fill: var(--tank-fill);
stroke: var(--tank-edge);
stroke-width: 2;
}
.liquid {
fill: url(#liquidGrad);
opacity: 0.9;
}
.liquid-top {
fill: var(--fluid-base);
opacity: 0.6;
}
.dashed-line {
stroke: var(--text-dim);
stroke-width: 1;
stroke-dasharray: 4 4;
opacity: 0.5;
}
.measure-text {
fill: var(--text-dim);
font-size: 10px;
font-family: var(--font-mono);
letter-spacing: 0.5px;
}
</style>
</head>
<body>
<div id="animation-container">
<!-- 边缘数据面板 -->
<div class="hud-panel hud-top-left">
<div class="hud-title">系统运行状态</div>
<p class="hud-text">
<span id="ui-status-dot" class="status-indicator status-filling"></span>
<span id="ui-status-text">缓冲罐蓄液中...</span>
</p>
<p class="hud-text" style="margin-top: 4px;">当前排量: <span id="ui-flow-rate" class="hud-value">0.0</span> m³/h</p>
</div>
<div class="hud-panel hud-top-right">
<div class="hud-title">核心工程参数</div>
<p class="hud-text">管路规格: <span class="hud-value">DN80</span></p>
<p class="hud-text">额定排量: <span class="hud-value">25 m³/h</span></p>
<p class="hud-text">触发液位: <span class="hud-value">85%</span></p>
</div>
<div class="hud-panel hud-bottom-left">
<div class="hud-title">TRIZ 最终理想解 (IFR)</div>
<p class="hud-text" style="max-width: 280px; white-space: normal;">
利用重力势能与大气压资源,在无需增加持续动力源的极简构架下,实现超量液体的自动感应、触发排放与自动停止。
</p>
</div>
<!-- 核心动画 SVG -->
<svg viewBox="0 0 1000 562" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg">
<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="0.5"/>
<circle cx="0" cy="0" r="1" fill="var(--grid-color)" />
</pattern>
<!-- 液体渐变 -->
<linearGradient id="liquidGrad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#0052d4" />
<stop offset="50%" stop-color="#4364f7" />
<stop offset="100%" stop-color="#6fb1fc" />
</linearGradient>
<!-- 发光滤镜 -->
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="4" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
<filter id="intense-glow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="8" result="blur1" />
<feGaussianBlur stdDeviation="3" result="blur2" />
<feMerge>
<feMergeNode in="blur1"/>
<feMergeNode in="blur2"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<!-- 绘制背景 -->
<rect width="100%" height="100%" fill="url(#grid)" />
<!-- 标尺与辅助线 -->
<!-- 85% 触发线 -->
<line x1="180" y1="217" x2="380" y2="217" class="dashed-line" stroke="#ffa502" />
<text x="130" y="221" class="measure-text" fill="#ffa502">85% 触发液位</text>
<!-- 虹吸破坏线 -->
<line x1="180" y1="410" x2="380" y2="410" class="dashed-line" stroke="#ff4757" />
<text x="115" y="414" class="measure-text" fill="#ff4757">吸入口/破坏液位</text>
<!-- 高差指示 -->
<line x1="380" y1="460" x2="800" y2="460" class="dashed-line" />
<line x1="630" y1="360" x2="800" y2="360" class="dashed-line" />
<path d="M 780 360 L 780 460" fill="none" stroke="var(--text-dim)" stroke-width="1" />
<polygon points="777,365 783,365 780,360" fill="var(--text-dim)" />
<polygon points="777,455 783,455 780,460" fill="var(--text-dim)" />
<text x="790" y="415" class="measure-text">ΔH ≥ 1.5m</text>
<!-- 虹吸管路背面 (外壳) -->
<path id="main-pipe-bg" class="pipe-base" d="M 280 405 L 280 120 Q 280 80 320 80 L 680 80 Q 720 80 720 120 L 720 480" />
<path id="main-pipe-inner" class="pipe-inner" d="M 280 405 L 280 120 Q 280 80 320 80 L 680 80 Q 720 80 720 120 L 720 480" />
<!-- 管路内部流体 -->
<!-- 使用 dasharray 控制流体的填充和流动 -->
<path id="fluid-fill" class="pipe-fluid" d="M 280 405 L 280 120 Q 280 80 320 80 L 680 80 Q 720 80 720 120 L 720 480" />
<g id="flow-group">
<path id="fluid-flow-lines" class="pipe-flow-lines" d="M 280 405 L 280 120 Q 280 80 320 80 L 680 80 Q 720 80 720 120 L 720 480" />
</g>
<!-- 防涡流罩 (吸入口) -->
<path d="M 260 405 L 300 405 L 310 420 L 250 420 Z" fill="#2c3e50" stroke="#1a252f" stroke-width="2" />
<text x="280" y="435" class="measure-text" text-anchor="middle">防涡流罩</text>
<!-- 引水罐/阀门 -->
<rect x="475" y="55" width="50" height="25" rx="4" fill="#2c3e50" stroke="#1a252f" stroke-width="2" />
<circle id="valve-light" cx="500" cy="67.5" r="4" fill="#555" />
<text x="500" y="45" class="measure-text" text-anchor="middle">引水机构</text>
<!-- 缓冲罐 (左侧高位) -->
<g id="buffer-tank">
<!-- 罐体后壁 -->
<rect x="200" y="160" width="160" height="300" class="tank-glass" />
<!-- 液体 -->
<rect id="buffer-liquid" x="202" y="380" width="156" height="78" class="liquid" />
<!-- 液体顶面反光 -->
<rect id="buffer-liquid-top" x="202" y="380" width="156" height="4" class="liquid-top" />
<!-- 罐体前壁刻度 -->
<rect x="200" y="160" width="160" height="300" fill="none" stroke="var(--tank-edge)" stroke-width="2" />
<path d="M 200 217 L 210 217 M 200 292 L 210 292 M 200 367 L 210 292" stroke="var(--tank-edge)" stroke-width="2" />
<text x="280" y="480" class="measure-text" text-anchor="middle" fill="var(--text-main)">缓冲罐</text>
</g>
<!-- 循环罐 (右侧低位) -->
<g id="circ-tank">
<rect x="630" y="360" width="180" height="150" class="tank-glass" />
<rect id="circ-liquid" x="632" y="460" width="176" height="48" class="liquid" />
<rect id="circ-liquid-top" x="632" y="460" width="176" height="4" class="liquid-top" />
<rect x="630" y="360" width="180" height="150" fill="none" stroke="var(--tank-edge)" stroke-width="2" />
<text x="720" y="530" class="measure-text" text-anchor="middle" fill="var(--text-main)">循环罐</text>
</g>
<!-- 气泡动画组 (用于展示虹吸破坏瞬间) -->
<g id="bubbles" opacity="0">
<circle cx="280" cy="410" r="3" fill="#fff" />
<circle cx="275" cy="390" r="4" fill="#fff" />
<circle cx="285" cy="370" r="2.5" fill="#fff" />
<circle cx="278" cy="350" r="3.5" fill="#fff" />
<circle cx="282" cy="330" r="2" fill="#fff" />
</g>
</svg>
</div>
<script>
document.addEventListener("DOMContentLoaded", () => {
// DOM 元素获取
const bufferLiquid = document.getElementById('buffer-liquid');
const bufferLiquidTop = document.getElementById('buffer-liquid-top');
const circLiquid = document.getElementById('circ-liquid');
const circLiquidTop = document.getElementById('circ-liquid-top');
const pipeFluid = document.getElementById('fluid-fill');
const flowGroup = document.getElementById('flow-group');
const valveLight = document.getElementById('valve-light');
const bubbles = document.getElementById('bubbles');
const uiStatusDot = document.getElementById('ui-status-dot');
const uiStatusText = document.getElementById('ui-status-text');
const uiFlowRate = document.getElementById('ui-flow-rate');
// 测量管路长度以设置 dasharray
const pipeLength = pipeFluid.getTotalLength();
pipeFluid.style.strokeDasharray = pipeLength;
pipeFluid.style.strokeDashoffset = pipeLength; // 初始全空
// 物理与几何常量映射
const TANK_BASE_Y = 458; // 缓冲罐底部Y坐标 (内径)
const TANK_HEIGHT = 296; // 缓冲罐最大内高度
const LVL_85_Y = 217; // 85% 液位 Y坐标
const LVL_15_Y = 410; // 15% 液位 Y坐标 (吸入口)
const CIRC_BASE_Y = 508;
// 动画时间轴配置 (总周期 12秒)
const DURATION = 12000;
let startTime = null;
// 核心动画循环
function animate(timestamp) {
if (!startTime) startTime = timestamp;
// 确保动画在页面重新聚焦或重新加载时持续运行
let elapsed = timestamp - startTime;
let progress = (elapsed % DURATION) / DURATION;
// progress 在 0.0 ~ 1.0 之间循环
updateSystemState(progress);
requestAnimationFrame(animate);
}
// 根据时间轴进度更新物理状态与视觉呈现
function updateSystemState(p) {
let bY, bH, cY, cH;
let pipeOffset = pipeLength;
let flowRate = "0.0";
// 阶段 1: 缓冲罐蓄液 (0.0 - 0.35)
if (p < 0.35) {
let subP = p / 0.35; // 0 -> 1
// 缓冲罐液位从 15% 上升到 85%
bY = LVL_15_Y - (LVL_15_Y - LVL_85_Y) * subP;
// 循环罐缓慢排空 (模拟系统后处理)
cY = 420 + (CIRC_BASE_Y - 420) * (subP * 0.5);
pipeOffset = pipeLength; // 管路空
flowGroup.classList.remove('flowing');
valveLight.setAttribute('fill', '#555');
valveLight.removeAttribute('filter');
bubbles.setAttribute('opacity', '0');
updateUI('filling', '缓冲罐蓄液中...', '0.0');
}
// 阶段 2: 引水触发 (0.35 - 0.40)
else if (p < 0.40) {
let subP = (p - 0.35) / 0.05;
bY = LVL_85_Y; // 液位满
cY = 420 + (CIRC_BASE_Y - 420) * 0.5;
// 流体被吸上左侧管路至顶点
// 左侧上行管长度约 325
pipeOffset = pipeLength - (325 * subP);
valveLight.setAttribute('fill', '#ffa502');
valveLight.setAttribute('filter', 'url(#intense-glow)');
updateUI('priming', '引水阀开启,建立真空...', '0.0');
}
// 阶段 3: 虹吸持续排液 (0.40 - 0.85)
else if (p < 0.85) {
let subP = (p - 0.40) / 0.45;
// 缓冲罐液位从 85% 降至 15%
bY = LVL_85_Y + (LVL_15_Y - LVL_85_Y) * subP;
// 循环罐液位上升
cY = 460 - (460 - 410) * subP;
pipeOffset = 0; // 管路全满
flowGroup.classList.add('flowing');
valveLight.setAttribute('fill', '#555');
valveLight.removeAttribute('filter');
// 模拟流量波动
let randomFluctuation = (Math.random() * 0.4 - 0.2).toFixed(1);
flowRate = (25.0 + parseFloat(randomFluctuation)).toFixed(1);
updateUI('siphoning', '虹吸效应形成,持续排液', flowRate);
}
// 阶段 4: 虹吸破坏,管路排空 (0.85 - 0.90)
else if (p < 0.90) {
let subP = (p - 0.85) / 0.05;
bY = LVL_15_Y;
cY = 410;
flowGroup.classList.remove('flowing');
// 模拟流体从顶点向两侧落下/排空
// 通过改变 stroke-dashoffset 和 dasharray 实现断开效果比较复杂
// 这里用简化的视觉处理:迅速增加 offset 模拟抽空
pipeOffset = pipeLength * subP;
// 显示气泡进入吸入口
bubbles.setAttribute('opacity', '1');
bubbles.setAttribute('transform', `translate(0, ${-20 * subP})`);
updateUI('broken', '液位低于吸口,虹吸破坏', '0.0');
}
// 阶段 5: 归位静置 (0.90 - 1.0)
else {
bY = LVL_15_Y;
cY = 410 + (CIRC_BASE_Y - 420) * ((p - 0.9) / 0.1 * 0.5); // 准备连接下一周期的液位
pipeOffset = pipeLength;
bubbles.setAttribute('opacity', '0');
updateUI('filling', '系统复位,准备下一周期', '0.0');
}
// 应用计算出的几何属性
bH = TANK_BASE_Y - bY;
bufferLiquid.setAttribute('y', bY);
bufferLiquid.setAttribute('height', bH);
bufferLiquidTop.setAttribute('y', bY);
cH = CIRC_BASE_Y - cY;
circLiquid.setAttribute('y', cY);
circLiquid.setAttribute('height', cH);
circLiquidTop.setAttribute('y', cY);
pipeFluid.style.strokeDashoffset = pipeOffset;
}
// 更新 UI 状态面板
let currentStatusCls = '';
function updateUI(statusKey, text, flow) {
const cls = `status-${statusKey}`;
if (currentStatusCls !== cls) {
uiStatusDot.className = `status-indicator ${cls}`;
uiStatusText.textContent = text;
currentStatusCls = cls;
}
uiFlowRate.textContent = flow;
}
// 启动动画
requestAnimationFrame(animate);
});
</script>
</body>
</html>
积分规则:每轮对话扣10分
等待动画代码生成...
