分享图
动画工坊
引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>5G 无人化值守与远程监控系统原理</title>
    <style>
        /* =========================================
           AESTHETICS & TYPOGRAPHY
           Cyber-industrial / Tech-minimalist theme
           ========================================= */
        @import url('https://fonts.googleapis.com/css2?family=Chakra+Petch:wght@400;500;600&family=Noto+Sans+SC:wght@300;400;500&display=swap');

        :root {
            --bg-base: #060913;
            --grid-color: rgba(0, 243, 255, 0.05);
            --neon-cyan: #00f3ff;
            --neon-cyan-dim: rgba(0, 243, 255, 0.3);
            --neon-purple: #8a2be2;
            --neon-alert: #ff2a6d;
            --text-main: #a0aec0;
            --text-bright: #ffffff;
            --panel-bg: rgba(6, 9, 19, 0.7);
            --panel-border: rgba(0, 243, 255, 0.15);
        }

        body, html {
            margin: 0;
            padding: 0;
            width: 100vw;
            height: 100vh;
            background-color: var(--bg-base);
            font-family: 'Noto Sans SC', sans-serif;
            color: var(--text-main);
            overflow: hidden;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        /* Background Grid Overlay */
        .bg-grid {
            position: absolute;
            top: 0; left: 0; right: 0; bottom: 0;
            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;
            pointer-events: none;
        }

        /* Radial gradient for depth */
        .bg-glow {
            position: absolute;
            top: 50%; left: 50%;
            transform: translate(-50%, -50%);
            width: 80vw; height: 80vh;
            background: radial-gradient(circle, rgba(0, 243, 255, 0.03) 0%, rgba(6, 9, 19, 0) 70%);
            z-index: 0;
            pointer-events: none;
        }

        /* =========================================
           UI PANELS (Strictly positioned in corners, small text)
           ========================================= */
        .ui-panel {
            position: absolute;
            background: var(--panel-bg);
            border: 1px solid var(--panel-border);
            border-radius: 6px;
            padding: 12px 16px;
            backdrop-filter: blur(10px);
            z-index: 10;
            font-size: 12px;
            pointer-events: none;
            box-shadow: 0 4px 20px rgba(0,0,0,0.5);
        }

        .ui-top-left { top: 24px; left: 24px; max-width: 250px; }
        .ui-bottom-left { bottom: 24px; left: 24px; }
        .ui-top-right { top: 24px; right: 24px; pointer-events: auto; }
        .ui-bottom-right { bottom: 24px; right: 24px; }

        h1, h2, .font-tech {
            font-family: 'Chakra Petch', sans-serif;
            margin: 0 0 8px 0;
        }

        h1 {
            color: var(--neon-cyan);
            font-size: 14px;
            font-weight: 600;
            letter-spacing: 1px;
            text-transform: uppercase;
            border-bottom: 1px solid var(--neon-cyan-dim);
            padding-bottom: 4px;
        }

        .data-row {
            display: flex;
            justify-content: space-between;
            margin-bottom: 4px;
            align-items: center;
        }

        .data-label { color: #6b7280; }
        .data-value { 
            color: var(--text-bright); 
            font-family: 'Chakra Petch', sans-serif; 
            font-weight: 500;
        }
        .highlight { color: var(--neon-cyan); }
        .alert-text { color: var(--neon-alert); }

        /* Status Indicator */
        .status-dot {
            display: inline-block;
            width: 6px; height: 6px;
            border-radius: 50%;
            background-color: var(--neon-cyan);
            box-shadow: 0 0 8px var(--neon-cyan);
            margin-right: 6px;
            animation: pulse-dot 2s infinite;
        }

        @keyframes pulse-dot {
            0% { opacity: 0.5; box-shadow: 0 0 4px var(--neon-cyan); }
            50% { opacity: 1; box-shadow: 0 0 12px var(--neon-cyan); }
            100% { opacity: 0.5; box-shadow: 0 0 4px var(--neon-cyan); }
        }

        /* Interactive Controls */
        .btn {
            background: transparent;
            border: 1px solid var(--neon-cyan-dim);
            color: var(--neon-cyan);
            padding: 6px 12px;
            border-radius: 4px;
            font-family: 'Noto Sans SC', sans-serif;
            font-size: 12px;
            cursor: pointer;
            transition: all 0.3s ease;
            margin-bottom: 8px;
            display: block;
            width: 100%;
            text-align: center;
        }
        .btn:hover {
            background: rgba(0, 243, 255, 0.1);
            border-color: var(--neon-cyan);
            box-shadow: 0 0 10px rgba(0, 243, 255, 0.2);
        }
        .btn-alert {
            color: var(--neon-alert);
            border-color: rgba(255, 42, 109, 0.3);
        }
        .btn-alert:hover, .btn-alert.active {
            background: rgba(255, 42, 109, 0.1);
            border-color: var(--neon-alert);
            box-shadow: 0 0 10px rgba(255, 42, 109, 0.2);
        }

        /* =========================================
           MAIN SVG CONTAINER
           Takes up maximum space, core visual element
           ========================================= */
        #animation-container {
            position: relative;
            width: 100%;
            height: 100%;
            z-index: 5;
            display: flex;
            justify-content: center;
            align-items: center;
        }

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

        /* SVG Element Styles */
        .node-base { fill: #0f172a; stroke: var(--neon-cyan-dim); stroke-width: 1.5; }
        .text-svg { font-family: 'Noto Sans SC', sans-serif; font-size: 14px; fill: var(--text-main); text-anchor: middle; }
        .text-svg-title { font-size: 16px; fill: var(--text-bright); font-weight: 500; }
        .text-svg-tech { font-family: 'Chakra Petch', sans-serif; font-size: 12px; fill: var(--neon-cyan); }
        
        .path-main { fill: none; stroke: var(--panel-border); stroke-width: 2; stroke-dasharray: 4 4; }
        .path-glow { fill: none; stroke: var(--neon-cyan); stroke-width: 4; opacity: 0.1; filter: url(#glow); }
        .path-vpn { fill: none; stroke: var(--neon-purple); stroke-width: 12; opacity: 0.15; stroke-linecap: round; }
        
        /* CSS Animations applied to SVG elements */
        .spin-slow { transform-origin: center; animation: spin 20s linear infinite; }
        .spin-slow-reverse { transform-origin: center; animation: spin-reverse 25s linear infinite; }
        
        @keyframes spin { 100% { transform: rotate(360deg); } }
        @keyframes spin-reverse { 100% { transform: rotate(-360deg); } }

        /* Dynamic classes controlled by JS */
        .state-alert .path-glow { stroke: var(--neon-alert); opacity: 0.2; }
        .state-alert .text-svg-tech.opc-mqtt { fill: var(--neon-alert); }
        .state-alert .node-gateway { stroke: var(--neon-alert); }
    </style>
</head>
<body>

    <!-- Background Effects -->
    <div class="bg-grid"></div>
    <div class="bg-glow"></div>

    <!-- UI Overlay Panels -->
    <div class="ui-panel ui-top-left">
        <h1>最终理想解 (IFR) 架构</h1>
        <div style="color: #6b7280; line-height: 1.5;">
            利用 5G 网关作为透明代理枢纽,无缝桥接物理设备与云端,消除空间距离障碍,实现“数据即刻可见,指令即刻触达”的理想无人化状态。
        </div>
    </div>

    <div class="ui-panel ui-bottom-left">
        <div class="font-tech" style="color: var(--neon-cyan); margin-bottom: 8px;">SYSTEM PARAMS //</div>
        <div class="data-row">
            <span class="data-label">上传频率 (MQTT):</span>
            <span class="data-value highlight">2 秒/次</span>
        </div>
        <div class="data-row">
            <span class="data-label">底层采集 (OPC UA):</span>
            <span class="data-value">实时加密</span>
        </div>
        <div class="data-row">
            <span class="data-label">安全防护机制:</span>
            <span class="data-value" style="color: var(--neon-purple);">VPN 隧道</span>
        </div>
    </div>

    <div class="ui-panel ui-bottom-right">
        <div class="font-tech" style="color: var(--neon-cyan); margin-bottom: 8px;">LINK STATUS //</div>
        <div class="data-row">
            <span class="data-label">控制指令时延:</span>
            <span class="data-value highlight" id="latency-val">42 ms</span>
        </div>
        <div class="data-row">
            <span class="data-label">网络状态 (5G):</span>
            <span class="data-value"><span class="status-dot"></span>已连接</span>
        </div>
    </div>

    <div class="ui-panel ui-top-right">
        <div class="font-tech" style="color: #6b7280; margin-bottom: 8px;">INTERACTIVE SIMULATION</div>
        <button class="btn" id="btn-control">模拟远程下发指令 (⬇)</button>
        <button class="btn btn-alert" id="btn-alarm">触发井场异常报警 (⬆)</button>
    </div>

    <!-- Main Animation SVG -->
    <div id="animation-container">
        <!-- viewBox centered, ample space -->
        <svg viewBox="0 0 1600 900" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg" id="main-canvas">
            <defs>
                <!-- Filters -->
                <filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
                    <feGaussianBlur stdDeviation="8" result="blur" />
                    <feComposite in="SourceGraphic" in2="blur" operator="over" />
                </filter>
                <filter id="glow-strong" x="-20%" y="-20%" width="140%" height="140%">
                    <feGaussianBlur stdDeviation="12" result="blur" />
                    <feComposite in="SourceGraphic" in2="blur" operator="over" />
                </filter>
                
                <!-- Gradients -->
                <linearGradient id="grad-cyan" x1="0%" y1="0%" x2="100%" y2="100%">
                    <stop offset="0%" stop-color="#00f3ff" stop-opacity="0.8" />
                    <stop offset="100%" stop-color="#0055ff" stop-opacity="0.2" />
                </linearGradient>
                <linearGradient id="grad-vpn" x1="0%" y1="0%" x2="100%" y2="0%">
                    <stop offset="0%" stop-color="#8a2be2" stop-opacity="0.1" />
                    <stop offset="50%" stop-color="#8a2be2" stop-opacity="0.4" />
                    <stop offset="100%" stop-color="#8a2be2" stop-opacity="0.1" />
                </linearGradient>

                <!-- Data Packet Symbols -->
                <g id="packet-up">
                    <circle cx="0" cy="0" r="4" fill="#00f3ff" filter="url(#glow)" />
                    <circle cx="0" cy="0" r="2" fill="#fff" />
                </g>
                <g id="packet-alarm">
                    <circle cx="0" cy="0" r="5" fill="#ff2a6d" filter="url(#glow-strong)" />
                    <circle cx="0" cy="0" r="2" fill="#fff" />
                </g>
                <g id="packet-down">
                    <rect x="-6" y="-3" width="12" height="6" rx="2" fill="#00f3ff" filter="url(#glow)" />
                </g>

                <!-- Network Waves Symbol -->
                <g id="radio-waves">
                    <circle cx="0" cy="0" r="10" fill="none" stroke="#00f3ff" stroke-width="1.5" opacity="0">
                        <animate attributeName="r" values="10; 40" dur="2s" repeatCount="indefinite" />
                        <animate attributeName="opacity" values="0.8; 0" dur="2s" repeatCount="indefinite" />
                    </circle>
                    <circle cx="0" cy="0" r="10" fill="none" stroke="#00f3ff" stroke-width="1.5" opacity="0">
                        <animate attributeName="r" values="10; 40" dur="2s" begin="1s" repeatCount="indefinite" />
                        <animate attributeName="opacity" values="0.8; 0" dur="2s" begin="1s" repeatCount="indefinite" />
                    </circle>
                </g>
            </defs>

            <!-- ============================== PATHS ============================== -->
            <!-- Base Path 1: PLC to Gateway -->
            <path id="path-plc-gw" d="M 350 450 L 600 450" class="path-main" />
            <path d="M 350 450 L 600 450" class="path-glow" />
            
            <!-- Base Path 2: Gateway to Cloud -->
            <path id="path-gw-cloud" d="M 1000 450 C 1150 450 1200 300 1350 300" class="path-main" />
            <path d="M 1000 450 C 1150 450 1200 300 1350 300" class="path-glow" />
            <!-- VPN Tunnel visualization (Gateway to Cloud) -->
            <path d="M 1000 450 C 1150 450 1200 300 1350 300" class="path-vpn" />
            <text x="1150" y="360" class="text-svg-tech" style="fill: var(--neon-purple); opacity: 0.7;">加密 VPN 隧道</text>

            <!-- Base Path 3: Gateway to APP -->
            <path id="path-gw-app" d="M 1000 450 C 1150 450 1200 600 1350 600" class="path-main" />
            <path d="M 1000 450 C 1150 450 1200 600 1350 600" class="path-glow" />

            <!-- Control Return Path (Cloud to PLC via GW) -->
            <path id="path-return" d="M 1350 300 C 1200 300 1150 450 1000 450 L 350 450" fill="none" />

            <!-- ============================== NODES ============================== -->
            
            <!-- NODE 1: Wellsite / PLC (Left) -->
            <g transform="translate(200, 450)">
                <!-- Decorative tech circles -->
                <circle cx="0" cy="0" r="80" fill="none" stroke="rgba(0,243,255,0.1)" stroke-width="1" class="spin-slow" stroke-dasharray="10 5" />
                <circle cx="0" cy="0" r="95" fill="none" stroke="rgba(0,243,255,0.05)" stroke-width="1" class="spin-slow-reverse" stroke-dasharray="20 10 5 10" />
                
                <!-- Main Box -->
                <rect x="-60" y="-70" width="120" height="140" rx="8" class="node-base" />
                <rect x="-50" y="-60" width="100" height="40" rx="4" fill="#1e293b" stroke="#334155" />
                <!-- PLC lights -->
                <circle cx="-30" cy="-40" r="4" fill="#00ff00" filter="url(#glow)" />
                <circle cx="-15" cy="-40" r="4" fill="#00ff00" />
                <circle cx="0" cy="-40" r="4" fill="#00ff00" />
                <circle cx="15" cy="-40" r="4" fill="#334155" id="plc-alarm-light" />
                
                <!-- Data bars simulation -->
                <rect x="-40" y="-5" width="6" height="20" fill="var(--neon-cyan)" opacity="0.6">
                    <animate attributeName="height" values="20; 5; 25; 15; 20" dur="1.5s" repeatCount="indefinite" />
                    <animate attributeName="y" values="-5; 10; -10; 0; -5" dur="1.5s" repeatCount="indefinite" />
                </rect>
                <rect x="-25" y="-5" width="6" height="30" fill="var(--neon-cyan)" opacity="0.4">
                    <animate attributeName="height" values="30; 10; 20; 5; 30" dur="2.1s" repeatCount="indefinite" />
                    <animate attributeName="y" values="-5; 15; 5; 20; -5" dur="2.1s" repeatCount="indefinite" />
                </rect>
                
                <text x="0" y="90" class="text-svg-title">井场前端采集系统</text>
                <text x="0" y="110" class="text-svg">PLC / 传感器 / 阀门</text>
                
                <!-- Real-time data generating visual -->
                <text x="0" y="40" class="text-svg-tech" opacity="0.8">液位: 68%</text>
                <text x="0" y="55" class="text-svg-tech" opacity="0.8">伺服电流: 4.2A</text>
            </g>

            <!-- NODE 2: 5G Industrial Gateway (Center) -->
            <g transform="translate(800, 450)" class="node-gateway">
                <!-- Large Hexagon base representing the core innovation/hub -->
                <polygon points="0,-100 86.6,-50 86.6,50 0,100 -86.6,50 -86.6,-50" fill="url(#grad-cyan)" opacity="0.1" />
                <polygon points="0,-110 95.2,-55 95.2,55 0,110 -95.2,55 -95.2,-55" fill="none" stroke="var(--neon-cyan)" stroke-width="1" opacity="0.3" class="spin-slow" />
                
                <!-- Gateway Box -->
                <rect x="-50" y="-40" width="100" height="80" rx="10" fill="#0f172a" stroke="var(--neon-cyan)" stroke-width="2" filter="url(#glow)" />
                <path d="M -30 -10 L -10 -10 L 0 10 L 20 -10 L 30 -10" fill="none" stroke="#fff" stroke-width="2" opacity="0.5" />
                
                <!-- Antennas -->
                <line x1="-30" y1="-40" x2="-40" y2="-70" stroke="var(--neon-cyan)" stroke-width="3" stroke-linecap="round" />
                <line x1="30" y1="-40" x2="40" y2="-70" stroke="var(--neon-cyan)" stroke-width="3" stroke-linecap="round" />
                
                <!-- 5G Waves coming from antennas -->
                <use href="#radio-waves" x="-40" y="-70" />
                <use href="#radio-waves" x="40" y="-70" />
                
                <text x="0" y="140" class="text-svg-title">工业 5G 网关</text>
                <text x="0" y="160" class="text-svg">边缘计算与协议转换</text>

                <!-- Protocol translation visual (The core IFR mechanism) -->
                <!-- OPC UA IN -->
                <path d="M -200 0 L -100 0" fill="none" stroke="var(--neon-cyan-dim)" stroke-width="1" stroke-dasharray="2 2" />
                <text x="-150" y="-10" class="text-svg-tech opc-mqtt">OPC UA 数据模型 (局域)</text>
                
                <!-- MQTT OUT -->
                <path d="M 100 0 L 200 0" fill="none" stroke="var(--neon-cyan-dim)" stroke-width="1" stroke-dasharray="2 2" />
                <text x="150" y="-10" class="text-svg-tech opc-mqtt">MQTT 物联网协议 (广域)</text>
            </g>

            <!-- NODE 3: Cloud SCADA (Top Right) -->
            <g transform="translate(1350, 300)">
                <!-- Server rack isometric abstraction -->
                <g stroke="var(--neon-cyan-dim)" stroke-width="1.5" fill="#0f172a">
                    <path d="M -60 20 L 0 40 L 60 20 L 0 0 Z" />
                    <path d="M -60 0 L 0 20 L 60 0 L 0 -20 Z" />
                    <path d="M -60 -20 L 0 0 L 60 -20 L 0 -40 Z" />
                    <path d="M -60 -40 L 0 -20 L 60 -40 L 0 -60 Z" />
                </g>
                <!-- Blinking server lights -->
                <circle cx="0" cy="15" r="2" fill="var(--neon-cyan)" filter="url(#glow)">
                    <animate attributeName="opacity" values="1;0;1" dur="1s" repeatCount="indefinite" />
                </circle>
                <circle cx="0" cy="-5" r="2" fill="var(--neon-cyan)" filter="url(#glow)">
                    <animate attributeName="opacity" values="0;1;0" dur="1.2s" repeatCount="indefinite" />
                </circle>

                <text x="0" y="70" class="text-svg-title">云端指挥中心</text>
                <text x="0" y="90" class="text-svg">SCADA / 远程诊断</text>
            </g>

            <!-- NODE 4: Mobile APP (Bottom Right) -->
            <g transform="translate(1350, 600)">
                <!-- Phone outline -->
                <rect x="-30" y="-55" width="60" height="110" rx="8" class="node-base" />
                <rect x="-25" y="-45" width="50" height="80" rx="4" fill="#1e293b" />
                <line x1="-10" y1="-50" x2="10" y2="-50" stroke="#334155" stroke-width="2" stroke-linecap="round" />
                
                <!-- App UI mock -->
                <circle cx="-10" cy="-30" r="5" fill="var(--neon-cyan)" opacity="0.8" />
                <rect x="0" y="-33" width="20" height="4" fill="#475569" />
                <circle cx="-10" cy="-15" r="5" fill="var(--neon-cyan)" opacity="0.8" />
                <rect x="0" y="-18" width="15" height="4" fill="#475569" />
                
                <text x="0" y="85" class="text-svg-title">移动端 APP</text>
                <text x="0" y="105" class="text-svg">实时监控与报警推送</text>
            </g>

            <!-- ============================== ANIMATED DATA FLOWS ============================== -->
            <!-- 2秒/次 continuous upload flow (PLC -> GW -> Cloud/APP) -->
            <g id="normal-data-flow">
                <!-- To Gateway -->
                <use href="#packet-up">
                    <animateMotion dur="1s" repeatCount="indefinite">
                        <mpath href="#path-plc-gw" />
                    </animateMotion>
                </use>
                <use href="#packet-up">
                    <animateMotion dur="1s" begin="0.5s" repeatCount="indefinite">
                        <mpath href="#path-plc-gw" />
                    </animateMotion>
                </use>

                <!-- Gateway to Cloud -->
                <use href="#packet-up">
                    <animateMotion dur="1s" repeatCount="indefinite">
                        <mpath href="#path-gw-cloud" />
                    </animateMotion>
                </use>
                <use href="#packet-up">
                    <animateMotion dur="1s" begin="0.5s" repeatCount="indefinite">
                        <mpath href="#path-gw-cloud" />
                    </animateMotion>
                </use>

                <!-- Gateway to APP -->
                <use href="#packet-up">
                    <animateMotion dur="1.2s" repeatCount="indefinite">
                        <mpath href="#path-gw-app" />
                    </animateMotion>
                </use>
            </g>

            <!-- Alarm Data Flow (Initially Hidden) -->
            <g id="alarm-data-flow" style="display: none;">
                <use href="#packet-alarm">
                    <animateMotion dur="0.8s" repeatCount="indefinite">
                        <mpath href="#path-plc-gw" />
                    </animateMotion>
                </use>
                <use href="#packet-alarm">
                    <animateMotion dur="0.8s" repeatCount="indefinite">
                        <mpath href="#path-gw-cloud" />
                    </animateMotion>
                </use>
                <use href="#packet-alarm">
                    <animateMotion dur="0.8s" repeatCount="indefinite">
                        <mpath href="#path-gw-app" />
                    </animateMotion>
                </use>
            </g>

            <!-- Fast Control Instruction (Triggered via JS) -->
            <use href="#packet-down" id="control-packet" style="display: none;">
                <!-- Animation defined in JS to allow re-triggering -->
            </use>

        </svg>
    </div>

    <script>
        // =========================================
        // INTERACTIVITY & LOGIC
        // =========================================
        document.addEventListener('DOMContentLoaded', () => {
            const btnAlarm = document.getElementById('btn-alarm');
            const btnControl = document.getElementById('btn-control');
            const normalFlow = document.getElementById('normal-data-flow');
            const alarmFlow = document.getElementById('alarm-data-flow');
            const container = document.getElementById('animation-container');
            const plcAlarmLight = document.getElementById('plc-alarm-light');
            const controlPacket = document.getElementById('control-packet');
            const latencyVal = document.getElementById('latency-val');
            
            let isAlarmActive = false;

            // Update latency slightly to simulate live dashboard
            setInterval(() => {
                const base = isAlarmActive ? 80 : 35;
                const jitter = Math.floor(Math.random() * 15);
                latencyVal.innerText = `${base + jitter} ms`;
            }, 2000);

            // Toggle Alarm Simulation
            btnAlarm.addEventListener('click', () => {
                isAlarmActive = !isAlarmActive;
                if (isAlarmActive) {
                    btnAlarm.classList.add('active');
                    btnAlarm.innerText = '取消井场异常报警 (⬆)';
                    container.classList.add('state-alert');
                    normalFlow.style.display = 'none';
                    alarmFlow.style.display = 'block';
                    plcAlarmLight.setAttribute('fill', '#ff2a6d');
                    plcAlarmLight.setAttribute('filter', 'url(#glow-strong)');
                } else {
                    btnAlarm.classList.remove('active');
                    btnAlarm.innerText = '触发井场异常报警 (⬆)';
                    container.classList.remove('state-alert');
                    normalFlow.style.display = 'block';
                    alarmFlow.style.display = 'none';
                    plcAlarmLight.setAttribute('fill', '#334155');
                    plcAlarmLight.removeAttribute('filter');
                }
            });

            // Trigger Remote Control Instruction (< 1s Latency Demo)
            let controlTimeout;
            btnControl.addEventListener('click', () => {
                // Prevent spamming
                if (controlPacket.style.display === 'block') return;
                
                btnControl.innerText = '指令下发中...';
                btnControl.style.borderColor = '#ffffff';
                btnControl.style.color = '#ffffff';
                
                // Show packet
                controlPacket.style.display = 'block';
                
                // Create and append animateMotion dynamically to trigger it immediately
                const animateMotion = document.createElementNS('http://www.w3.org/2000/svg', 'animateMotion');
                animateMotion.setAttribute('dur', '0.6s'); // Represents < 1s latency
                animateMotion.setAttribute('fill', 'freeze');
                
                const mpath = document.createElementNS('http://www.w3.org/2000/svg', 'mpath');
                mpath.setAttribute('href', '#path-return');
                
                animateMotion.appendChild(mpath);
                controlPacket.appendChild(animateMotion);
                
                // Trigger animation (SMIL beginElement if supported, or rely on insert)
                try { animateMotion.beginElement(); } catch(e) {}

                // Reset after animation duration
                clearTimeout(controlTimeout);
                controlTimeout = setTimeout(() => {
                    controlPacket.style.display = 'none';
                    controlPacket.innerHTML = ''; // Clean up
                    
                    btnControl.innerText = '模拟远程下发指令 (⬇)';
                    btnControl.style.borderColor = '';
                    btnControl.style.color = '';
                    
                    // Visual feedback on PLC
                    const ogColor = plcAlarmLight.getAttribute('fill');
                    plcAlarmLight.setAttribute('fill', '#ffffff');
                    setTimeout(() => plcAlarmLight.setAttribute('fill', ogColor), 300);
                    
                }, 650); // Slightly longer than dur
            });
        });
    </script>
</body>
</html>
积分规则:每轮对话扣10分