独立渲染引擎就绪引擎就绪
<!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>
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;500;700&display=swap');
:root {
--bg-color: #0B0E14;
--grid-color: rgba(255, 255, 255, 0.03);
--fluid-color: #00D8FF;
--fluid-glow: rgba(0, 216, 255, 0.4);
--metal-light: #E2E8F0;
--metal-dark: #64748B;
--accent-color: #FF5500;
--text-color: #8B9BB4;
}
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
background-color: var(--bg-color);
font-family: 'JetBrains Mono', monospace;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
}
/* Blueprint Grid Background */
.bg-grid {
position: absolute;
top: 0; left: 0; width: 100%; height: 100%;
background-image:
linear-gradient(var(--grid-color) 1px, transparent 1px),
linear-gradient(90deg, var(--grid-color) 1px, transparent 1px);
background-size: 40px 40px;
z-index: 0;
}
.bg-grid::after {
content: '';
position: absolute;
top: 0; left: 0; width: 100%; height: 100%;
background: radial-gradient(circle at center, transparent 30%, var(--bg-color) 100%);
}
/* SVG Container */
.svg-container {
position: relative;
width: 100%;
max-width: 1200px;
height: 100vh;
z-index: 10;
}
svg {
width: 100%;
height: 100%;
display: block;
}
/* Typography & Overlays - Strictly minimized and pushed to edges */
.overlay {
position: absolute;
z-index: 20;
pointer-events: none;
color: var(--text-color);
font-size: 12px;
letter-spacing: 1px;
line-height: 1.6;
}
.overlay-top-left { top: 32px; left: 40px; }
.overlay-bottom-left { bottom: 32px; left: 40px; }
.overlay-bottom-right { bottom: 32px; right: 40px; text-align: right; }
.title {
color: var(--metal-light);
font-size: 16px;
font-weight: 700;
margin-bottom: 8px;
text-transform: uppercase;
display: flex;
align-items: center;
gap: 8px;
}
.title::before {
content: '';
display: inline-block;
width: 8px;
height: 8px;
background-color: var(--accent-color);
box-shadow: 0 0 8px var(--accent-color);
}
.data-row {
display: flex;
justify-content: space-between;
width: 220px;
border-bottom: 1px solid rgba(139, 155, 180, 0.1);
padding: 4px 0;
}
.data-value {
color: var(--fluid-color);
font-weight: 500;
}
.accent-text { color: var(--accent-color); }
/* Flow Animation CSS */
.flow-dash {
stroke-dasharray: 10 10;
animation: flow 0.5s linear infinite;
}
@keyframes flow {
to { stroke-dashoffset: -20; }
}
.glow { filter: drop-shadow(0 0 12px var(--fluid-glow)); }
.metal-glow { filter: drop-shadow(0 4px 6px rgba(0,0,0,0.5)); }
</style>
</head>
<body>
<div class="bg-grid"></div>
<!-- Data Overlays -->
<div class="overlay overlay-top-left">
<div class="title">IFR: 最终理想解</div>
<div style="margin-bottom: 16px; color: #5a6b85;">完全利用系统内部资源(重力、浮力)<br>实现负反馈调控,消除外部能源依赖。</div>
<div class="data-row"><span>当前液位高度</span><span class="data-value" id="ui-level">0 mm</span></div>
<div class="data-row"><span>浮球升降行程</span><span class="data-value" id="ui-stroke">0 mm</span></div>
<div class="data-row"><span>作用力臂比</span><span class="data-value accent-text">1:3</span></div>
<div class="data-row"><span>蝶阀开度状态</span><span class="data-value" id="ui-valve">0.0°</span></div>
<div class="data-row"><span>系统能耗</span><span class="data-value" style="color: #00FF66;">0.00 kW</span></div>
</div>
<div class="overlay overlay-bottom-left">
<span class="accent-text">SYS.STAT //</span> 纯机械自适应稳态运行中
</div>
<div class="overlay overlay-bottom-right">
核心机理: 负反馈杠杆机构<br>
适用边界: 缓冲罐液位缓变场景
</div>
<!-- Main SVG Animation -->
<div class="svg-container">
<svg viewBox="0 0 1000 600" preserveAspectRatio="xMidYMid meet">
<defs>
<linearGradient id="metalGrad" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#E2E8F0" />
<stop offset="50%" stop-color="#94A3B8" />
<stop offset="100%" stop-color="#475569" />
</linearGradient>
<linearGradient id="fluidGrad" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="rgba(0, 216, 255, 0.8)" />
<stop offset="100%" stop-color="rgba(0, 85, 119, 0.9)" />
</linearGradient>
<linearGradient id="darkMetal" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#475569" />
<stop offset="100%" stop-color="#1E293B" />
</linearGradient>
<filter id="neonGlow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="4" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
</defs>
<!-- 1. Background Structure (Tank & Pipes) -->
<g id="tank-structure">
<!-- Inflow pipe -->
<path d="M 220 0 L 220 80" fill="none" stroke="var(--metal-dark)" stroke-width="16" />
<path d="M 220 0 L 220 80" fill="none" stroke="var(--bg-color)" stroke-width="12" />
<path d="M 220 0 L 220 100" fill="none" stroke="var(--fluid-color)" stroke-width="6" class="flow-dash glow" opacity="0.5" />
<!-- Main Tank -->
<rect x="150" y="100" width="200" height="350" fill="rgba(30, 41, 59, 0.4)" stroke="var(--metal-dark)" stroke-width="4" rx="8" />
<!-- Outflow Pipe -->
<path d="M 350 410 L 800 410" fill="none" stroke="var(--metal-dark)" stroke-width="32" stroke-linecap="round"/>
<path d="M 350 410 L 800 410" fill="none" stroke="var(--bg-color)" stroke-width="26" stroke-linecap="round"/>
</g>
<!-- 2. Dynamic Fluid -->
<g id="fluid-group">
<!-- Tank Fluid -->
<rect id="tank-fluid" x="152" y="300" width="196" height="148" fill="url(#fluidGrad)" class="glow" rx="6" />
<line id="fluid-surface" x1="152" y1="300" x2="348" y2="300" stroke="#FFFFFF" stroke-width="2" opacity="0.5" />
<!-- Outflow Fluid (Masked to pipe) -->
<clipPath id="pipe-clip">
<rect x="350" y="396" width="450" height="28" />
</clipPath>
<g clip-path="url(#pipe-clip)">
<rect id="outflow-fluid" x="350" y="396" width="450" height="28" fill="var(--fluid-color)" opacity="0" class="glow" />
<line id="outflow-dash" x1="350" y1="410" x2="800" y2="410" stroke="#FFFFFF" stroke-width="4" opacity="0" class="flow-dash" />
</g>
</g>
<!-- 3. Mechanical System (IFR Core) -->
<g id="mechanism" class="metal-glow">
<!-- Support Bracket -->
<path d="M 540 100 L 560 100 L 560 220 L 540 220 Z" fill="url(#darkMetal)" />
<circle cx="550" cy="200" r="12" fill="url(#metalGrad)" />
<circle cx="550" cy="200" r="4" fill="var(--bg-color)" />
<!-- Float Ball -->
<g id="float-assembly">
<rect x="245" y="0" width="10" height="100" fill="url(#metalGrad)" id="float-rod" />
<!-- Stainless Steel Float -->
<ellipse cx="250" cy="0" rx="40" ry="30" fill="url(#metalGrad)" id="float-ball" />
<ellipse cx="250" cy="-15" rx="20" ry="8" fill="#FFFFFF" opacity="0.3" id="float-highlight" />
</g>
<!-- Main Lever (Force Arm & Resistance Arm 3:1) -->
<!-- Pivot is at 550, 200. Float attaches at 250 (Distance 300). Linkage at 650 (Distance 100). -->
<g id="main-lever">
<!-- The rod -->
<line x1="250" y1="200" x2="650" y2="200" stroke="url(#metalGrad)" stroke-width="14" stroke-linecap="round" id="lever-arm" />
<!-- Pivot Joint -->
<circle cx="550" cy="200" r="8" fill="var(--accent-color)" filter="url(#neonGlow)" />
<!-- Force Vector Indications -->
<text x="400" y="185" fill="var(--accent-color)" font-size="12" text-anchor="middle" opacity="0.8">L1 = 3x (浮力臂)</text>
<text x="600" y="185" fill="var(--accent-color)" font-size="12" text-anchor="middle" opacity="0.8">L2 = 1x</text>
</g>
<!-- Vertical Linkage Rod -->
<g id="linkage-assembly">
<line x1="650" y1="200" x2="650" y2="350" stroke="url(#metalGrad)" stroke-width="8" stroke-linecap="round" id="linkage-rod" />
<circle cx="650" cy="200" r="6" fill="#1E293B" stroke="url(#metalGrad)" stroke-width="2" id="joint-top" />
<circle cx="650" cy="350" r="6" fill="#1E293B" stroke="url(#metalGrad)" stroke-width="2" id="joint-bottom" />
</g>
<!-- Butterfly Valve Assembly -->
<g id="valve-assembly">
<!-- Valve Body Exterior -->
<rect x="620" y="380" width="60" height="60" fill="url(#darkMetal)" rx="4" />
<line x1="650" y1="370" x2="650" y2="380" stroke="url(#metalGrad)" stroke-width="6" />
<!-- Valve Lever (connects linkage to valve axis) -->
<line x1="650" y1="350" x2="650" y2="410" stroke="var(--metal-light)" stroke-width="10" stroke-linecap="round" id="valve-lever" />
<circle cx="650" cy="410" r="10" fill="var(--accent-color)" filter="url(#neonGlow)" />
<!-- Internal Valve Disc (Visible through "cutaway" or conceptual view) -->
<!-- Conceptual cross-section view of the pipe at the valve -->
<ellipse cx="650" cy="410" rx="12" ry="24" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="2" />
<line x1="650" y1="386" x2="650" y2="434" stroke="#FFF" stroke-width="6" id="valve-disc" stroke-linecap="round" />
</g>
<!-- Measurement Markers -->
<g opacity="0.4" font-size="10" fill="var(--text-color)">
<!-- Stroke indicator -->
<line x1="100" y1="210" x2="140" y2="210" stroke="var(--text-color)" stroke-width="1" stroke-dasharray="2 2" />
<line x1="100" y1="310" x2="140" y2="310" stroke="var(--text-color)" stroke-width="1" stroke-dasharray="2 2" />
<path d="M 120 210 L 120 310" fill="none" stroke="var(--text-color)" stroke-width="1" marker-start="url(#arrow)" marker-end="url(#arrow)"/>
<text x="110" y="265" text-anchor="end" transform="rotate(-90, 110, 265)">100mm 行程</text>
</g>
</g>
<!-- Markers definition -->
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="4" markerHeight="4" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="var(--text-color)" />
</marker>
</defs>
</svg>
</div>
<script>
/**
* Core Logic: Procedural animation based on sine wave to simulate continuous
* operation of the IFR mechanical feedback loop.
* No user interaction required, auto-starts on load.
*/
document.addEventListener('DOMContentLoaded', () => {
// DOM Elements
const els = {
tankFluid: document.getElementById('tank-fluid'),
fluidSurface: document.getElementById('fluid-surface'),
floatAssembly: document.getElementById('float-assembly'),
floatRod: document.getElementById('float-rod'),
mainLever: document.getElementById('main-lever'),
linkageRod: document.getElementById('linkage-rod'),
jointTop: document.getElementById('joint-top'),
jointBottom: document.getElementById('joint-bottom'),
valveLever: document.getElementById('valve-lever'),
valveDisc: document.getElementById('valve-disc'),
outflowFluid: document.getElementById('outflow-fluid'),
outflowDash: document.getElementById('outflow-dash'),
uiLevel: document.getElementById('ui-level'),
uiStroke: document.getElementById('ui-stroke'),
uiValve: document.getElementById('ui-valve')
};
// Kinematic Constants
const PIVOT_X = 550;
const PIVOT_Y = 200;
const FLOAT_X = 250;
const LINKAGE_BASE_X = 650; // Distance ratio 300 : 100 = 3:1
const VALVE_X = 650;
const VALVE_Y = 410;
// Operating Range
const Y_MIN = 210; // Float highest (Valve fully open)
const Y_MAX = 310; // Float lowest (Valve fully closed)
const STROKE = Y_MAX - Y_MIN;
// Animation state
let startTime = performance.now();
const CYCLE_DURATION = 12000; // ms per full up/down cycle
function animate(currentTime) {
// 1. Calculate normalized progress [0.0, 1.0] using smooth sine wave
const elapsed = currentTime - startTime;
const phase = (elapsed % CYCLE_DURATION) / CYCLE_DURATION * Math.PI * 2;
// p = 0 (low water, closed), p = 1 (high water, open)
const p = (Math.sin(phase - Math.PI/2) + 1) / 2;
// 2. Compute positions
const floatY = Y_MAX - (p * STROKE);
// Calculate main lever angle
// Angle relative to horizontal left
const angleRad = Math.atan2(floatY - PIVOT_Y, FLOAT_X - PIVOT_X);
const angleDeg = angleRad * (180 / Math.PI);
// Calculate right end of lever (linkage connection)
const leverDistRight = 100;
const rightX = PIVOT_X + leverDistRight * Math.cos(angleRad + Math.PI);
const rightY = PIVOT_Y + leverDistRight * Math.sin(angleRad + Math.PI);
// Calculate valve kinematics (Stroke maps to 90 degrees)
// When p=0 (float low), valve is closed (horizontal 0 deg)
// When p=1 (float high), valve is open (vertical 90 deg)
const valveAngleDeg = p * 90;
const valveAngleRad = valveAngleDeg * (Math.PI / 180);
// Valve lever geometry (length = stroke of linkage / sin(90))
const valveLeverLength = STROKE * (100/300); // Inverse ratio
const valveJointX = VALVE_X - valveLeverLength * Math.cos(valveAngleRad);
const valveJointY = VALVE_Y - valveLeverLength * Math.sin(valveAngleRad);
// 3. Apply Transforms and Attributes
// Fluid Level
els.tankFluid.setAttribute('y', floatY);
els.tankFluid.setAttribute('height', 450 - floatY); // Tank bottom is 450
els.fluidSurface.setAttribute('y1', floatY);
els.fluidSurface.setAttribute('y2', floatY);
// Float Assembly (Translate Y)
els.floatAssembly.setAttribute('transform', `translate(0, ${floatY})`);
// Float rod connects float to lever
const rodHeight = floatY - (floatY); // Actually rod moves with float, connect point is fixed on lever
// Main Lever (Rotate around pivot)
// atan2 gives angle from positive X axis. We need rotation from horizontal.
// Float is on left (-X). Horizontal is roughly 180 or -180.
const rotationBaseline = Math.atan2(0, -300) * 180/Math.PI; // 180
const currentRotation = angleDeg - rotationBaseline;
els.mainLever.setAttribute('transform', `rotate(${currentRotation}, ${PIVOT_X}, ${PIVOT_Y})`);
// To ensure visual perfection of linkage, we procedurally position the rod
// between the computed endpoints rather than relying entirely on SVG transforms
els.linkageRod.setAttribute('x1', rightX);
els.linkageRod.setAttribute('y1', rightY);
els.linkageRod.setAttribute('x2', valveJointX);
els.linkageRod.setAttribute('y2', valveJointY);
els.jointTop.setAttribute('cx', rightX);
els.jointTop.setAttribute('cy', rightY);
els.jointBottom.setAttribute('cx', valveJointX);
els.jointBottom.setAttribute('cy', valveJointY);
// Valve Lever
els.valveLever.setAttribute('x1', valveJointX);
els.valveLever.setAttribute('y1', valveJointY);
els.valveLever.setAttribute('x2', VALVE_X);
els.valveLever.setAttribute('y2', VALVE_Y);
// Valve Disc (rotates 0 to 90)
els.valveDisc.setAttribute('transform', `rotate(${valveAngleDeg}, ${VALVE_X}, ${VALVE_Y})`);
// Outflow Fluid Dynamics (Opacity based on valve opening)
// Add a small threshold before flow starts
const flowOpacity = p > 0.05 ? Math.min(1, p * 1.5) : 0;
els.outflowFluid.style.opacity = flowOpacity;
els.outflowDash.style.opacity = flowOpacity > 0 ? 0.8 : 0;
// Adjust animation speed based on flow rate
els.outflowDash.style.animationDuration = `${1.5 - p}s`;
// 4. Update UI Dashboard
els.uiLevel.innerText = (p * 100).toFixed(1) + ' mm';
els.uiStroke.innerText = (p * 100).toFixed(1) + ' mm';
els.uiValve.innerText = valveAngleDeg.toFixed(1) + '°';
// Loop
requestAnimationFrame(animate);
}
// Start animation loop
requestAnimationFrame(animate);
});
</script>
</body>
</html>
积分规则:每轮对话扣10分
等待动画代码生成...
