分享图
动画工坊
引擎就绪
<!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: #1a233a;
            --text-main: #e2e8f0;
            --text-muted: #64748b;
            
            /* Status Colors */
            --color-normal: #00f0ff; /* Cyan - Active/Normal */
            --color-standby: #fbbf24; /* Amber - Standby/Sync */
            --color-safe: #10b981; /* Green - Safe State/Success */
            --color-danger: #ef4444; /* Red - Failure/Alarm */
            --color-hardwire: #f97316; /* Orange - Independent Hardwire */
            --color-fluid: #3b82f6; /* Blue - Fluid */
            
            --font-mono: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
        }

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

        body {
            background-color: var(--bg-color);
            color: var(--text-main);
            font-family: var(--font-mono);
            overflow: hidden;
            width: 100vw;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            background-image: 
                linear-gradient(var(--grid-color) 1px, transparent 1px),
                linear-gradient(90deg, var(--grid-color) 1px, transparent 1px);
            background-size: 40px 40px;
            background-position: center center;
            transition: box-shadow 0.5s ease;
        }

        /* Screen Edge Vignette for Alarm State */
        body.alarm-state {
            box-shadow: inset 0 0 150px rgba(239, 68, 68, 0.2);
        }

        #animation-container {
            width: 95%;
            height: 95%;
            max-width: 1400px;
            max-height: 900px;
            position: relative;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        svg {
            width: 100%;
            height: 100%;
            filter: drop-shadow(0 0 20px rgba(0, 0, 0, 0.5));
        }

        /* HUD Panels - Strictly constrained to edges, small text */
        .hud-panel {
            position: absolute;
            background: rgba(11, 15, 25, 0.85);
            border: 1px solid rgba(100, 116, 139, 0.3);
            backdrop-filter: blur(8px);
            padding: 12px 16px;
            border-radius: 4px;
            pointer-events: none;
            z-index: 10;
        }

        .hud-top-left {
            top: 20px;
            left: 20px;
            border-left: 3px solid var(--color-normal);
            transition: border-color 0.3s ease;
        }

        .hud-bottom-right {
            bottom: 20px;
            right: 20px;
            text-align: right;
            max-width: 320px;
        }

        .hud-title {
            font-size: 14px;
            font-weight: bold;
            letter-spacing: 1px;
            margin-bottom: 4px;
            color: #fff;
        }

        .hud-text {
            font-size: 12px;
            color: var(--text-muted);
            line-height: 1.5;
        }

        .status-indicator {
            display: inline-block;
            width: 8px;
            height: 8px;
            border-radius: 50%;
            margin-right: 6px;
            background-color: var(--color-normal);
            box-shadow: 0 0 8px var(--color-normal);
        }

        /* SVG Element Styles */
        .component-box {
            fill: rgba(15, 23, 42, 0.9);
            stroke: var(--text-muted);
            stroke-width: 2;
            rx: 6;
            transition: stroke 0.3s, fill 0.3s;
        }

        .component-text {
            fill: var(--text-main);
            font-size: 14px;
            font-family: var(--font-mono);
            text-anchor: middle;
            dominant-baseline: middle;
            font-weight: bold;
        }

        .sub-text {
            fill: var(--text-muted);
            font-size: 10px;
            text-anchor: middle;
        }

        .data-line {
            fill: none;
            stroke: var(--text-muted);
            stroke-width: 2;
            opacity: 0.3;
        }

        .flow-line {
            fill: none;
            stroke-width: 2.5;
            stroke-dasharray: 8 8;
            opacity: 0;
            transition: opacity 0.3s;
        }

        /* Animations */
        @keyframes flow {
            to { stroke-dashoffset: -32; }
        }

        @keyframes pulse-alarm {
            0%, 100% { stroke: var(--color-danger); filter: drop-shadow(0 0 8px var(--color-danger)); }
            50% { stroke: #991b1b; filter: none; }
        }

        @keyframes pulse-sync {
            0%, 100% { opacity: 0.4; }
            50% { opacity: 1; }
        }

        /* State Classes */
        /* 1. Normal State */
        .state-normal .main-plc { stroke: var(--color-normal); }
        .state-normal .standby-plc { stroke: var(--color-standby); }
        .state-normal .flow-main { stroke: var(--color-normal); opacity: 1; animation: flow 1s linear infinite; }
        .state-normal .flow-sync { stroke: var(--color-standby); opacity: 0.6; animation: flow 2s linear infinite, pulse-sync 2s infinite; }
        .state-normal .hud-top-left { border-color: var(--color-normal); }
        .state-normal #status-dot { background: var(--color-normal); box-shadow: 0 0 8px var(--color-normal); }

        /* 2. Main PLC Fail State */
        .state-plc-fail .main-plc { animation: pulse-alarm 1s infinite; }
        .state-plc-fail .main-plc-text { fill: var(--color-danger); }
        .state-plc-fail .standby-plc { stroke: var(--color-normal); filter: drop-shadow(0 0 8px var(--color-normal)); }
        .state-plc-fail .flow-standby { stroke: var(--color-normal); opacity: 1; animation: flow 1s linear infinite; }
        .state-plc-fail .hud-top-left { border-color: var(--color-standby); }
        .state-plc-fail #status-dot { background: var(--color-standby); box-shadow: 0 0 8px var(--color-standby); }

        /* 3. Total Fail & Hardwire State */
        .state-total-fail .main-plc, .state-total-fail .standby-plc, .state-total-fail .sensor-box { animation: pulse-alarm 0.5s infinite; }
        .state-total-fail .hardwire-box { stroke: var(--color-hardwire); filter: drop-shadow(0 0 12px var(--color-hardwire)); fill: rgba(249, 115, 22, 0.1); }
        .state-total-fail .flow-hardwire { stroke: var(--color-hardwire); opacity: 1; stroke-dasharray: 12 6; animation: flow 0.5s linear infinite; }
        .state-total-fail .valve-core { fill: var(--color-hardwire); transform: rotate(90deg); transform-origin: 500px 580px; transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1); }
        .state-total-fail .hud-top-left { border-color: var(--color-danger); }
        .state-total-fail #status-dot { background: var(--color-danger); box-shadow: 0 0 8px var(--color-danger); }

        /* Independent Power */
        .power-line { fill: none; stroke: var(--color-hardwire); stroke-width: 2; stroke-dasharray: 4 4; opacity: 0.5; }
        .state-total-fail .power-line { opacity: 1; animation: flow 1s linear infinite; }

    </style>
</head>
<body>

    <!-- Top Left HUD: System Status -->
    <div class="hud-panel hud-top-left" id="status-hud">
        <div class="hud-title"><span class="status-indicator" id="status-dot"></span><span id="status-title">系统正常运行</span></div>
        <div class="hud-text" id="status-desc">主控 PLC 掌握控制权,备用系统实时同步热备。</div>
    </div>

    <!-- Bottom Right HUD: Principle Explanation -->
    <div class="hud-panel hud-bottom-right">
        <div class="hud-title">最终理想解 (IFR) 架构</div>
        <div class="hud-text">
            极简冗余逻辑:<br>
            1. 硬件双机热备 (切换时间 &le; 0.5s)<br>
            2. 独立供电硬接线回路 (规避系统性瘫痪)<br>
            3. 极端工况下自动降级为物理泄放模式
        </div>
    </div>

    <div id="animation-container" class="state-normal">
        <svg viewBox="0 0 1000 700" preserveAspectRatio="xMidYMid meet">
            <defs>
                <filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
                    <feGaussianBlur stdDeviation="4" result="blur" />
                    <feComposite in="SourceGraphic" in2="blur" operator="over" />
                </filter>
                <marker id="arrow-normal" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto">
                    <path d="M 0 0 L 10 5 L 0 10 z" fill="var(--color-normal)" />
                </marker>
                <marker id="arrow-hardwire" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto">
                    <path d="M 0 0 L 10 5 L 0 10 z" fill="var(--color-hardwire)" />
                </marker>
                
                <!-- Tank Pattern -->
                <pattern id="tank-hatch" width="10" height="10" patternTransform="rotate(45 0 0)" patternUnits="userSpaceOnUse">
                    <line x1="0" y1="0" x2="0" y2="10" stroke="rgba(255,255,255,0.05)" stroke-width="2" />
                </pattern>
            </defs>

            <!-- Background Context -->
            <text x="500" y="40" fill="var(--text-muted)" font-size="12" text-anchor="middle" letter-spacing="4">DRILLING PLATFORM FLUID CONTROL SYSTEM</text>
            <line x1="100" y1="650" x2="900" y2="650" stroke="var(--grid-color)" stroke-width="4" />

            <!-- ================= HARDWARE COMPONENTS ================= -->

            <!-- Central Tank -->
            <g id="tank-group" transform="translate(400, 200)">
                <!-- Tank Body Outline -->
                <rect x="0" y="0" width="200" height="300" fill="url(#tank-hatch)" stroke="var(--text-muted)" stroke-width="3" rx="10" />
                
                <!-- Fluid (Animated via JS) -->
                <rect id="fluid-level" x="4" y="100" width="192" height="196" fill="var(--color-fluid)" opacity="0.6" rx="6" />
                <path d="M 4 100 Q 50 90 100 100 T 196 100" fill="none" stroke="rgba(255,255,255,0.5)" stroke-width="2" id="fluid-surface"/>
                
                <text x="100" y="40" fill="var(--text-muted)" font-size="14" text-anchor="middle" font-weight="bold">高压缓冲储罐</text>
            </g>

            <!-- Sensors -->
            <g id="sensor-group" transform="translate(380, 250)">
                <rect class="component-box sensor-box" x="-30" y="0" width="50" height="30" />
                <text class="sub-text" x="-5" y="15">LVS-1</text>
                <line x1="20" y1="15" x2="40" y2="15" stroke="var(--text-muted)" stroke-width="2" />
                
                <rect class="component-box sensor-box" x="-30" y="100" width="50" height="30" />
                <text class="sub-text" x="-5" y="115">PRS-2</text>
                <line x1="20" y1="115" x2="40" y2="115" stroke="var(--text-muted)" stroke-width="2" />
            </g>

            <!-- Valve -->
            <g id="valve-group" transform="translate(470, 520)">
                <rect x="25" y="-20" width="10" height="20" fill="var(--text-muted)" /> <!-- Pipe connection -->
                <path d="M 0 0 L 60 40 L 0 40 L 60 0 Z" fill="rgba(15,23,42,0.9)" stroke="var(--text-muted)" stroke-width="2" />
                <circle class="valve-core" cx="30" cy="20" r="12" fill="var(--text-muted)" />
                <rect class="valve-core" x="27" y="5" width="6" height="30" fill="#0b0f19" /> <!-- Indicator -->
                <rect x="25" y="40" width="10" height="40" fill="var(--text-muted)" /> <!-- Outlet pipe -->
                <!-- Fluid Drain Animation Particle Path -->
                <path id="drain-flow" d="M 30 40 L 30 100" class="flow-line flow-hardwire" stroke-width="4" stroke="var(--color-fluid)" />
            </g>

            <!-- PLCs -->
            <g id="plcs">
                <!-- Main PLC -->
                <rect class="component-box main-plc" x="100" y="100" width="160" height="80" />
                <text class="component-text main-plc-text" x="180" y="135">主控 PLC (A机)</text>
                <text class="sub-text" x="180" y="155">Master Control</text>

                <!-- Standby PLC -->
                <rect class="component-box standby-plc" x="740" y="100" width="160" height="80" />
                <text class="component-text standby-plc-text" x="820" y="135">备用 PLC (B机)</text>
                <text class="sub-text" x="820" y="155">Hot Standby</text>
            </g>

            <!-- Hardwired Safety Loop -->
            <g id="hardwire-module" transform="translate(100, 480)">
                <rect class="component-box hardwire-box" x="0" y="0" width="160" height="80" />
                <text class="component-text" x="80" y="35">硬接线安全回路</text>
                <text class="sub-text" x="80" y="55">独立继电器控制</text>
                
                <!-- Independent Power Source -->
                <circle cx="20" cy="110" r="12" fill="none" stroke="var(--color-hardwire)" stroke-width="2" />
                <text x="20" y="114" fill="var(--color-hardwire)" font-size="12" text-anchor="middle">⚡</text>
                <text class="sub-text" x="80" y="113" fill="var(--text-muted)">独立 UPS 供电</text>
                <path d="M 35 110 L 80 110 L 80 80" class="power-line" />
            </g>


            <!-- ================= CONNECTIONS & DATA FLOWS ================= -->

            <!-- Static Base Lines -->
            <!-- Sensors to Main PLC -->
            <path d="M 350 265 L 180 265 L 180 180" class="data-line" />
            <path d="M 350 365 L 220 365 L 220 180" class="data-line" />
            
            <!-- Sensors to Standby PLC -->
            <path d="M 350 265 L 300 265 L 300 80 L 820 80 L 820 100" class="data-line" />
            
            <!-- PLC Heartbeat -->
            <path d="M 260 140 L 740 140" class="data-line" />

            <!-- Main PLC to Valve -->
            <path d="M 200 180 L 200 540 L 470 540" class="data-line" />
            
            <!-- Standby PLC to Valve -->
            <path d="M 800 180 L 800 540 L 530 540" class="data-line" />

            <!-- Hardwire to Valve (Direct) -->
            <path d="M 260 520 L 470 520" class="data-line" stroke="var(--color-hardwire)" stroke-dasharray="4 4" />


            <!-- Animated Flow Lines (Overlays) -->
            
            <!-- 1. Normal Flow (Main PLC active) -->
            <g class="flow-main">
                <path d="M 350 265 L 180 265 L 180 180" class="flow-line flow-main" />
                <path d="M 350 365 L 220 365 L 220 180" class="flow-line flow-main" />
                <path d="M 200 180 L 200 540 L 465 540" class="flow-line flow-main" marker-end="url(#arrow-normal)" />
            </g>

            <!-- Heartbeat Sync (Main to Standby) -->
            <path d="M 260 140 L 735 140" class="flow-line flow-sync" marker-end="url(#arrow-normal)" />

            <!-- 2. Standby Flow (Activated when Main fails) -->
            <g class="flow-standby">
                <path d="M 350 265 L 300 265 L 300 80 L 820 80 L 820 95" class="flow-line flow-standby" />
                <path d="M 800 180 L 800 540 L 535 540" class="flow-line flow-standby" marker-end="url(#arrow-normal)" />
            </g>

            <!-- 3. Hardwire Flow (Activated on total digital failure) -->
            <g class="flow-hardwire">
                <!-- Direct command bypassing digital logic -->
                <path d="M 260 520 L 465 520" class="flow-line flow-hardwire" marker-end="url(#arrow-hardwire)" filter="url(#glow)" />
            </g>

        </svg>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const container = document.getElementById('animation-container');
            const body = document.body;
            const titleEl = document.getElementById('status-title');
            const descEl = document.getElementById('status-desc');
            const fluidLevel = document.getElementById('fluid-level');
            const fluidSurface = document.getElementById('fluid-surface');
            
            // Animation States Configuration
            const states = [
                {
                    id: 'state-normal',
                    title: '系统正常运行',
                    desc: '主控 PLC (A机) 掌握控制权读取传感数据,备用 PLC (B机) 实时同步热备。',
                    duration: 4000,
                    alarm: false
                },
                {
                    id: 'state-plc-fail',
                    title: '主控 PLC 故障 - 无缝切换 (<0.5s)',
                    desc: 'A机通讯中断。冗余控制链激活,B机瞬间接管控制权,维持系统连续性。',
                    duration: 4000,
                    alarm: false
                },
                {
                    id: 'state-total-fail',
                    title: '极端通讯瘫痪 - 自动泄放模式',
                    desc: '传感器全部失效。硬接线安全回路利用独立电源强制打开蝶阀,执行物理防溢流保护 (IFR)。',
                    duration: 6000,
                    alarm: true
                }
            ];

            let currentStateIndex = 0;
            let drainAnimationReq;
            let fluidY = 100;
            let fluidH = 196;

            function updateState() {
                const state = states[currentStateIndex];
                
                // Update Classes
                container.className = state.id;
                if(state.alarm) {
                    body.classList.add('alarm-state');
                } else {
                    body.classList.remove('alarm-state');
                }

                // Update HUD
                titleEl.textContent = state.title;
                descEl.innerHTML = state.desc;

                // Handle specific SVG animations via JS for better control
                cancelAnimationFrame(drainAnimationReq);
                if (state.id === 'state-total-fail') {
                    // Animate fluid draining
                    const drain = () => {
                        if (fluidH > 20) {
                            fluidH -= 0.5;
                            fluidY += 0.5;
                            fluidLevel.setAttribute('height', fluidH);
                            fluidLevel.setAttribute('y', fluidY);
                            
                            // Update surface curve y position
                            fluidSurface.setAttribute('d', `M 4 ${fluidY} Q 50 ${fluidY - 10} 100 ${fluidY} T 196 ${fluidY}`);
                            
                            drainAnimationReq = requestAnimationFrame(drain);
                        }
                    };
                    drain();
                } else {
                    // Reset fluid
                    fluidY = 100;
                    fluidH = 196;
                    fluidLevel.setAttribute('height', fluidH);
                    fluidLevel.setAttribute('y', fluidY);
                    fluidSurface.setAttribute('d', `M 4 100 Q 50 90 100 100 T 196 100`);
                }

                // Schedule next state
                setTimeout(() => {
                    currentStateIndex = (currentStateIndex + 1) % states.length;
                    updateState();
                }, state.duration);
            }

            // Start animation loop immediately
            updateState();
        });
    </script>
</body>
</html>
积分规则:每轮对话扣10分