分享图
动画工坊
引擎就绪
<!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: #050914;
            --panel-bg: rgba(10, 15, 30, 0.75);
            --border-color: rgba(0, 240, 255, 0.2);
            --text-main: #e0f2fe;
            --text-dim: #7dd3fc;
            --accent: #00f0ff;
            --accent-glow: rgba(0, 240, 255, 0.6);
            --warn: #fbbf24;
            --danger: #ef4444;
            --mesh-color: rgba(148, 163, 184, 0.3);
            --pcb-color: #022c22;
        }

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

        body {
            background-color: var(--bg-color);
            color: var(--text-main);
            font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Microsoft YaHei';
            overflow: hidden;
            width: 100vw;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            background-image: 
                radial-gradient(circle at 50% 50%, rgba(0, 240, 255, 0.05) 0%, transparent 60%),
                linear-gradient(rgba(255,255,255,0.02) 1px, transparent 1px),
                linear-gradient(90deg, rgba(255,255,255,0.02) 1px, transparent 1px);
            background-size: 100% 100%, 40px 40px, 40px 40px;
        }

        /* 核心视觉容器 */
        #visualization-container {
            position: relative;
            width: 100%;
            max-width: 1600px;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        /* 纯SVG物理仿真层 */
        #simulation-svg {
            position: absolute;
            width: 70%;
            height: 90%;
            left: 5%;
            filter: drop-shadow(0 0 20px rgba(0, 240, 255, 0.1));
        }

        /* 数据看板界面 */
        .dashboard {
            position: absolute;
            right: 40px;
            top: 50%;
            transform: translateY(-50%);
            width: 380px;
            display: flex;
            flex-direction: column;
            gap: 20px;
            z-index: 10;
        }

        .panel {
            background: var(--panel-bg);
            border: 1px solid var(--border-color);
            border-radius: 8px;
            padding: 20px;
            backdrop-filter: blur(10px);
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5), inset 0 0 20px rgba(0, 240, 255, 0.05);
            position: relative;
            overflow: hidden;
        }

        .panel::before {
            content: '';
            position: absolute;
            top: 0; left: 0; width: 100%; height: 2px;
            background: linear-gradient(90deg, transparent, var(--accent), transparent);
        }

        .panel-header {
            font-size: 14px;
            font-weight: 600;
            letter-spacing: 1px;
            margin-bottom: 15px;
            display: flex;
            align-items: center;
            justify-content: space-between;
            color: var(--accent);
            text-transform: uppercase;
        }

        .panel-header::before {
            content: '';
            display: inline-block;
            width: 8px;
            height: 8px;
            background-color: var(--accent);
            border-radius: 50%;
            margin-right: 10px;
            box-shadow: 0 0 10px var(--accent-glow);
            animation: pulse-dot 2s infinite;
        }

        /* 热力图容器 */
        #heatmap-container {
            width: 100%;
            aspect-ratio: 4/3;
            background: rgba(0, 0, 0, 0.5);
            border: 1px solid rgba(255,255,255,0.1);
            border-radius: 4px;
            position: relative;
            display: grid;
            grid-template-columns: repeat(16, 1fr);
            grid-template-rows: repeat(12, 1fr);
            gap: 1px;
            padding: 2px;
        }

        .heatmap-cell {
            background-color: #000;
            transition: background-color 0.3s ease;
            border-radius: 1px;
        }

        /* 扫描线 (热力图上) */
        #heatmap-scanner {
            position: absolute;
            top: 0;
            left: 0;
            width: calc(100% / 16);
            height: 100%;
            background: rgba(255, 255, 255, 0.1);
            border-left: 2px solid var(--accent);
            border-right: 1px solid rgba(0, 240, 255, 0.3);
            pointer-events: none;
            box-shadow: 0 0 15px var(--accent-glow);
            transition: transform 0.05s linear;
        }

        /* 色阶图例 */
        .legend {
            margin-top: 15px;
            display: flex;
            flex-direction: column;
            gap: 5px;
        }
        .legend-bar {
            width: 100%;
            height: 8px;
            background: linear-gradient(90deg, #0000aa, #0088ff, #00ff00, #ffff00, #ff0000);
            border-radius: 4px;
        }
        .legend-labels {
            display: flex;
            justify-content: space-between;
            font-size: 11px;
            color: var(--text-dim);
            font-family: monospace;
        }

        /* 数据指标 */
        .metrics-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 12px;
        }
        .metric-box {
            background: rgba(0, 0, 0, 0.3);
            border: 1px solid rgba(255,255,255,0.05);
            padding: 10px;
            border-radius: 4px;
        }
        .metric-label {
            font-size: 11px;
            color: var(--text-dim);
            margin-bottom: 4px;
        }
        .metric-value {
            font-size: 16px;
            font-family: monospace;
            font-weight: bold;
            color: var(--text-main);
        }
        .metric-value.highlight {
            color: var(--accent);
            text-shadow: 0 0 8px var(--accent-glow);
        }

        /* 状态指示器 */
        .status-bar {
            display: flex;
            align-items: center;
            justify-content: space-between;
            font-size: 12px;
            margin-top: 10px;
            padding-top: 10px;
            border-top: 1px dashed rgba(255,255,255,0.1);
        }
        .status-dot {
            width: 8px;
            height: 8px;
            border-radius: 50%;
            background: #22c55e;
            box-shadow: 0 0 8px #22c55e;
            margin-right: 6px;
        }

        /* 绝对定位的浮动标签 (用于SVG物理区域解说) */
        .floating-label {
            position: absolute;
            font-size: 12px;
            color: var(--text-dim);
            background: rgba(0,0,0,0.6);
            border: 1px solid rgba(0,240,255,0.3);
            padding: 6px 10px;
            border-radius: 4px;
            pointer-events: none;
            backdrop-filter: blur(4px);
            white-space: nowrap;
        }
        .floating-label::after {
            content: '';
            position: absolute;
            width: 30px;
            height: 1px;
            background: var(--accent);
            top: 50%;
            left: -30px;
        }

        #label-sensor { top: 75%; left: 10%; }
        #label-sensor::after { width: 100px; transform: rotate(-15deg); transform-origin: right center; left: 100%; top: auto; bottom: 50%; }
        
        #label-mesh { top: 40%; left: 15%; }
        #label-mesh::after { width: 60px; transform: rotate(15deg); transform-origin: left center; left: 100%; top: 50%; }

        #label-bus { top: 85%; left: 35%; border-color: #a855f7; color: #d8b4fe; }
        #label-bus::after { background: #a855f7; width: 40px; transform: rotate(-45deg); transform-origin: right center; left: 100%; top: 0; }

        @keyframes pulse-dot {
            0%, 100% { opacity: 1; transform: scale(1); }
            50% { opacity: 0.5; transform: scale(0.8); }
        }

        @keyframes flow-data {
            0% { stroke-dashoffset: 20; }
            100% { stroke-dashoffset: 0; }
        }

    </style>
</head>
<body>

    <div id="visualization-container">
        
        <!-- 物理系统等距视图 SVG -->
        <svg id="simulation-svg" viewBox="0 0 1000 800" preserveAspectRatio="xMidYMid meet">
            <defs>
                <!-- 筛网材质 -->
                <pattern id="mesh-pattern" width="20" height="20" patternUnits="userSpaceOnUse">
                    <path d="M 20 0 L 0 0 0 20" fill="none" stroke="rgba(255,255,255,0.15)" stroke-width="1"/>
                    <path d="M 10 0 L 10 20 M 0 10 L 20 10" fill="none" stroke="rgba(255,255,255,0.05)" stroke-width="0.5"/>
                </pattern>
                
                <!-- 发光滤镜 -->
                <filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
                    <feGaussianBlur stdDeviation="5" result="blur" />
                    <feComposite in="SourceGraphic" in2="blur" operator="over" />
                </filter>
                <filter id="glow-strong" x="-50%" y="-50%" width="200%" height="200%">
                    <feGaussianBlur stdDeviation="12" result="blur" />
                    <feComponentTransfer in="blur" result="glow">
                        <feFuncA type="linear" slope="1.5"/>
                    </feComponentTransfer>
                    <feMerge>
                        <feMergeNode in="glow" />
                        <feMergeNode in="SourceGraphic" />
                    </feMerge>
                </filter>

                <!-- 渐变定义 -->
                <linearGradient id="liquid-grad" x1="0%" y1="0%" x2="0%" y2="100%">
                    <stop offset="0%" stop-color="rgba(0, 240, 255, 0.7)" />
                    <stop offset="100%" stop-color="rgba(0, 100, 255, 0.2)" />
                </linearGradient>
            </defs>

            <!-- 整体进行等距变换 -->
            <g transform="translate(500, 200) scale(1, 0.5) rotate(45)">
                
                <!-- 底部:结构基座与CAN总线 -->
                <rect x="-320" y="-220" width="640" height="440" fill="rgba(5, 10, 20, 0.8)" stroke="rgba(255,255,255,0.1)" rx="10"/>
                
                <!-- 数据传输总线 (CAN Bus) -->
                <path id="can-bus-line" d="M -300 240 L 300 240 L 350 290 L 600 290" fill="none" stroke="#a855f7" stroke-width="4" stroke-dasharray="10,5" filter="url(#glow)"/>
                <circle cx="300" cy="240" r="4" fill="#a855f7" filter="url(#glow)"/>
                
                <g id="data-pulses"></g>

                <!-- 第2层:PCB传感器阵列 (2xN 实际渲染为更密集的矩阵以展示原理) -->
                <rect x="-300" y="-200" width="600" height="400" fill="var(--pcb-color)" stroke="#064e3b" stroke-width="4" rx="5"/>
                
                <!-- 传感器矩阵 (由JS动态生成填充) -->
                <g id="sensor-matrix"></g>

                <!-- 物理扫描线 (在PCB上方) -->
                <rect id="physical-scanner" x="-300" y="-200" width="15" height="400" fill="rgba(0, 240, 255, 0.4)" filter="url(#glow-strong)"/>
                <line id="physical-scanner-line" x1="-292.5" y1="-200" x2="-292.5" y2="200" stroke="#fff" stroke-width="2" filter="url(#glow)"/>

                <!-- 悬浮层结构支撑 -->
                <g stroke="rgba(255,255,255,0.2)" stroke-width="2" stroke-dasharray="5,5">
                    <line x1="-300" y1="-200" x2="-300" y2="-200" transform="translate(0, 0) scale(1, 2) rotate(-45)"/> <!-- 伪3D立柱,用绝对位移代替 -->
                </g>

            </g>
            
            <!-- 绘制垂直连接柱 (连接PCB和筛网) -->
            <path d="M 197 200 L 197 100 M 803 200 L 803 100 M 197 800 L 197 700 M 803 800 L 803 700" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="2" stroke-dasharray="4,4"/>

            <g transform="translate(500, 100) scale(1, 0.5) rotate(45)">
                <!-- 第3层:筛网 (Mesh) -->
                <rect x="-320" y="-220" width="640" height="440" fill="url(#mesh-pattern)" stroke="rgba(148, 163, 184, 0.8)" stroke-width="3"/>
                <!-- 筛网边框高光 -->
                <rect x="-320" y="-220" width="640" height="440" fill="none" stroke="var(--accent)" stroke-width="1" filter="url(#glow)"/>

                <!-- 第4层:动态液膜 (Liquid Film) - 由多条曲线构成的曲面 -->
                <g id="liquid-surface-group" transform="translate(0, 0)"></g>
            </g>

        </svg>

        <!-- 悬浮解说标签 -->
        <div class="floating-label" id="label-mesh">工业振动筛网 (不适用严重金属粘结)</div>
        <div class="floating-label" id="label-sensor">下方底置: 2×N 微波/电容分布阵列<br><span style="font-size:10px; color:#64748b;">空间分辨率: 100mm | 周期: 200ms</span></div>
        <div class="floating-label" id="label-bus">CAN总线高速采集回传</div>

        <!-- 右侧数据看板 -->
        <div class="dashboard">
            <div class="panel">
                <div class="panel-header">实时液膜分布等高线映射</div>
                
                <!-- 核心:二维液膜热力图 -->
                <div id="heatmap-container">
                    <div id="heatmap-scanner"></div>
                    <!-- 单元格由JS生成 -->
                </div>

                <div class="legend">
                    <div class="legend-bar"></div>
                    <div class="legend-labels">
                        <span>薄 (介电常数低)</span>
                        <span>平衡态</span>
                        <span>堆积 (介电常数高)</span>
                    </div>
                </div>
            </div>

            <div class="panel">
                <div class="panel-header">阵列扫描控制终端 (PLC)</div>
                <div class="metrics-grid">
                    <div class="metric-box">
                        <div class="metric-label">矩阵扫描周期 (ms)</div>
                        <div class="metric-value highlight">200.0</div>
                    </div>
                    <div class="metric-value metric-box">
                        <div class="metric-label">空间分辨率 (mm)</div>
                        <div class="metric-value">100.0</div>
                    </div>
                    <div class="metric-box">
                        <div class="metric-label">区域平衡度指标 (RBI)</div>
                        <div class="metric-value" id="rbi-value">0.85</div>
                    </div>
                    <div class="metric-box">
                        <div class="metric-label">当前扫描列 (Col)</div>
                        <div class="metric-value highlight" id="col-value">01</div>
                    </div>
                </div>

                <div class="status-bar">
                    <div style="display:flex; align-items:center;">
                        <div class="status-dot"></div>
                        <span>电容矩阵传感在线</span>
                    </div>
                    <span style="color:var(--text-dim); font-family:monospace;">SYS_RUNNING</span>
                </div>
            </div>
        </div>

    </div>

    <script>
        document.addEventListener('DOMContentLoaded', () => {
            // 系统参数
            const ROWS = 12; // 对应热力图高度
            const COLS = 16; // 对应热力图宽度 (模拟2xN阵列的细分扫描)
            const SENSOR_WIDTH = 600;
            const SENSOR_HEIGHT = 400;
            const CELL_W = SENSOR_WIDTH / COLS;
            const CELL_H = SENSOR_HEIGHT / ROWS;
            const SCAN_PERIOD = 2000; // 动画视觉周期设为2s,对应实际200ms,方便人眼观察

            // DOM 元素
            const sensorMatrixGroup = document.getElementById('sensor-matrix');
            const liquidSurfaceGroup = document.getElementById('liquid-surface-group');
            const heatmapContainer = document.getElementById('heatmap-container');
            const heatmapScanner = document.getElementById('heatmap-scanner');
            const physicalScanner = document.getElementById('physical-scanner');
            const colValueEl = document.getElementById('col-value');
            const rbiValueEl = document.getElementById('rbi-value');
            const dataPulsesGroup = document.getElementById('data-pulses');

            // 状态数据
            let liquidData = Array.from({length: ROWS}, () => new Array(COLS).fill(0));
            let heatmapCells = [];
            let physicalSensors = [];
            let time = 0;
            let currentScanCol = 0;

            // 颜色映射函数 (Jet Colormap: Blue -> Cyan -> Green -> Yellow -> Red)
            function getHeatmapColor(value) {
                // value: 0 to 1
                let r = 0, g = 0, b = 0;
                if (value < 0.25) {
                    r = 0; g = 4 * value; b = 1;
                } else if (value < 0.5) {
                    r = 0; g = 1; b = 1 - 4 * (value - 0.25);
                } else if (value < 0.75) {
                    r = 4 * (value - 0.5); g = 1; b = 0;
                } else {
                    r = 1; g = 1 - 4 * (value - 0.75); b = 0;
                }
                return `rgb(${Math.floor(r*255)}, ${Math.floor(g*255)}, ${Math.floor(b*255)})`;
            }

            // 初始化物理传感器阵列 (SVG) 和 热力图网格 (HTML)
            function initSystem() {
                // 热力图扫描器置顶
                heatmapContainer.appendChild(heatmapScanner);

                for (let r = 0; r < ROWS; r++) {
                    physicalSensors[r] = [];
                    for (let c = 0; c < COLS; c++) {
                        // 1. 初始化热力图单元格
                        const cell = document.createElement('div');
                        cell.className = 'heatmap-cell';
                        heatmapContainer.appendChild(cell);
                        heatmapCells.push(cell);

                        // 2. 初始化物理传感器 (PCB上的焊盘/感应区)
                        // 为了贴合2xN的说明,我们在视觉上将它们分组
                        const isMainSensor = (r % 3 === 1); 
                        
                        const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
                        rect.setAttribute('x', -SENSOR_WIDTH/2 + c * CELL_W + 2);
                        rect.setAttribute('y', -SENSOR_HEIGHT/2 + r * CELL_H + 2);
                        rect.setAttribute('width', CELL_W - 4);
                        rect.setAttribute('height', CELL_H - 4);
                        rect.setAttribute('rx', 2);
                        rect.setAttribute('fill', isMainSensor ? '#047857' : '#022c22'); 
                        rect.setAttribute('stroke', isMainSensor ? '#10b981' : 'none');
                        rect.setAttribute('stroke-width', '0.5');
                        rect.style.transition = 'fill 0.1s, filter 0.1s';
                        
                        sensorMatrixGroup.appendChild(rect);
                        physicalSensors[r][c] = rect;
                    }
                }

                // 初始化液膜表面路径 (每一行一条折线/曲线,堆叠表现厚度)
                // 由于是在等距视图中,我们通过改变等距平面的Z轴(或者说相对位移)来表现高度
                // 巧妙利用路径填充来模拟体积
            }

            // 生成动态液膜数据 (模拟非均匀分布的流动)
            function updateLiquidData() {
                time += 0.05;
                let totalDepth = 0;
                let maxDepth = 0.001;

                for (let r = 0; r < ROWS; r++) {
                    for (let c = 0; c < COLS; c++) {
                        // 混合多个正弦波模拟复杂的流体表面形态
                        const wave1 = Math.sin(c * 0.4 + time * 2);
                        const wave2 = Math.cos(r * 0.5 - time * 1.5);
                        const wave3 = Math.sin((c + r) * 0.3 + time);
                        
                        // 制造一个局部堆积区 (矛盾点:分布不均)
                        const accumulation = Math.exp(-((c - 10)**2 + (r - 6)**2) / 10) * 0.8;
                        
                        // 归一化到 0~1
                        let depth = (wave1 * 0.2 + wave2 * 0.2 + wave3 * 0.1 + 0.5) + accumulation;
                        depth = Math.max(0, Math.min(1, depth)); // 钳制在0-1
                        
                        liquidData[r][c] = depth;
                        totalDepth += depth;
                        if(depth > maxDepth) maxDepth = depth;
                    }
                }

                // 计算区域平衡度指标 (RBI) - 简化的方差概念
                const avg = totalDepth / (ROWS * COLS);
                let variance = 0;
                for (let r = 0; r < ROWS; r++) {
                    for (let c = 0; c < COLS; c++) {
                        variance += Math.pow(liquidData[r][c] - avg, 2);
                    }
                }
                const rbi = 1 - Math.sqrt(variance / (ROWS * COLS));
                rbiValueEl.innerText = rbi.toFixed(3);
                rbiValueEl.style.color = rbi < 0.6 ? varwarn : (rbi > 0.8 ? 'var(--accent)' : 'var(--text-main)');
            }

            // 渲染物理液膜曲面 (基于数据生成SVG Path)
            function renderLiquidSurface() {
                liquidSurfaceGroup.innerHTML = '';
                
                // 为了性能和效果,我们画条带或者多边形
                for (let r = 0; r < ROWS; r++) {
                    let d = `M -${SENSOR_WIDTH/2} ${-SENSOR_HEIGHT/2 + r * CELL_H + CELL_H/2} `;
                    
                    for (let c = 0; c < COLS; c++) {
                        const val = liquidData[r][c];
                        const x = -SENSOR_WIDTH/2 + c * CELL_W + CELL_W/2;
                        // 高度映射到等距投影的左上方向 (-x, -y 在视口直角坐标系中,但因为父级旋转,我们只需改变局部相对位置。
                        // 简化处理:由于父级包含 scale(1, 0.5) rotate(45),要在Z轴隆起,需要对坐标做逆运算。
                        // 更简单的视觉欺骗:沿着局部X/Y轴反向偏移产生“鼓起”效果。
                        // 真正的垂直鼓起需要沿 (-1, -1) 方向移动。
                        const heightOffset = val * 60; // 最大隆起高度
                        const px = x - heightOffset;
                        const py = -SENSOR_HEIGHT/2 + r * CELL_H + CELL_H/2 - heightOffset;
                        
                        d += `L ${px} ${py} `;
                    }
                    // 闭合到底部形成体积感
                    d += `L ${SENSOR_WIDTH/2} ${-SENSOR_HEIGHT/2 + r * CELL_H + CELL_H/2} `;
                    
                    const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
                    path.setAttribute('d', d);
                    path.setAttribute('fill', 'none');
                    // 基于该行平均高度上色
                    const avgVal = liquidData[r].reduce((a,b)=>a+b,0)/COLS;
                    path.setAttribute('stroke', `rgba(0, 200, 255, ${0.3 + avgVal*0.5})`);
                    path.setAttribute('stroke-width', '4');
                    // path.style.filter = 'url(#glow)';
                    
                    // 添加一层半透明填充制造水体感
                    const fillPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
                    const dFill = d + `L ${SENSOR_WIDTH/2} ${-SENSOR_HEIGHT/2 + (r+1) * CELL_H} L -${SENSOR_WIDTH/2} ${-SENSOR_HEIGHT/2 + (r+1) * CELL_H} Z`;
                    fillPath.setAttribute('d', dFill);
                    fillPath.setAttribute('fill', `rgba(0, 150, 255, ${0.1 + avgVal*0.2})`);
                    
                    liquidSurfaceGroup.appendChild(fillPath);
                    liquidSurfaceGroup.appendChild(path);
                }
            }

            // 发送数据脉冲动画 (模拟CAN总线传输)
            function fireDataPulse() {
                const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
                circle.setAttribute('cx', '-300');
                circle.setAttribute('cy', '240');
                circle.setAttribute('r', '5');
                circle.setAttribute('fill', '#a855f7');
                circle.setAttribute('filter', 'url(#glow-strong)');
                dataPulsesGroup.appendChild(circle);

                // 使用Web Animations API
                const animation = circle.animate([
                    { transform: 'translate(0, 0)' },
                    { transform: 'translate(600px, 0)' }, // 沿X移动,然后折线部分简化处理或只展示前半段
                    { transform: 'translate(650px, 50px)' },
                    { transform: 'translate(900px, 50px)' }
                ], {
                    duration: 600,
                    easing: 'linear'
                });

                animation.onfinish = () => circle.remove();
            }

            // 主动画循环
            let lastScanTime = 0;
            
            function animate(timestamp) {
                updateLiquidData();
                renderLiquidSurface();

                // 处理扫描逻辑
                const scanProgress = (timestamp % SCAN_PERIOD) / SCAN_PERIOD; // 0 to 1
                const targetCol = Math.floor(scanProgress * COLS);

                // 物理扫描线平滑移动
                const scanX = -SENSOR_WIDTH/2 + scanProgress * SENSOR_WIDTH;
                physicalScanner.setAttribute('x', scanX);
                document.getElementById('physical-scanner-line').setAttribute('x1', scanX + 7.5);
                document.getElementById('physical-scanner-line').setAttribute('x2', scanX + 7.5);
                
                // UI界面扫描线平滑移动
                heatmapScanner.style.transform = `translateX(${scanProgress * 100 * COLS}%)`;

                // 当扫描列切换时触发数据采集动作
                if (targetCol !== currentScanCol) {
                    currentScanCol = targetCol;
                    colValueEl.innerText = (currentScanCol + 1).toString().padStart(2, '0');
                    fireDataPulse();

                    // 更新热力图颜色并点亮物理传感器
                    for (let r = 0; r < ROWS; r++) {
                        const val = liquidData[r][currentScanCol];
                        const color = getHeatmapColor(val);
                        
                        // 1. 更新热力图该列
                        const cellIndex = r * COLS + currentScanCol;
                        heatmapCells[cellIndex].style.backgroundColor = color;
                        heatmapCells[cellIndex].style.boxShadow = `0 0 10px ${color}`;
                        
                        // 渐隐尾迹效果
                        setTimeout(() => {
                            if(heatmapCells[cellIndex]) heatmapCells[cellIndex].style.boxShadow = 'none';
                        }, 300);

                        // 2. 物理传感器瞬间高亮 (模拟电容充放电测量)
                        const pSensor = physicalSensors[r][currentScanCol];
                        pSensor.setAttribute('fill', '#00f0ff');
                        pSensor.setAttribute('filter', 'url(#glow-strong)');
                        
                        setTimeout(() => {
                            const isMainSensor = (r % 3 === 1); 
                            pSensor.setAttribute('fill', isMainSensor ? '#047857' : '#022c22');
                            pSensor.removeAttribute('filter');
                        }, 150); // 短暂亮起后熄灭
                    }
                }

                requestAnimationFrame(animate);
            }

            // 启动
            initSystem();
            requestAnimationFrame(animate);
        });
    </script>
</body>
</html>
积分规则:每轮对话扣10分