当前位置: 首页 > ai >正文

18、时序数据库 (TSDB) 存储高密度传感器数据组件 - /数据与物联网组件/tsdb-power-plant-archive

76个工业组件库示例汇总

时序数据库 (TSDB) 存储高密度传感器数据组件 (模拟)

概述

这是一个交互式的 Web 组件,用于模拟从时序数据库 (Time Series Database, TSDB) 查询和展示发电厂高密度温度传感器历史数据的场景。用户可以选择不同的温度测点,定义一个时间范围,然后模拟执行查询,并查看结果的统计摘要、数据样本以及一个预留的趋势图区域。

请注意:这是一个前端模拟演示,它不连接任何真实的数据库,所有数据和查询延迟都是在浏览器端模拟生成的。

主要功能

  • 模拟 TSDB 查询: 模拟针对高密度传感器数据的历史查询过程。
  • 传感器选择: 提供多个预定义的发电厂温度测点供用户选择。
  • 时间范围定义: 允许用户通过日期时间选择器指定查询的开始和结束时间。
  • 查询执行与状态反馈:
    • 点击按钮触发模拟查询。
    • 显示查询状态(查询中、完成、无数据、失败)和加载指示器。
    • 模拟网络和数据库处理的延迟。
  • 结果展示:
    • 统计摘要: 显示查询时间范围内数据的最小值、最大值、平均值和数据点总数。
    • 数据样本: 以表格形式展示少量(首尾)查询到的数据点(时间戳和数值)。
    • 趋势图占位符: 预留了用于展示温度变化趋势图的区域(当前未实现具体图表绘制)。
  • 模拟数据归档: 右上角计数器持续增加,模拟传感器数据不断被写入 TSDB。
  • 界面风格: 采用苹果科技风格,布局简洁,响应式设计。

如何使用

  1. 打开页面: 在浏览器中打开 index.html
  2. 查看默认状态: 页面加载后,会显示默认选中的测点和过去一小时的时间范围。
  3. 选择测点: 从"选择温度测点"下拉菜单中选择你感兴趣的传感器。
  4. 定义时间范围: 使用日期时间选择器设置查询的"开始时间"和"结束时间"。确保开始时间早于结束时间,否则"查询"按钮将不可用。
  5. 执行查询: 点击"查询历史数据"按钮。
  6. 观察结果:
    • 查询状态会更新,并显示加载动画。
    • 模拟延迟后,结果区域会显示所选测点的统计摘要和数据样本。
    • 如果时间范围过短或模拟逻辑未生成数据,会提示"无数据"。

模拟细节

  • 数据生成: 查询时,脚本会根据所选测点的预设参数(基础值、波动幅度、噪声)和时间范围,通过叠加正弦波(模拟日周期和小时周期)和随机噪声来动态生成模拟温度数据。每个测点的参数不同,以产生不同的数据模式。
  • 归档计数: 右上角的"已归档数据点"是一个纯粹的视觉模拟,表示数据在持续写入,其增长速度与实际查询生成的数据量无关。
  • 查询延迟: 查询按钮按下后,会有一个 0.5 到 2 秒的随机延迟,用以模拟真实查询所需的时间。
  • 数据密度: 模拟生成数据时,尝试模拟约每 5 秒一个数据点,但查询返回的总点数上限为 5000 个,以避免浏览器性能问题。

文件结构

数据与物联网组件/tsdb-power-plant-archive/
├── index.html         # 组件的 HTML 结构
├── styles.css         # 组件的 CSS 样式
├── script.js          # 组件的 JavaScript 逻辑(模拟查询、数据生成、交互)
└── README.md          # 本说明文件

技术栈

  • HTML5
  • CSS3 (使用了 CSS 变量, Flexbox/Grid 布局)
  • JavaScript (原生 JS, 无外部库依赖)

效果展示

在这里插入图片描述

源码

index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>TSDB - 发电厂历史温度归档</title><link rel="stylesheet" href="styles.css"><!-- Placeholder for potential charting library -->
</head>
<body><div class="tsdb-container"><header class="main-header"><h1>时序数据库 - 发电厂温度数据归档模拟</h1><div class="header-info"><span title="Simulated number of data points archived since page load">模拟已归档点数: <span id="archivedPointsCounter">0</span></span><span>时间: <span id="currentTime">--:--:--</span></span></div></header><main class="main-content"><!-- Column 1: Sensor Selection & Query Params --><section class="query-params-section"><h2><i class="icon icon-tag"></i> 查询参数</h2><div class="param-group"><label for="sensorSelect"><i class="icon icon-sensor"></i> 选择温度测点:</label><select id="sensorSelect"><option value="" disabled selected>-- 请选择测点 --</option><!-- Options populated by JS --></select></div><div class="param-group"><label><i class="icon icon-time"></i> 选择时间范围:</label><div class="time-inputs"><div><label for="startTime">开始时间:</label><input type="datetime-local" id="startTime" name="startTime"></div><div><label for="endTime">结束时间:</label><input type="datetime-local" id="endTime" name="endTime"></div></div></div><div class="param-group action-group"><button id="queryButton" class="action-button" disabled><i class="icon icon-query"></i> 查询历史数据</button><div class="query-status">状态: <span id="queryStatus" class="status-idle">空闲</span><span id="querySpinner" class="spinner" style="display: none;"></span></div></div></section><!-- Column 2: Query Results --><section class="results-section"><h2><i class="icon icon-results"></i> 查询结果 (<span id="selectedSensorDisplay">未选择测点</span>)</h2><div id="resultsPlaceholder" class="placeholder-results">请选择测点和时间范围,然后点击查询。</div><div id="resultsContent" style="display: none;"><div class="summary-stats"><h3><i class="icon icon-stats"></i> 统计摘要</h3><div class="stats-grid"><div class="stat-item"><span>最低温度 (°C):</span> <strong id="statMinTemp">--</strong></div><div class="stat-item"><span>最高温度 (°C):</span> <strong id="statMaxTemp">--</strong></div><div class="stat-item"><span>平均温度 (°C):</span> <strong id="statAvgTemp">--</strong></div><div class="stat-item"><span>模拟点数:</span> <strong id="statPointCount">--</strong></div></div></div><div class="sample-data"><h3><i class="icon icon-table"></i> 数据抽样 (模拟)</h3><div class="table-container"><table><thead><tr><th>时间戳</th><th>温度值 (°C)</th></tr></thead><tbody id="sampleDataTableBody"><!-- Sample rows populated by JS --><tr><td colspan="2" class="placeholder">暂无数据</td></tr></tbody></table></div></div><div class="trend-chart"><h3><i class="icon icon-chart"></i> 温度趋势 (模拟)</h3><div class="chart-placeholder" id="tempTrendChart"><p>温度变化趋势图</p><div class="fake-chart tsdb-trend"></div></div></div></div></section></main><footer class="main-footer"><p>&copy; 2024 模拟 TSDB 查询系统. 概念演示.</p></footer></div><script src="script.js"></script>
</body>
</html> 

styles.css

:root {--background-color: #f0f2f5;--container-bg: #ffffff;--header-bg: #6c757d; /* Neutral grey header */--header-text: #ffffff;--section-border: #dee2e6;--input-bg: #ffffff;--input-border: #ced4da;--input-focus-border: #86b7fe;--input-focus-shadow: rgba(13, 110, 253, 0.25);--button-bg: #0d6efd;--button-hover-bg: #0b5ed7;--button-disabled-bg: #adb5bd;--text-primary: #212529;--text-secondary: #6c757d;--text-label: #495057;--value-color: #000000;--status-idle: var(--text-secondary);--status-querying: #ffc107; /* Yellow */--status-done: #198754; /* Green */--status-error: #dc3545; /* Red */--placeholder-bg: #f8f9fa;--table-header-bg: #f1f3f5;--table-row-hover-bg: #e9ecef;--chart-placeholder-bg: #f8f9fa;--spinner-color: var(--button-bg);--font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;--border-radius: 6px;--box-shadow: 0 1px 3px rgba(0, 0, 0, 0.07);
}* {box-sizing: border-box;margin: 0;padding: 0;
}body {font-family: var(--font-family);background-color: var(--background-color);color: var(--text-primary);line-height: 1.5;overflow-x: hidden;
}.tsdb-container {max-width: 1400px;margin: 1rem auto;background-color: var(--container-bg);border-radius: var(--border-radius);box-shadow: var(--box-shadow);overflow: hidden;display: flex;flex-direction: column;min-height: calc(100vh - 2rem);max-height: calc(100vh - 2rem);height: 750px; /* Adjust height as needed */
}/* Header */
.main-header {background-color: var(--header-bg);color: var(--header-text);padding: 0.7rem 1.5rem;display: flex;justify-content: space-between;align-items: center;flex-shrink: 0;border-bottom: 1px solid rgba(0,0,0,0.1);
}.main-header h1 {font-size: 1.25rem;font-weight: 500;
}.header-info span {margin-left: 1.5rem;font-size: 0.85rem;opacity: 0.9;
}/* Main Content Layout */
.main-content {flex-grow: 1;padding: 1rem;overflow: hidden;display: grid;grid-template-columns: 400px 1fr; /* Fixed width for params, flexible results */gap: 1rem;
}/* Query Parameters Section */
.query-params-section {background-color: #fdfdfd;border: 1px solid var(--section-border);border-radius: var(--border-radius);padding: 1.2rem;display: flex;flex-direction: column;gap: 1.5rem;overflow-y: auto;
}.query-params-section h2,
.results-section h2 {font-size: 1.15rem;font-weight: 500;margin-bottom: 0.5rem;padding-bottom: 0.6rem;border-bottom: 1px solid var(--section-border);display: flex;align-items: center;color: var(--text-primary);flex-shrink: 0;
}.query-params-section h2 .icon,
.results-section h2 .icon {margin-right: 0.6rem;font-size: 1.05em;
}.param-group {display: flex;flex-direction: column;gap: 0.5rem;
}.param-group > label:first-child {font-weight: 500;color: var(--text-label);font-size: 0.9rem;display: flex;align-items: center;
}.param-group > label:first-child .icon {margin-right: 0.4rem;
}select,
input[type="datetime-local"] {width: 100%;padding: 0.5rem 0.75rem;font-size: 0.9rem;border: 1px solid var(--input-border);border-radius: var(--border-radius);background-color: var(--input-bg);transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
}select:focus,
input[type="datetime-local"]:focus {border-color: var(--input-focus-border);outline: 0;box-shadow: 0 0 0 0.2rem var(--input-focus-shadow);
}.time-inputs {display: flex;flex-direction: column;gap: 0.5rem;padding-left: 1.5rem; /* Indent time inputs */
}.time-inputs div {display: flex;flex-direction: column;gap: 0.2rem;
}.time-inputs label {font-size: 0.8rem;color: var(--text-secondary);
}.action-group {margin-top: 1rem;padding-top: 1rem;border-top: 1px dashed var(--section-border);align-items: center;flex-direction: row;justify-content: space-between;
}.action-button {display: inline-flex;align-items: center;justify-content: center;gap: 0.4rem;background-color: var(--button-bg);color: white;border: none;padding: 0.6rem 1.2rem;border-radius: var(--border-radius);cursor: pointer;font-size: 0.95rem;font-weight: 500;transition: background-color 0.2s ease;flex-shrink: 0;
}.action-button:hover:not(:disabled) {background-color: var(--button-hover-bg);
}.action-button:disabled {background-color: var(--button-disabled-bg);cursor: not-allowed;
}.query-status {font-size: 0.85rem;color: var(--text-secondary);display: flex;align-items: center;gap: 0.5rem;
}#queryStatus {font-weight: 500;
}
#queryStatus.status-idle { color: var(--status-idle); }
#queryStatus.status-querying { color: var(--status-querying); }
#queryStatus.status-done { color: var(--status-done); }
#queryStatus.status-error { color: var(--status-error); }/* Spinner */
.spinner {border: 3px solid rgba(0, 0, 0, 0.1);border-left-color: var(--spinner-color);border-radius: 50%;width: 16px;height: 16px;animation: spin 1s linear infinite;
}@keyframes spin {0% { transform: rotate(0deg); }100% { transform: rotate(360deg); }
}/* Results Section */
.results-section {background-color: #fdfdfd;border: 1px solid var(--section-border);border-radius: var(--border-radius);padding: 1.2rem;display: flex;flex-direction: column;overflow-y: auto;
}.results-section h2 #selectedSensorDisplay {font-weight: normal;color: var(--text-secondary);font-size: 0.9em;margin-left: 0.3rem;
}.placeholder-results {flex-grow: 1;display: flex;align-items: center;justify-content: center;color: var(--text-secondary);font-style: italic;text-align: center;background-color: var(--placeholder-bg);border-radius: var(--border-radius);
}#resultsContent {display: flex; /* Changed from none initially */flex-direction: column;gap: 1.5rem;/* flex-grow: 1; */
}.results-section h3 {font-size: 1rem;font-weight: 500;margin-bottom: 0.8rem;display: flex;align-items: center;color: var(--text-label);
}.results-section h3 .icon {margin-right: 0.5rem;font-size: 1em;
}/* Summary Stats */
.summary-stats {background-color: var(--widget-bg);padding: 1rem;border-radius: var(--border-radius);border: 1px solid var(--widget-border);
}.stats-grid {display: grid;grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));gap: 0.5rem 1rem;
}.stat-item {font-size: 0.9rem;
}.stat-item span {color: var(--text-secondary);margin-right: 0.4rem;
}.stat-item strong {font-weight: 600;color: var(--value-color);
}/* Sample Data Table */
.sample-data {background-color: var(--widget-bg);padding: 1rem;border-radius: var(--border-radius);border: 1px solid var(--widget-border);
}.table-container {max-height: 200px; /* Limit table height */overflow-y: auto;border: 1px solid var(--section-border);border-radius: var(--border-radius);
}table {width: 100%;border-collapse: collapse;
}thead th {background-color: var(--table-header-bg);padding: 0.6rem 0.8rem;text-align: left;font-size: 0.8rem;font-weight: 600;color: var(--text-secondary);border-bottom: 1px solid var(--section-border);position: sticky; /* Keep header visible */top: 0;
}tbody td {padding: 0.5rem 0.8rem;font-size: 0.85rem;border-bottom: 1px solid var(--section-border);
}tbody tr:last-child td {border-bottom: none;
}tbody tr:hover {background-color: var(--table-row-hover-bg);
}/* Trend Chart */
.trend-chart {background-color: var(--widget-bg);padding: 1rem;border-radius: var(--border-radius);border: 1px solid var(--widget-border);
}.chart-placeholder {background-color: var(--chart-placeholder-bg);border-radius: var(--border-radius);padding: 1rem;display: flex;flex-direction: column;align-items: center;justify-content: center;border: 1px solid var(--widget-border);min-height: 150px;position: relative;
}.chart-placeholder p {font-size: 0.85rem;color: var(--text-secondary);margin-bottom: 0.5rem;font-weight: 500;
}.fake-chart.tsdb-trend {width: 95%;height: 70%;border: 1px dashed var(--text-secondary);position: relative;overflow: hidden;
}.fake-chart.tsdb-trend::after {content: '';position: absolute;top: 0;left: 0;width: 100%;height: 100%;background: linear-gradient(to right, transparent, rgba(220, 53, 69, 0.1), rgba(255, 193, 7, 0.15), rgba(13, 110, 253, 0.1), transparent);animation: fakeTrendPulse 8s ease-in-out infinite;
}@keyframes fakeTrendPulse {0% { transform: scaleY(0.5) translateY(30%); opacity: 0.4; }50% { transform: scaleY(1) translateY(0); opacity: 0.7; }100% { transform: scaleY(0.5) translateY(30%); opacity: 0.4; }
}/* Footer */
.main-footer {background-color: #f8f8f8;padding: 0.5rem 1.5rem;text-align: center;font-size: 0.8rem;color: var(--text-secondary);border-top: 1px solid var(--section-border);flex-shrink: 0;
}/* Responsive Design */
@media (max-width: 992px) {.main-content {grid-template-columns: 1fr; /* Stack columns */grid-template-rows: auto 1fr;}.query-params-section { grid-row: 1; }.results-section { grid-row: 2; }.tsdb-container {max-height: none;height: auto;margin: 0.5rem;}.stats-grid {grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));}
}@media (max-width: 768px) {.main-content {padding: 0.8rem;gap: 0.8rem;}.query-params-section, .results-section {padding: 1rem;}.action-group {flex-direction: column;align-items: stretch;gap: 0.8rem;}.query-status {justify-content: center;margin-top: 0.5rem;}.main-header {padding: 0.6rem 1rem;}.main-header h1 {font-size: 1.1rem;}
}/* Basic Icon Placeholders */
.icon::before {display: inline-block;font-weight: normal;font-style: normal;font-variant: normal;text-rendering: auto;-webkit-font-smoothing: antialiased;margin-right: 0.3em;
}
.icon-tag::before { content: "🏷️"; }
.icon-sensor::before { content: "🌡️"; } /* Thermometer */
.icon-time::before { content: "⏱️"; }
.icon-query::before { content: "🔍"; }
.icon-results::before { content: "📊"; }
.icon-stats::before { content: "🔢"; }
.icon-table::before { content: "📋"; }
.icon-chart::before { content: "📈"; } 

script.js

// script.js - TSDB Power Plant Archive Componentdocument.addEventListener('DOMContentLoaded', () => {// --- DOM Elements ---const currentTimeEl = document.getElementById('currentTime');const archivedPointsCounterEl = document.getElementById('archivedPointsCounter');const sensorSelect = document.getElementById('sensorSelect');const startTimeInput = document.getElementById('startTime');const endTimeInput = document.getElementById('endTime');const queryButton = document.getElementById('queryButton');const queryStatusEl = document.getElementById('queryStatus');const querySpinnerEl = document.getElementById('querySpinner');const selectedSensorDisplayEl = document.getElementById('selectedSensorDisplay');const resultsPlaceholderEl = document.getElementById('resultsPlaceholder');const resultsContentEl = document.getElementById('resultsContent');const statMinTempEl = document.getElementById('statMinTemp');const statMaxTempEl = document.getElementById('statMaxTemp');const statAvgTempEl = document.getElementById('statAvgTemp');const statPointCountEl = document.getElementById('statPointCount');const sampleDataTableBody = document.getElementById('sampleDataTableBody');// Chart placeholder elements are not directly manipulated in this simulation// --- Simulation State & Parameters ---let simulationTime = new Date();let archivedPoints = 0;let isQuerying = false;const sensors = {'Boiler_ZoneA_Temp': { name: '锅炉区域A温度', base: 600, amplitude: 25, noise: 5 },'Boiler_ZoneB_Temp': { name: '锅炉区域B温度', base: 650, amplitude: 30, noise: 6 },'Turbine_Inlet_Temp': { name: '汽轮机入口温度', base: 550, amplitude: 15, noise: 3 },'Condenser_Outlet_Temp': { name: '冷凝器出口温度', base: 45, amplitude: 5, noise: 1 },'Feedwater_Heater_Temp': { name: '给水加热器温度', base: 180, amplitude: 10, noise: 2 }};// Update intervalsconst timeUpdateInterval = 1000;const archiveInterval = 100; // Simulate points archiving quickly// --- Initialization ---function initializeTSDBMonitor() {populateSensorSelect();setDefaultTimeRange();setupEventListeners();updateTime();setInterval(updateTime, timeUpdateInterval);// Start simulated archivingsetInterval(() => {archivedPoints += Math.floor(Math.random() * 5 + 1); // Archive 1-5 points per intervalarchivedPointsCounterEl.textContent = archivedPoints.toLocaleString();}, archiveInterval);validateInputs(); // Initial validation checkconsole.log("TSDB Monitor Initialized");}function populateSensorSelect() {for (const tag in sensors) {const option = document.createElement('option');option.value = tag;option.textContent = `${sensors[tag].name} (${tag})`;sensorSelect.appendChild(option);}}function setDefaultTimeRange() {const now = new Date();const oneHourAgo = new Date(now.getTime() - 60 * 60 * 1000);// Format for datetime-local input (YYYY-MM-DDTHH:mm)endTimeInput.value = formatDateForInput(now);startTimeInput.value = formatDateForInput(oneHourAgo);}function formatDateForInput(date) {const year = date.getFullYear();const month = String(date.getMonth() + 1).padStart(2, '0');const day = String(date.getDate()).padStart(2, '0');const hours = String(date.getHours()).padStart(2, '0');const minutes = String(date.getMinutes()).padStart(2, '0');return `${year}-${month}-${day}T${hours}:${minutes}`;}// --- Event Handlers ---function setupEventListeners() {sensorSelect.addEventListener('change', validateInputs);startTimeInput.addEventListener('change', validateInputs);endTimeInput.addEventListener('change', validateInputs);queryButton.addEventListener('click', handleQuery);}function validateInputs() {const sensorSelected = sensorSelect.value !== '';const startTimeValid = startTimeInput.value !== '';const endTimeValid = endTimeInput.value !== '';let timeRangeValid = false;if (startTimeValid && endTimeValid) {const start = new Date(startTimeInput.value);const end = new Date(endTimeInput.value);timeRangeValid = start < end;}queryButton.disabled = !(sensorSelected && timeRangeValid);return sensorSelected && timeRangeValid;}function handleQuery() {if (isQuerying || !validateInputs()) {return;}isQuerying = true;setQueryStatus('querying', '查询中...');resultsPlaceholderEl.style.display = 'none'; // Hide placeholder immediatelyresultsContentEl.style.display = 'none'; // Hide old resultssampleDataTableBody.innerHTML = '<tr><td colspan="2" class="placeholder">生成数据中...</td></tr>'; // Clear tableconst selectedTag = sensorSelect.value;const sensorInfo = sensors[selectedTag];selectedSensorDisplayEl.textContent = sensorInfo ? sensorInfo.name : '未知测点';// Simulate network/DB delayconst queryDelay = Math.random() * 1500 + 500; // 0.5s to 2s delaysetTimeout(() => {try {const startTime = new Date(startTimeInput.value);const endTime = new Date(endTimeInput.value);const simulatedData = generateSimulatedData(sensorInfo, startTime, endTime);if (simulatedData.length === 0) {setQueryStatus('error', '无数据');resultsPlaceholderEl.textContent = `在选定时间范围 (${startTime.toLocaleString()} - ${endTime.toLocaleString()}) 内,${sensorInfo.name} 无模拟数据。`;resultsPlaceholderEl.style.display = 'block';resultsContentEl.style.display = 'none';} else {processAndRenderResults(simulatedData);setQueryStatus('done', '完成');}} catch (error) {console.error("Query simulation error:", error);setQueryStatus('error', '查询失败');resultsPlaceholderEl.textContent = '模拟查询过程中发生错误。';resultsPlaceholderEl.style.display = 'block';resultsContentEl.style.display = 'none';}isQuerying = false;}, queryDelay);}// --- Data Simulation & Processing ---function generateSimulatedData(sensorInfo, startTime, endTime) {const data = [];const durationMillis = endTime.getTime() - startTime.getTime();const pointsToGenerate = Math.min(5000, Math.floor(durationMillis / (1000 * 5))); // Simulate 1 point every 5 seconds, max 5000if (pointsToGenerate <= 0) return [];const timeStep = durationMillis / pointsToGenerate;for (let i = 0; i < pointsToGenerate; i++) {const timestamp = new Date(startTime.getTime() + i * timeStep);// Simulate value based on a slow sine wave (daily cycle) + faster sine (hourly cycle) + noiseconst timeFractionDay = (timestamp.getHours() * 3600 + timestamp.getMinutes() * 60 + timestamp.getSeconds()) / (24 * 3600);const timeFractionHour = (timestamp.getMinutes() * 60 + timestamp.getSeconds()) / 3600;const dailyCycle = Math.sin(timeFractionDay * 2 * Math.PI) * (sensorInfo.amplitude * 0.6);const hourlyCycle = Math.sin(timeFractionHour * 2 * Math.PI) * (sensorInfo.amplitude * 0.3);const noise = (Math.random() - 0.5) * sensorInfo.noise;const value = sensorInfo.base + dailyCycle + hourlyCycle + noise;data.push({ timestamp, value });}return data;}function processAndRenderResults(data) {if (!data || data.length === 0) {// Should be handled before calling this, but double-checkresultsContentEl.style.display = 'none';resultsPlaceholderEl.textContent = '无数据显示。';resultsPlaceholderEl.style.display = 'block';return;}let minTemp = data[0].value;let maxTemp = data[0].value;let sumTemp = 0;data.forEach(point => {if (point.value < minTemp) minTemp = point.value;if (point.value > maxTemp) maxTemp = point.value;sumTemp += point.value;});const avgTemp = sumTemp / data.length;// Update statsstatMinTempEl.textContent = minTemp.toFixed(1);statMaxTempEl.textContent = maxTemp.toFixed(1);statAvgTempEl.textContent = avgTemp.toFixed(1);statPointCountEl.textContent = data.length.toLocaleString();// Update sample data table (show first/last few points)sampleDataTableBody.innerHTML = ''; // Clear previous samplesconst sampleSize = 10;const samples = data.slice(0, sampleSize / 2).concat(data.slice(-sampleSize / 2));samples.forEach(point => {const row = document.createElement('tr');row.innerHTML = `<td>${point.timestamp.toLocaleString('zh-CN')}</td><td>${point.value.toFixed(2)}</td>`;sampleDataTableBody.appendChild(row);});// Show results sectionresultsContentEl.style.display = 'flex'; // Use flex for column layoutresultsPlaceholderEl.style.display = 'none';// In a real scenario, update the chart here// e.g., updateChart(data);}// --- UI Updates ---function setQueryStatus(statusType, statusText) {queryStatusEl.textContent = statusText;queryStatusEl.className = `status-${statusType}`;querySpinnerEl.style.display = (statusType === 'querying') ? 'inline-block' : 'none';}// --- Utility Functions ---function updateTime() {simulationTime = new Date();currentTimeEl.textContent = simulationTime.toLocaleTimeString('zh-CN');}// --- Initial Call ---initializeTSDBMonitor();
}); 
http://www.xdnf.cn/news/6213.html

相关文章:

  • OpenSHMEM 介绍和使用指南
  • contains方法的实现对比
  • Java 源码 HashMap源码分析
  • ConcurrentHashMap
  • GeoServer发布WMTS详细过程
  • javaScript简单版
  • 详解Windows(十三)——Windows防火墙
  • k8s监控方案实践补充(一):部署Metrics Server实现kubectl top和HPA支持
  • ESG时代,EcoVadis认证如何提升企业国际竞争力
  • 苍穹外卖--菜品分页查询
  • 优雅的请求接口(java)
  • 制造业降本增效的核心要素
  • 通过SMTP协议实现Linux邮件发送配置指南
  • 0514得物、0509滴滴面试总结复盘
  • 20250514 无限空间,当 a(t)→0,所有‌物理距离‌ d→0 ‌,这个状态是什么,是无限大的无限致密状态吗
  • 什么是临时对象?临时对象在什么情况下产生?
  • 网络检测工具InternetTest v8.9.1.2504 单文件版,支持一键查询IP/DNS、WIFI密码信息
  • 自营交易考试中,怎么用“黄昏之星”形态做出漂亮反转单?
  • 2025年文化传播、心理学与公共管理国际会议(CPPM 2025)
  • unordered_map和unordered的介绍和使用
  • 解密企业级大模型智能体Agentic AI 关键技术:MCP、A2A、Reasoning LLMs- consistency is the key
  • acwing 1488. 最短距离 超级源点 最短路 堆优化Dijkstra
  • Grafana变化趋势:Graph面板
  • SDIO EMMC中ADMA和SDMA简介
  • Linux常用命令40——alias设置命令别名
  • numpy 中数组的广播
  • 打破边界,智评未来:AI如何重塑学科交叉融合的评价体系?
  • 深度伪造对知识产权保护的新挑战与应对之策
  • 算法题(146):最大子段和
  • 山东大学软件学院软件工程计算机图形学复习笔记(2025)