// 全局变量
let currentModule = 'data-reception';
let dataStreamInterval;
let timeUpdateInterval;
let processingTaskInterval;
// DOM加载完成后初始化
document.addEventListener('DOMContentLoaded', function() {
initializeApp();
});
// 应用初始化
function initializeApp() {
setupNavigation();
setupTimeDisplay();
setupDataStream();
setupProcessingNodes();
setupVisualizationControls();
setupDataPoints();
console.log('海洋数据系统DEMO已启动');
}
// 设置导航功能
function setupNavigation() {
const navItems = document.querySelectorAll('.nav-item');
const modules = document.querySelectorAll('.module');
navItems.forEach(item => {
item.addEventListener('click', function() {
const targetModule = this.getAttribute('data-module');
// 更新导航状态
navItems.forEach(nav => nav.classList.remove('active'));
this.classList.add('active');
// 切换模块显示
modules.forEach(module => module.classList.remove('active'));
document.getElementById(targetModule).classList.add('active');
currentModule = targetModule;
// 根据模块执行特定初始化
switch(targetModule) {
case 'data-reception':
startDataReception();
break;
case 'data-processing':
startProcessingMonitor();
break;
case 'data-visualization':
startVisualization();
break;
}
console.log(`切换到模块: ${targetModule}`);
});
});
}
// 设置时间显示
function setupTimeDisplay() {
const timeDisplay = document.getElementById('currentTime');
function updateTime() {
const now = new Date();
const timeString = now.toLocaleTimeString('zh-CN', {
hour12: false,
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
timeDisplay.textContent = timeString;
}
updateTime();
timeUpdateInterval = setInterval(updateTime, 1000);
}
// 设置数据流显示
// 数据流管理类
class DataStreamManager {
constructor() {
this.container = null;
this.interval = null;
this.maxItems = 12;
this.updateFrequency = 500; // 1秒更新一次
this.isRunning = false;
}
init() {
this.container = document.querySelector('.data-stream');
if (!this.container) {
console.error('数据流容器未找到');
return false;
}
// 清空容器
this.container.innerHTML = '';
// 初始化几个数据项
this.generateInitialData();
// 开始定期更新
this.start();
console.log('数据流管理器初始化完成');
return true;
}
generateInitialData() {
// 生成3-5个初始数据项
const initialCount = Math.floor(Math.random() * 3) + 3;
for (let i = 0; i < initialCount; i++) {
setTimeout(() => {
this.addDataItem();
}, i * 300);
}
}
addDataItem() {
if (!this.container) return;
// 随机选择设备
const device = oceanDevices[Math.floor(Math.random() * oceanDevices.length)];
const param = device.parameters[Math.floor(Math.random() * device.parameters.length)];
const value = this.generateValue(param);
const timestamp = new Date().toLocaleTimeString('zh-CN', {
hour12: false,
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
// 创建数据项
const item = this.createDataItem(device, param, value, timestamp);
// 添加到容器顶部
this.container.insertBefore(item, this.container.firstChild);
// 限制数量
this.limitItems();
// 触发进入动画
requestAnimationFrame(() => {
item.style.opacity = '1';
item.style.transform = 'translateX(0)';
});
}
createDataItem(device, param, value, timestamp) {
const item = document.createElement('div');
item.className = `stream-item ${this.getDeviceClass(device.type)}`;
// 参数名称映射
const paramNames = {
'time': '时间', 'lng_lat': '经纬度', 'temp': '温度', 'cond': '电导率',
'depth': '深度', 'salinity': '盐度', 'flow_velocity': '流速', 'flow_direction': '流向',
'gravity': '重力', 'magnetic_field_1': '磁场强度1', 'magnetic_field_2': '磁场强度2',
'wave_height_max': '最大波高', 'wave_height_effective': '有效波高', 'cycle_max': '最大周期',
'wind_speed': '风速', 'wind_direction': '风向', 'air_pressure': '气压',
'humidity': '湿度', 'visibility': '能见度', 'cloud_height_1': '云高1',
'irradiance': '辐照度', 'turbidity': '浊度', 'chlorophyll': '叶绿素'
};
item.innerHTML = `
${this.getDeviceIcon(device.type)}
${device.name}
${paramNames[param] || param}
`;
// 添加点击事件
item.addEventListener('click', () => {
this.showItemDetails(device, param, value, timestamp);
});
return item;
}
limitItems() {
const items = this.container.querySelectorAll('.stream-item');
if (items.length > this.maxItems) {
const excess = items.length - this.maxItems;
for (let i = 0; i < excess; i++) {
const lastItem = items[items.length - 1 - i];
lastItem.classList.add('removing');
setTimeout(() => {
if (lastItem.parentNode) {
lastItem.remove();
}
}, 300);
}
}
}
generateValue(param) {
const valueRanges = {
'temp': () => (Math.random() * 30 + 5).toFixed(1) + '°C',
'depth': () => (Math.random() * 6000 + 10).toFixed(0) + 'm',
'flow_velocity': () => (Math.random() * 2 + 0.1).toFixed(2) + 'm/s',
'wind_speed': () => (Math.random() * 20 + 2).toFixed(1) + 'm/s',
'air_pressure': () => (Math.random() * 50 + 1000).toFixed(1) + 'hPa',
'humidity': () => (Math.random() * 40 + 40).toFixed(0) + '%',
'wave_height_max': () => (Math.random() * 8 + 0.5).toFixed(1) + 'm',
'salinity': () => (Math.random() * 5 + 30).toFixed(2) + 'psu',
'gravity': () => (Math.random() * 0.1 + 9.8).toFixed(3) + 'm/s²',
'visibility': () => (Math.random() * 20 + 5).toFixed(1) + 'km',
'cloud_height_1': () => (Math.random() * 3000 + 500).toFixed(0) + 'm'
};
return valueRanges[param] ? valueRanges[param]() : (Math.random() * 100).toFixed(2);
}
getDeviceClass(type) {
const classMap = {
'CTD': 'device-ctd', 'ADCP_38K': 'device-adcp', 'ADCP_150K': 'device-adcp',
'GRAVITY': 'device-gravity', 'MAGNETIC': 'device-magnetic', 'WAVE_GAUGE': 'device-wave',
'DEPTH_SOUNDER': 'device-depth', 'WAVE_RADAR': 'device-radar', 'MULTI_SENSOR': 'device-multi',
'WAVE_BUOY': 'device-buoy', 'BEIDOU': 'device-beidou', 'WIND_PROFILER': 'device-wind',
'WEATHER_STATION': 'device-weather', 'SKY_SCANNER': 'device-sky', 'TURBULENCE': 'device-turbulence',
'LIDAR_WIND': 'device-lidar', 'VISIBILITY': 'device-visibility', 'CLOUD_HEIGHT': 'device-cloud',
'NAVIGATION': 'device-navigation'
};
return classMap[type] || 'device-default';
}
getDeviceIcon(type) {
const iconMap = {
'CTD': '🌊', 'ADCP_38K': '🌀', 'ADCP_150K': '🌀', 'GRAVITY': '⚖️', 'MAGNETIC': '🧲',
'WAVE_GAUGE': '〰️', 'DEPTH_SOUNDER': '📏', 'WAVE_RADAR': '📡', 'MULTI_SENSOR': '🔬',
'WAVE_BUOY': '🛟', 'BEIDOU': '🛰️', 'WIND_PROFILER': '💨', 'WEATHER_STATION': '🌤️',
'SKY_SCANNER': '🌌', 'TURBULENCE': '🌪️', 'LIDAR_WIND': '🔦', 'VISIBILITY': '👁️',
'CLOUD_HEIGHT': '☁️', 'NAVIGATION': '🧭'
};
return iconMap[type] || '📊';
}
showItemDetails(device, param, value, timestamp) {
// 创建模态框
const modal = document.createElement('div');
modal.className = 'stream-detail-modal';
modal.style.cssText = `
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0, 0, 0, 0.8); display: flex; align-items: center;
justify-content: center; z-index: 1000; backdrop-filter: blur(5px);
`;
const content = document.createElement('div');
content.style.cssText = `
background: linear-gradient(135deg, #1e3a8a 0%, #0f172a 100%);
border-radius: 16px; padding: 24px; max-width: 400px; width: 90%;
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);
`;
content.innerHTML = `
${this.getDeviceIcon(device.type)}
${device.name}
设备ID: ${device.id}
参数
${param}
数值
${value}
时间
${timestamp}
`;
modal.appendChild(content);
document.body.appendChild(modal);
// 点击背景关闭
modal.addEventListener('click', (e) => {
if (e.target === modal) modal.remove();
});
}
start() {
if (this.isRunning) return;
this.isRunning = true;
this.interval = setInterval(() => {
this.addDataItem();
}, this.updateFrequency);
console.log('数据流开始运行');
}
stop() {
if (this.interval) {
clearInterval(this.interval);
this.interval = null;
}
this.isRunning = false;
console.log('数据流已停止');
}
restart() {
this.stop();
setTimeout(() => {
this.start();
}, 100);
}
}
// 创建全局数据流管理器实例
const dataStreamManager = new DataStreamManager();
// 重新定义setupDataStream函数
function setupDataStream() {
return dataStreamManager.init();
}
// 设置数据点交互
function setupDataPoints() {
const dataPoints = document.querySelectorAll('.data-point');
const sourceDetails = document.getElementById('sourceDetails');
const sourceInfo = {
'浮标-001': {
location: '北纬 25.2°, 东经 120.5°',
status: '在线',
lastUpdate: '2分钟前',
type: '海洋浮标'
},
'卫星-A': {
location: '轨道高度 705km',
status: '在线',
lastUpdate: '1分钟前',
type: '海洋观测卫星'
},
'监测站-B': {
location: '北纬 22.8°, 东经 118.3°',
status: '在线',
lastUpdate: '30秒前',
type: '海岸监测站'
},
'船舶-C': {
location: '北纬 24.1°, 东经 119.7°',
status: '在线',
lastUpdate: '5分钟前',
type: '科考船'
}
};
dataPoints.forEach(point => {
point.addEventListener('click', function() {
const sourceName = this.getAttribute('data-source');
const info = sourceInfo[sourceName];
if (info && sourceDetails) {
sourceDetails.innerHTML = `
数据源:
${sourceName}
类型:
${info.type}
位置:
${info.location}
状态:
${info.status}
最后更新:
${info.lastUpdate}
`;
}
// 高亮效果
dataPoints.forEach(p => p.classList.remove('highlighted'));
this.classList.add('highlighted');
});
});
}
// 设置处理节点交互
function setupProcessingNodes() {
const nodes = document.querySelectorAll('.pipeline-node');
const nodeTitle = document.getElementById('nodeTitle');
const nodeDetails = document.getElementById('nodeDetails');
const nodeInfo = {
'input': {
title: '原始数据输入',
details: `
功能: 接收来自各种数据源的原始海洋数据
数据类型: 温度、盐度、叶绿素、波高等
当前状态: 正常运行
处理速率: 15.2 MB/s
`
},
'clean': {
title: '数据清洗',
details: `
功能: 去除异常值、填补缺失数据
质量指标:
- 数据完整性: 98.5%
- 异常值检出率: 2.1%
- 处理成功率: 99.8%
算法: 3σ准则 + 卡尔曼滤波
`
},
'format': {
title: '数据格式化',
details: `
功能: 统一数据格式和坐标系统
输出格式: NetCDF-4
坐标系: WGS84
时间标准: UTC
处理延迟: < 5秒
`
},
'interpolation': {
title: '三维插值',
details: `
功能: 生成规则网格的三维温度场
插值方法: 克里金插值
质量评估:
- 相关系数: 0.95
- RMSE: 0.2°C
- 标准差: 0.15
网格分辨率: 0.1° × 0.1°
`
},
'analysis': {
title: '叶绿素反演',
details: `
功能: 基于多光谱数据反演叶绿素浓度
算法: OC4v6 + 神经网络
波段: 443, 490, 510, 555 nm
精度: ±0.3 mg/m³
覆盖范围: 全球海域
`
},
'output': {
title: '产品数据库',
details: `
功能: 存储最终处理产品
存储格式: HDF5 + 元数据
数据产品:
更新频率: 每小时
`
}
};
nodes.forEach(node => {
node.addEventListener('click', function() {
const step = this.getAttribute('data-step');
const info = nodeInfo[step];
if (info && nodeTitle && nodeDetails) {
nodeTitle.textContent = info.title;
nodeDetails.innerHTML = info.details;
}
// 高亮效果
nodes.forEach(n => n.classList.remove('highlighted'));
this.classList.add('highlighted');
});
});
}
// 设置可视化控件
function setupVisualizationControls() {
const playButton = document.querySelector('#data-visualization .btn-primary');
const dataSelect = document.querySelector('#data-visualization .control-select');
if (playButton) {
playButton.addEventListener('click', function() {
const icon = this.querySelector('i');
const text = this.querySelector('span') || this.childNodes[this.childNodes.length - 1];
if (icon.classList.contains('fa-play')) {
icon.classList.remove('fa-play');
icon.classList.add('fa-pause');
if (text) text.textContent = ' 暂停动画';
startTemperatureAnimation();
} else {
icon.classList.remove('fa-pause');
icon.classList.add('fa-play');
if (text) text.textContent = ' 播放动画';
stopTemperatureAnimation();
}
});
}
if (dataSelect) {
dataSelect.addEventListener('change', function() {
updateVisualizationData(this.value);
});
}
}
// 启动数据接收
function startDataReception() {
console.log('数据接收模块已激活');
// 重新启动数据流(如果已停止)
if (!dataStreamInterval) {
setupDataStream();
}
}
// 启动处理监控
function startProcessingMonitor() {
console.log('数据处理模块已激活');
startProcessingTask();
}
// 启动可视化
function startVisualization() {
console.log('数据可视化模块已激活');
updateMetrics();
}
// 启动处理任务演示
function startProcessingTask() {
const nodes = document.querySelectorAll('.pipeline-node');
const logContent = document.getElementById('logContent');
function addLogEntry(message, type = 'info') {
if (!logContent) return;
const now = new Date();
const timeString = now.toLocaleTimeString('zh-CN', {
hour12: false,
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
const logEntry = document.createElement('div');
logEntry.className = `log-entry ${type}`;
logEntry.textContent = `[${timeString}] ${message}`;
logContent.insertBefore(logEntry, logContent.firstChild);
// 限制日志条数
while (logContent.children.length > 20) {
logContent.removeChild(logContent.lastChild);
}
}
function simulateProcessing() {
const messages = [
{ msg: '数据块 #A7B2 处理完成', type: 'info' },
{ msg: '三维插值算法执行成功', type: 'info' },
{ msg: '叶绿素反演计算完成', type: 'info' },
{ msg: '警告: 数据源 浮标-003 信号弱', type: 'warning' },
{ msg: '产品数据已存储到数据库', type: 'info' },
{ msg: '质量检验通过率: 98.5%', type: 'info' }
];
const randomMessage = messages[Math.floor(Math.random() * messages.length)];
addLogEntry(randomMessage.msg, randomMessage.type);
}
// 定期添加日志
processingTaskInterval = setInterval(simulateProcessing, 5000);
// 初始日志
setTimeout(() => addLogEntry('南海温度场与叶绿素产品生成任务启动'), 1000);
}
// 温度动画控制
let temperatureAnimationInterval;
function startTemperatureAnimation() {
const temperatureZones = document.querySelectorAll('.temperature-zone');
temperatureAnimationInterval = setInterval(() => {
temperatureZones.forEach(zone => {
// 随机改变温度区域的大小和位置
const newTop = Math.random() * 70 + 10;
const newLeft = Math.random() * 70 + 10;
const newWidth = Math.random() * 20 + 15;
const newHeight = Math.random() * 15 + 10;
zone.style.top = newTop + '%';
zone.style.left = newLeft + '%';
zone.style.width = newWidth + '%';
zone.style.height = newHeight + '%';
});
}, 2000);
}
function stopTemperatureAnimation() {
if (temperatureAnimationInterval) {
clearInterval(temperatureAnimationInterval);
temperatureAnimationInterval = null;
}
}
// 更新可视化数据
function updateVisualizationData(dataType) {
const metrics = document.querySelectorAll('.metric-value');
const dataValues = {
'温度数据': ['24.5°C', '2.8m', '3'],
'盐度数据': ['34.2‰', '1.9m', '2'],
'叶绿素数据': ['0.8mg/m³', '2.1m', '4']
};
const values = dataValues[dataType] || dataValues['温度数据'];
metrics.forEach((metric, index) => {
if (values[index]) {
metric.textContent = values[index];
}
});
console.log(`切换到${dataType}显示`);
}
// 更新指标数据
function updateMetrics() {
const statValues = document.querySelectorAll('.stat-value');
// 模拟数据更新
setInterval(() => {
statValues.forEach(stat => {
const currentText = stat.textContent;
if (currentText.includes('MB/s')) {
const newValue = (Math.random() * 10 + 10).toFixed(1);
stat.textContent = newValue + ' MB/s';
} else if (currentText.includes('°C')) {
const newValue = (Math.random() * 5 + 22).toFixed(1);
stat.textContent = newValue + '°C';
} else if (!isNaN(parseInt(currentText))) {
const baseValue = parseInt(currentText);
const variation = Math.floor(Math.random() * 10 - 5);
stat.textContent = Math.max(0, baseValue + variation);
}
});
}, 10000);
}
// 添加CSS类用于高亮效果
const style = document.createElement('style');
style.textContent = `
.data-point.highlighted {
transform: scale(1.5);
box-shadow: 0 0 20px var(--accent-green);
z-index: 20;
}
.pipeline-node.highlighted {
transform: translateY(-5px) scale(1.05);
box-shadow: 0 15px 40px rgba(0, 212, 255, 0.4);
border-color: var(--accent-blue);
}
.node-info {
line-height: 1.6;
}
.node-info ul {
margin: 0.5rem 0;
padding-left: 1rem;
}
.node-info li {
margin: 0.25rem 0;
color: var(--text-secondary);
}
.node-info strong {
color: var(--accent-blue);
}
`;
document.head.appendChild(style);
// 清理函数
function cleanup() {
if (dataStreamInterval) clearInterval(dataStreamInterval);
if (timeUpdateInterval) clearInterval(timeUpdateInterval);
if (processingTaskInterval) clearInterval(processingTaskInterval);
if (temperatureAnimationInterval) clearInterval(temperatureAnimationInterval);
}
// 页面卸载时清理
window.addEventListener('beforeunload', cleanup);
// 导出主要函数供调试使用
window.OceanDemo = {
switchModule: function(moduleName) {
const navItem = document.querySelector(`[data-module="${moduleName}"]`);
if (navItem) navItem.click();
},
startProcessingDemo: startProcessingTask,
updateVisualization: updateVisualizationData,
cleanup: cleanup
};
console.log('海洋数据系统DEMO脚本加载完成');
// 真实海洋设备数据配置
const oceanDevices = [
{
id: 'ctd_001',
name: 'CTD温盐深仪',
type: 'CTD',
position: { lat: 35.2, lng: 120.5 },
parameters: ['time', 'lng_lat', 'temp', 'cond', 'depth'],
status: 'online',
color: '#00ff88'
},
{
id: 'adcp_38k_001',
name: '船载ADCP系统(38k)',
type: 'ADCP_38K',
position: { lat: 36.1, lng: 121.2 },
parameters: ['data_time', 'lng_lat', 'depth', 'flow_velocity', 'flow_direction', 'flow_velocity_e', 'flow_velocity_n', 'flow_velocity_v'],
status: 'online',
color: '#0088ff'
},
{
id: 'adcp_150k_001',
name: '船载ADCP系统(150k)',
type: 'ADCP_150K',
position: { lat: 34.8, lng: 119.8 },
parameters: ['data_time', 'lng_lat', 'depth', 'flow_velocity', 'flow_direction', 'flow_velocity_e', 'flow_velocity_n', 'flow_velocity_v'],
status: 'online',
color: '#0066ff'
},
{
id: 'gravity_001',
name: '重力仪',
type: 'GRAVITY',
position: { lat: 35.5, lng: 120.8 },
parameters: ['data_time', 'lng_lat', 'gravity'],
status: 'online',
color: '#ff6600'
},
{
id: 'magnetic_001',
name: '磁力仪',
type: 'MAGNETIC',
position: { lat: 36.3, lng: 121.5 },
parameters: ['data_time', 'lng_lat', 'magnetic_field_1', 'magnetic_field_2'],
status: 'online',
color: '#ff0066'
},
{
id: 'wave_gauge_001',
name: '波潮仪',
type: 'WAVE_GAUGE',
position: { lat: 35.8, lng: 120.2 },
parameters: ['data_time', 'lng_lat', 'wave_height_max', 'cycle_max', 'wave_height_1_10', 'cycle_1_10', 'wave_height_effective', 'cycle_effective', 'wave_height_average', 'cycle_average'],
status: 'online',
color: '#00ffff'
},
{
id: 'depth_sounder_001',
name: '6000米测深仪',
type: 'DEPTH_SOUNDER',
position: { lat: 34.5, lng: 119.5 },
parameters: ['data_time', 'lng_lat', 'depth_f', 'depth_m'],
status: 'online',
color: '#8800ff'
},
{
id: 'wave_radar_001',
name: '测波雷达',
type: 'WAVE_RADAR',
position: { lat: 36.5, lng: 122.1 },
parameters: ['data_time', 'lng_lat', 'wave_height_effective', 'cycle_tm2', 'direction_peak', 'cycle_peak', 'wavelength_peak', 'direction_swell_primary', 'cycle_swell_primary', 'wavelength_swell_primary', 'direction_wind_wave', 'cycle_wind_wave', 'wavelength_wind_wave', 'current_direction', 'current_velocity', 'encounter_current_direction', 'encounter_current_velocity'],
status: 'online',
color: '#ffff00'
},
{
id: 'multi_sensor_001',
name: '表层多要素自动测定系统',
type: 'MULTI_SENSOR',
position: { lat: 35.1, lng: 119.9 },
parameters: ['data_time', 'lng_lat', 'temp', 'cond', 'salinity', 'chlorophyll', 'cdom', 'turbidity'],
status: 'online',
color: '#00ff00'
},
{
id: 'wave_buoy_001',
name: '小型波浪浮标',
type: 'WAVE_BUOY',
position: { lat: 34.9, lng: 120.7 },
parameters: ['time', 'lng_lat', 'wave_height_average', 'cycle_average', 'wave_height_max', 'cycle_max', 'wave_height_1_10', 'cycle_1_10', 'wave_height_effective'],
status: 'online',
color: '#ff8800'
},
{
id: 'beidou_001',
name: '北斗探测系统',
type: 'BEIDOU',
position: { lat: 36.0, lng: 121.8 },
parameters: ['data_time', 'lng_lat', 'temp', 'relative_humidity', 'air_pressure', 'wind_speed', 'height', 'wind_direction'],
status: 'online',
color: '#ff4400'
},
{
id: 'wind_profiler_001',
name: '舰载风廓线雷达',
type: 'WIND_PROFILER',
position: { lat: 35.7, lng: 121.0 },
parameters: ['time', 'lng_lat', 'height', 'wind_direction', 'wind_speed', 'wind_speed_v', 'reliability_l', 'reliability_v', 'cn2'],
status: 'online',
color: '#4400ff'
},
{
id: 'weather_station_001',
name: '船载自动气象站',
type: 'WEATHER_STATION',
position: { lat: 34.7, lng: 119.3 },
parameters: ['data_time', 'lng_lat', 'wind_speed_realtime', 'wind_direction_realtime', 'wind_speed_average', 'wind_direction_average', 'wind_speed_max', 'wind_direction_max', 'time_wind_speed_max', 'temperature', 'humidity', 'pressure', 'rainfall_minute', 'rainfall_hour', 'rainfall_day', 'status_sensor'],
status: 'online',
color: '#88ff00'
},
{
id: 'sky_scanner_001',
name: '全天空背景扫描仪',
type: 'SKY_SCANNER',
position: { lat: 36.2, lng: 120.3 },
parameters: ['data_time', 'lng_lat', 'irradiance', 'radiance'],
status: 'online',
color: '#ff0088'
},
{
id: 'turbulence_001',
name: '大气湍流谱仪',
type: 'TURBULENCE',
position: { lat: 35.4, lng: 121.7 },
parameters: ['data_time', 'lng_lat', 'temp', 'air_pressure', 'cn2'],
status: 'online',
color: '#0044ff'
},
{
id: 'lidar_wind_001',
name: '激光测风雷达',
type: 'LIDAR_WIND',
position: { lat: 34.6, lng: 120.1 },
parameters: ['data_time', 'lng_lat', 'height', 'wind_speed_l', 'wind_direction_l', 'wind_speed_v'],
status: 'online',
color: '#ff6600'
},
{
id: 'visibility_001',
name: '天气现象及能见度仪',
type: 'VISIBILITY',
position: { lat: 35.9, lng: 119.6 },
parameters: ['data_time', 'lng_lat', 'height', 'visibility', 'azimuth_angle', 'elevation'],
status: 'online',
color: '#66ff00'
},
{
id: 'cloud_height_001',
name: '激光云高仪',
type: 'CLOUD_HEIGHT',
position: { lat: 36.4, lng: 120.9 },
parameters: ['data_time', 'lng_lat', 'cloud_height_1', 'cloud_height_2', 'cloud_height_3', 'cloud_height_4', 'cloud_height_5', 'cloud_thickness_1', 'cloud_thickness_2', 'cloud_thickness_3', 'cloud_thickness_4', 'cloud_thickness_5'],
status: 'online',
color: '#00aaff'
},
{
id: 'navigation_001',
name: '船舶航行数据',
type: 'NAVIGATION',
position: { lat: 35.3, lng: 121.3 },
parameters: ['POS惯导', 'GNSS', '计程仪', '电罗经', '测深仪'],
status: 'online',
color: '#aa00ff'
}
];
function initDataReception() {
const earthContainer = document.getElementById('earth-container');
if (!earthContainer) return;
// 清空容器
earthContainer.innerHTML = '';
// 创建地球
const earth = document.createElement('div');
earth.className = 'earth';
earthContainer.appendChild(earth);
// 添加真实设备数据源点
oceanDevices.forEach((device, index) => {
const point = document.createElement('div');
point.className = 'data-source-point';
point.style.backgroundColor = device.color;
point.style.boxShadow = `0 0 20px ${device.color}`;
// 根据经纬度计算位置(简化的球面投影)
const x = 50 + (device.position.lng - 120) * 8; // 相对于120度经线
const y = 50 - (device.position.lat - 35) * 8; // 相对于35度纬线
point.style.left = `${Math.max(10, Math.min(90, x))}%`;
point.style.top = `${Math.max(10, Math.min(90, y))}%`;
point.setAttribute('data-device-id', device.id);
point.setAttribute('data-device-name', device.name);
point.setAttribute('data-device-type', device.type);
// 添加点击事件
point.addEventListener('click', () => showDeviceDetails(device));
earthContainer.appendChild(point);
// 创建数据流线
const streamLine = document.createElement('div');
streamLine.className = 'data-stream-line';
streamLine.style.background = `linear-gradient(45deg, transparent, ${device.color}, transparent)`;
streamLine.style.left = point.style.left;
streamLine.style.top = point.style.top;
streamLine.style.animationDelay = `${index * 0.2}s`;
earthContainer.appendChild(streamLine);
});
// 更新统计信息
updateReceptionStats();
}
function updateReceptionStats() {
const totalDevices = oceanDevices.length;
const onlineDevices = oceanDevices.filter(d => d.status === 'online').length;
const totalParams = oceanDevices.reduce((sum, device) => sum + device.parameters.length, 0);
// 更新统计显示
const statsElements = {
'total-received': `${(Math.random() * 50000 + 150000).toFixed(0)}`,
'reception-rate': `${(Math.random() * 200 + 800).toFixed(0)} 包/秒`,
'online-sources': `${onlineDevices}/${totalDevices}`,
'data-types': `${totalParams} 种参数`
};
Object.entries(statsElements).forEach(([id, value]) => {
const element = document.getElementById(id);
if (element) element.textContent = value;
});
}
// 底部数据流面板管理
class BottomDataStreamManager {
constructor() {
this.isCollapsed = false;
this.dataStreamManager = new DataStreamManager();
this.init();
}
init() {
this.setupEventListeners();
this.startDataStream();
}
setupEventListeners() {
const streamHeader = document.querySelector('.stream-header');
const streamToggle = document.querySelector('.stream-toggle');
if (streamHeader) {
streamHeader.addEventListener('click', () => this.togglePanel());
}
if (streamToggle) {
streamToggle.addEventListener('click', (e) => {
e.stopPropagation();
this.togglePanel();
});
}
}
togglePanel() {
const panel = document.querySelector('.bottom-data-stream');
if (panel) {
this.isCollapsed = !this.isCollapsed;
panel.classList.toggle('collapsed', this.isCollapsed);
// 更新按钮文本
const toggleText = document.querySelector('.stream-toggle span');
if (toggleText) {
toggleText.textContent = this.isCollapsed ? '展开' : '收起';
}
}
}
startDataStream() {
// 启动数据流管理器
this.dataStreamManager.start();
// 每1秒添加新数据 - 加快生成速度
setInterval(() => {
this.addNewDataItem();
}, 1000);
}
addNewDataItem() {
const container = document.querySelector('.data-stream.horizontal');
if (!container) return;
const newItem = this.dataStreamManager.generateDataItem();
const itemElement = this.createStreamItemElement(newItem);
// 为新卡片添加特殊类名
itemElement.classList.add('new-item');
// 为现有卡片添加推动效果
const existingItems = container.querySelectorAll('.stream-item');
existingItems.forEach((item, index) => {
if (index < 5) { // 对前5个卡片添加推动效果
// 先移除可能存在的重置类
item.classList.remove('reset-position');
// 添加推动效果
setTimeout(() => {
item.classList.add('push-right');
}, 50); // 小延迟确保DOM更新
}
});
// 添加到容器开头
container.insertBefore(itemElement, container.firstChild);
// 延迟重置卡片位置,创建流动效果
setTimeout(() => {
const allItems = container.querySelectorAll('.stream-item');
allItems.forEach((item, index) => {
if (item.classList.contains('push-right')) {
item.classList.remove('push-right');
item.classList.add('reset-position');
}
});
}, 100);
// 限制显示的数据项数量,为超出的卡片添加淡出动画
setTimeout(() => {
const items = container.querySelectorAll('.stream-item');
if (items.length > 20) {
const itemToRemove = items[items.length - 1];
itemToRemove.classList.add('fade-out');
// 动画完成后移除元素
setTimeout(() => {
if (itemToRemove.parentNode) {
itemToRemove.remove();
}
}, 500);
}
}, 200);
// 清理类名
setTimeout(() => {
itemElement.classList.remove('new-item');
const allItems = container.querySelectorAll('.stream-item');
allItems.forEach(item => {
item.classList.remove('reset-position');
});
}, 800);
// 自动滚动到最新数据
container.scrollLeft = 0;
}
createStreamItemElement(data) {
const item = document.createElement('div');
item.className = 'stream-item';
// 设备类型颜色
const deviceColors = {
'temperature': { bg: 'rgba(239, 68, 68, 0.2)', border: '#ef4444', icon: '🌡️' },
'pressure': { bg: 'rgba(59, 130, 246, 0.2)', border: '#3b82f6', icon: '📊' },
'salinity': { bg: 'rgba(34, 197, 94, 0.2)', border: '#22c55e', icon: '🧂' },
'ph': { bg: 'rgba(168, 85, 247, 0.2)', border: '#a855f7', icon: '⚗️' },
'oxygen': { bg: 'rgba(6, 182, 212, 0.2)', border: '#06b6d4', icon: '💨' },
'turbidity': { bg: 'rgba(245, 158, 11, 0.2)', border: '#f59e0b', icon: '🌊' }
};
const colorInfo = deviceColors[data.type] || deviceColors['temperature'];
item.innerHTML = `
${colorInfo.icon}
${data.deviceName}
${data.parameter}
${data.value}
${data.timestamp}
`;
return item;
}
}
// 初始化底部数据流面板
document.addEventListener('DOMContentLoaded', () => {
// 检查是否存在底部数据流面板
if (document.querySelector('.bottom-data-stream')) {
new BottomDataStreamManager();
}
});
function showDeviceDetails(device) {
// 创建设备详情弹窗
const modal = document.createElement('div');
modal.className = 'device-modal';
modal.innerHTML = `
设备ID: ${device.id}
设备类型: ${device.type}
位置: ${device.position.lat}°N, ${device.position.lng}°E
状态: ${device.status === 'online' ? '在线' : '离线'}
测量参数:
${device.parameters.map(param => `${param}`).join('')}
实时数据:
数据包数:
${Math.floor(Math.random() * 1000 + 500)}
传输速率:
${Math.floor(Math.random() * 50 + 20)} KB/s
数据质量:
${(Math.random() * 10 + 90).toFixed(1)}%
`;
document.body.appendChild(modal);
// 关闭弹窗事件
const closeBtn = modal.querySelector('.device-modal-close');
closeBtn.addEventListener('click', () => {
document.body.removeChild(modal);
});
modal.addEventListener('click', (e) => {
if (e.target === modal) {
document.body.removeChild(modal);
}
});
}
// 更新数据流显示函数
function updateDataStream() {
const streamContainer = document.querySelector('.data-stream');
if (!streamContainer) return;
// 随机选择一个设备
const device = oceanDevices[Math.floor(Math.random() * oceanDevices.length)];
const param = device.parameters[Math.floor(Math.random() * device.parameters.length)];
const value = generateRandomValue(param);
const now = new Date();
const timestamp = now.toLocaleTimeString('zh-CN', {
hour12: false,
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
// 获取参数的中文名称
const paramNames = {
'time': '时间',
'lng_lat': '经纬度',
'temp': '温度',
'cond': '电导率',
'depth': '深度',
'salinity': '盐度',
'flow_velocity': '流速',
'flow_direction': '流向',
'gravity': '重力',
'magnetic_field_1': '磁场强度1',
'magnetic_field_2': '磁场强度2',
'wave_height_max': '最大波高',
'wave_height_effective': '有效波高',
'cycle_max': '最大周期',
'wind_speed': '风速',
'wind_direction': '风向',
'air_pressure': '气压',
'humidity': '湿度',
'visibility': '能见度',
'cloud_height_1': '云高1',
'irradiance': '辐照度',
'turbidity': '浊度',
'chlorophyll': '叶绿素'
};
// 创建数据流项目
const streamItem = document.createElement('div');
streamItem.className = `stream-item ${getDeviceTypeClass(device.type)}`;
streamItem.innerHTML = `
${deviceTypeIcons[device.type] || '📊'}
${device.name}
${paramNames[param] || param}
`;
// 添加点击事件
streamItem.addEventListener('click', () => {
showStreamItemDetails(device, param, value, timestamp);
});
// 添加到流中
streamContainer.insertBefore(streamItem, streamContainer.firstChild);
// 限制显示的项目数量
const items = streamContainer.querySelectorAll('.stream-item');
if (items.length > 12) {
const lastItem = items[items.length - 1];
lastItem.classList.add('removing');
setTimeout(() => {
if (lastItem.parentNode) {
lastItem.remove();
}
}, 300);
}
}
// 显示数据流项目详细信息
function showStreamItemDetails(device, param, value, timestamp) {
const modal = document.createElement('div');
modal.className = 'stream-detail-modal';
modal.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
backdrop-filter: blur(5px);
`;
const content = document.createElement('div');
content.style.cssText = `
background: linear-gradient(135deg, #1e3a8a 0%, #0f172a 100%);
border-radius: 16px;
padding: 24px;
max-width: 400px;
width: 90%;
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);
`;
content.innerHTML = `
${deviceTypeIcons[device.type] || '📊'}
${device.name}
设备ID: ${device.id}
参数
${param}
数值
${value}
时间
${timestamp}
位置
${device.position.lat.toFixed(2)}°N, ${device.position.lng.toFixed(2)}°E
`;
modal.appendChild(content);
document.body.appendChild(modal);
// 点击背景关闭
modal.addEventListener('click', (e) => {
if (e.target === modal) {
modal.remove();
}
});
}
// 更新数据源点渲染函数
function renderDataSourcePoints() {
const earthSphere = document.querySelector('.earth-sphere');
if (!earthSphere) return;
// 清除现有的数据点
earthSphere.querySelectorAll('.data-source-point').forEach(point => point.remove());
earthSphere.querySelectorAll('.data-stream-line').forEach(line => line.remove());
oceanDevices.forEach((device, index) => {
// 创建数据源点
const point = document.createElement('div');
point.className = 'data-source-point';
point.style.backgroundColor = deviceTypeColors[device.type] || '#00d4ff';
point.style.color = deviceTypeColors[device.type] || '#00d4ff';
// 根据经纬度计算位置(简化的球面投影)
const x = ((device.longitude + 180) / 360) * 100;
const y = ((90 - device.latitude) / 180) * 100;
point.style.left = `${x}%`;
point.style.top = `${y}%`;
// 添加点击事件
point.addEventListener('click', () => showDeviceDetails(device));
// 添加悬停提示
point.title = `${device.name} (${device.type})`;
earthSphere.appendChild(point);
// 创建数据流线
if (Math.random() < 0.3) { // 30%的概率显示数据流
const streamLine = document.createElement('div');
streamLine.className = 'data-stream-line';
streamLine.style.background = `linear-gradient(to top, ${deviceTypeColors[device.type] || '#00d4ff'}, transparent)`;
streamLine.style.left = `${x}%`;
streamLine.style.top = `${y}%`;
streamLine.style.animationDelay = `${Math.random() * 3}s`;
earthSphere.appendChild(streamLine);
}
});
}
// 更新设备详情显示函数
function showDeviceDetails(device) {
// 创建模态框
const modal = document.createElement('div');
modal.className = 'device-modal';
modal.innerHTML = `
设备类型: ${device.type}
位置: ${device.latitude.toFixed(4)}°N, ${device.longitude.toFixed(4)}°E
状态: ${device.status === 'online' ? '在线' : '离线'}
设备ID: ${device.id}
监测参数
${device.parameters.map(param => `${param}`).join('')}
实时数据
${device.parameters.slice(0, 6).map(param => `
${param}
${generateRandomValue(param)}
`).join('')}
`;
// 添加关闭事件
modal.querySelector('.device-modal-close').addEventListener('click', () => {
modal.remove();
});
modal.addEventListener('click', (e) => {
if (e.target === modal) {
modal.remove();
}
});
document.body.appendChild(modal);
}
function generateRandomValue(param) {
const valueMap = {
'temp': `${(Math.random() * 30 + 5).toFixed(2)}°C`,
'temperature': `${(Math.random() * 30 + 5).toFixed(2)}°C`,
'depth': `${(Math.random() * 6000).toFixed(1)}m`,
'wind_speed': `${(Math.random() * 20 + 2).toFixed(1)}m/s`,
'wave_height_max': `${(Math.random() * 8 + 1).toFixed(2)}m`,
'pressure': `${(Math.random() * 50 + 1000).toFixed(1)}hPa`,
'humidity': `${(Math.random() * 40 + 40).toFixed(1)}%`,
'salinity': `${(Math.random() * 5 + 30).toFixed(2)}‰`,
'flow_velocity': `${(Math.random() * 3).toFixed(2)}m/s`,
'gravity': `${(Math.random() * 0.1 + 9.8).toFixed(4)}m/s²`,
'visibility': `${(Math.random() * 20 + 5).toFixed(1)}km`,
'irradiance': `${(Math.random() * 1000 + 200).toFixed(1)}W/m²`
};
// 检查参数名是否包含特定关键词
for (const [key, value] of Object.entries(valueMap)) {
if (param.includes(key)) {
return value;
}
}
// 默认返回数值
return `${(Math.random() * 100).toFixed(2)}`;
}
// 数据处理模块
function initDataProcessing() {
const pipelineContainer = document.querySelector('.pipeline-container');
if (!pipelineContainer) return;
// 清空现有内容
pipelineContainer.innerHTML = '';
// 创建处理流水线
const pipelineFlow = document.createElement('div');
pipelineFlow.className = 'pipeline-flow';
// 定义处理节点(基于真实海洋数据处理流程)
const processingNodes = [
{
id: 'data-ingestion',
type: 'input-node',
icon: 'fas fa-download',
title: '数据接收',
description: '接收来自19种海洋观测设备的原始数据'
},
{
id: 'data-validation',
type: 'process-node',
icon: 'fas fa-check-circle',
title: '数据验证',
description: '验证CTD、ADCP、重力仪等设备数据的完整性和准确性'
},
{
id: 'quality-control',
type: 'process-node',
icon: 'fas fa-filter',
title: '质量控制',
description: '对温度、盐度、流速等参数进行质量检查和异常值过滤'
},
{
id: 'data-calibration',
type: 'compute-node',
icon: 'fas fa-cogs',
title: '数据校准',
description: '校准传感器漂移,统一时间基准和坐标系统'
},
{
id: 'oceanographic-analysis',
type: 'compute-node',
icon: 'fas fa-chart-line',
title: '海洋学分析',
description: '计算海水密度、声速、地转流等海洋学参数'
},
{
id: 'data-fusion',
type: 'compute-node',
icon: 'fas fa-layer-group',
title: '数据融合',
description: '融合多源观测数据,生成综合海洋环境场'
},
{
id: 'data-output',
type: 'output-node',
icon: 'fas fa-upload',
title: '数据输出',
description: '输出标准格式的海洋数据产品和可视化结果'
}
];
// 创建节点元素
processingNodes.forEach((node, index) => {
const nodeElement = document.createElement('div');
nodeElement.className = `pipeline-node ${node.type}`;
nodeElement.id = node.id;
nodeElement.innerHTML = `
${node.title}
`;
// 添加点击事件
nodeElement.addEventListener('click', () => showNodeDetails(node));
pipelineFlow.appendChild(nodeElement);
// 添加连接线(除了最后一个节点)
if (index < processingNodes.length - 1) {
const connection = document.createElement('div');
connection.className = 'pipeline-connection';
connection.style.left = `${(index + 1) * 150 - 75}px`;
connection.style.width = '150px';
pipelineFlow.appendChild(connection);
}
});
pipelineContainer.appendChild(pipelineFlow);
// 更新处理统计
updateProcessingStats();
// 启动处理监控
startProcessingMonitor();
}
// 显示节点详情
function showNodeDetails(node) {
const detailsPanel = document.querySelector('.node-details');
if (!detailsPanel) return;
// 根据节点类型显示不同的详细信息
let detailsContent = '';
switch(node.id) {
case 'data-ingestion':
detailsContent = `
数据接收节点
${node.description}
- CTD数据:温度、盐度、深度
- ADCP数据:流速、流向
- 重力仪:重力异常
- 磁力仪:磁场强度
- 气象数据:风速、气压、湿度
- 波浪数据:波高、周期、方向
处理速度: 1000条/秒
数据格式: NetCDF, ASCII, Binary
`;
break;
case 'data-validation':
detailsContent = `
数据验证节点
${node.description}
- 时间戳连续性检查
- 地理坐标合理性验证
- 物理参数范围检查
- 数据完整性验证
验证规则: 127项
通过率: 98.5%
`;
break;
case 'quality-control':
detailsContent = `
质量控制节点
${node.description}
- 统计异常值检测
- 物理一致性检查
- 时间序列平滑
- 空间插值质量评估
QC标准: IOC/UNESCO
处理算法: 3σ准则, Hampel滤波
`;
break;
case 'data-calibration':
detailsContent = `
数据校准节点
${node.description}
- 传感器漂移校正
- 时间同步校准
- 坐标系统转换
- 单位标准化
校准精度: ±0.001°C (温度)
时间精度: ±1ms
`;
break;
case 'oceanographic-analysis':
detailsContent = `
海洋学分析节点
${node.description}
- 海水状态方程计算
- 地转流计算
- 混合层深度估算
- 海洋锋面识别
计算模型: TEOS-10
分析算法: 动力高度法, 梯度检测
`;
break;
case 'data-fusion':
detailsContent = `
数据融合节点
${node.description}
- 多源数据时空配准
- 最优插值算法
- 卡尔曼滤波融合
- 不确定性评估
融合方法: 变分同化
网格分辨率: 0.1° × 0.1°
`;
break;
case 'data-output':
detailsContent = `
数据输出节点
${node.description}
- 标准格式转换
- 元数据生成
- 可视化产品制作
- 质量报告生成
输出格式: NetCDF-4, HDF5, GeoTIFF
产品类型: L1, L2, L3级数据产品
`;
break;
default:
detailsContent = `${node.title}
${node.description}
`;
}
detailsPanel.innerHTML = detailsContent;
}
// 更新处理统计
function updateProcessingStats() {
const stats = [
{ label: '处理任务', value: Math.floor(Math.random() * 50) + 150, id: 'processing-tasks' },
{ label: '完成任务', value: Math.floor(Math.random() * 30) + 120, id: 'completed-tasks' },
{ label: '等待队列', value: Math.floor(Math.random() * 20) + 10, id: 'pending-tasks' },
{ label: '错误任务', value: Math.floor(Math.random() * 5) + 2, id: 'error-tasks', error: true }
];
stats.forEach(stat => {
const element = document.getElementById(stat.id);
if (element) {
const numberElement = element.querySelector('.stat-number');
if (numberElement) {
numberElement.textContent = stat.value;
if (stat.error) {
element.classList.add('error');
}
}
}
});
// 更新资源监控
updateResourceMonitor();
}
// 更新资源监控
function updateResourceMonitor() {
const resources = [
{ id: 'cpu-usage', value: Math.floor(Math.random() * 30) + 45 },
{ id: 'memory-usage', value: Math.floor(Math.random() * 20) + 60 },
{ id: 'storage-usage', value: Math.floor(Math.random() * 15) + 35 }
];
resources.forEach(resource => {
const element = document.getElementById(resource.id);
if (element) {
const progressRing = element.querySelector('.progress-ring');
const progressValue = element.querySelector('.progress-value');
if (progressRing && progressValue) {
// 更新环形进度条
const percentage = resource.value;
progressRing.style.background = `conic-gradient(var(--accent-blue) ${percentage * 3.6}deg, rgba(255, 255, 255, 0.1) ${percentage * 3.6}deg)`;
progressValue.textContent = `${percentage}%`;
}
}
});
}
// 启动处理监控
function startProcessingMonitor() {
// 模拟处理日志
const logContent = document.querySelector('.log-content');
if (!logContent) return;
const logMessages = [
{ type: 'info', message: '[INFO] 开始处理CTD数据批次 #2024-001' },
{ type: 'info', message: '[INFO] 数据验证完成,通过率: 98.7%' },
{ type: 'warning', message: '[WARN] ADCP设备 #03 数据延迟 5分钟' },
{ type: 'info', message: '[INFO] 质量控制完成,标记异常值 12个' },
{ type: 'info', message: '[INFO] 海洋学参数计算完成' },
{ type: 'error', message: '[ERROR] 重力仪数据校准失败,重试中...' },
{ type: 'info', message: '[INFO] 数据融合完成,生成L3级产品' },
{ type: 'info', message: '[INFO] 输出NetCDF文件: ocean_data_20240115.nc' }
];
let logIndex = 0;
const addLogEntry = () => {
if (logIndex < logMessages.length) {
const log = logMessages[logIndex];
const logEntry = document.createElement('div');
logEntry.className = `log-entry ${log.type}`;
logEntry.textContent = `${new Date().toLocaleTimeString()} ${log.message}`;
logContent.appendChild(logEntry);
logContent.scrollTop = logContent.scrollHeight;
logIndex++;
setTimeout(addLogEntry, Math.random() * 3000 + 2000);
} else {
// 重置日志
setTimeout(() => {
logContent.innerHTML = '';
logIndex = 0;
addLogEntry();
}, 5000);
}
};
addLogEntry();
}
// 设备类型颜色映射
const deviceTypeColors = {
'CTD': '#00ff88',
'ADCP': '#0088ff',
'Gravity': '#ff6600',
'Magnetic': '#ff0066',
'Wave': '#00ffff',
'Depth': '#8800ff',
'Radar': '#ffff00',
'Multi': '#00ff00',
'Buoy': '#ff8800',
'Beidou': '#ff4400',
'Wind': '#4400ff',
'Weather': '#88ff00',
'Sky': '#ff0088',
'Turbulence': '#0044ff',
'Lidar': '#ff6600',
'Visibility': '#66ff00',
'Cloud': '#00aaff',
'Navigation': '#aa00ff'
};
// 设备类型图标映射
const deviceTypeIcons = {
'CTD': '🌊',
'ADCP': '🌀',
'Gravity': '⚖️',
'Magnetic': '🧲',
'Wave': '〰️',
'Depth': '📏',
'Radar': '📡',
'Multi': '🔬',
'Buoy': '🛟',
'Beidou': '🛰️',
'Wind': '💨',
'Weather': '🌤️',
'Sky': '🌌',
'Turbulence': '🌪️',
'Lidar': '🔦',
'Visibility': '👁️',
'Cloud': '☁️',
'Navigation': '🧭'
};
// 获取设备类型的CSS类名
function getDeviceTypeClass(deviceType) {
const typeMap = {
'CTD': 'ctd',
'ADCP': 'adcp',
'Gravity': 'gravity',
'Magnetic': 'magnetic',
'Wave': 'wave',
'Depth': 'depth',
'Radar': 'radar',
'Multi': 'multi',
'Buoy': 'buoy',
'Beidou': 'beidou',
'Wind': 'wind',
'Weather': 'weather',
'Sky': 'sky',
'Turbulence': 'turbulence',
'Lidar': 'lidar',
'Visibility': 'visibility',
'Cloud': 'cloud',
'Navigation': 'navigation'
};
return `device-${typeMap[deviceType] || 'default'}`;
}
// 更新数据流显示函数
function updateDataStream() {
const streamContainer = document.querySelector('.data-stream');
if (!streamContainer) return;
// 随机选择一个设备
const device = oceanDevices[Math.floor(Math.random() * oceanDevices.length)];
const param = device.parameters[Math.floor(Math.random() * device.parameters.length)];
const value = generateRandomValue(param);
const time = new Date().toLocaleTimeString();
// 创建数据流项目
const streamItem = document.createElement('div');
streamItem.className = `stream-item ${getDeviceTypeClass(device.type)}`;
streamItem.innerHTML = `
${time}
${deviceTypeIcons[device.type] || '📊'}
${device.name}
${param}
${value}
`;
// 添加到流中
streamContainer.insertBefore(streamItem, streamContainer.firstChild);
// 限制显示的项目数量
const items = streamContainer.querySelectorAll('.stream-item');
if (items.length > 10) {
items[items.length - 1].remove();
}
// 添加进入动画
streamItem.style.opacity = '0';
streamItem.style.transform = 'translateX(-20px)';
setTimeout(() => {
streamItem.style.transition = 'all 0.3s ease';
streamItem.style.opacity = '1';
streamItem.style.transform = 'translateX(0)';
}, 50);
}
// 更新数据源点渲染函数
function renderDataSourcePoints() {
const earthSphere = document.querySelector('.earth-sphere');
if (!earthSphere) return;
// 清除现有的数据点
earthSphere.querySelectorAll('.data-source-point').forEach(point => point.remove());
earthSphere.querySelectorAll('.data-stream-line').forEach(line => line.remove());
oceanDevices.forEach((device, index) => {
// 创建数据源点
const point = document.createElement('div');
point.className = 'data-source-point';
point.style.backgroundColor = deviceTypeColors[device.type] || '#00d4ff';
point.style.color = deviceTypeColors[device.type] || '#00d4ff';
// 根据经纬度计算位置(简化的球面投影)
const x = ((device.longitude + 180) / 360) * 100;
const y = ((90 - device.latitude) / 180) * 100;
point.style.left = `${x}%`;
point.style.top = `${y}%`;
// 添加点击事件
point.addEventListener('click', () => showDeviceDetails(device));
// 添加悬停提示
point.title = `${device.name} (${device.type})`;
earthSphere.appendChild(point);
// 创建数据流线
if (Math.random() < 0.3) { // 30%的概率显示数据流
const streamLine = document.createElement('div');
streamLine.className = 'data-stream-line';
streamLine.style.background = `linear-gradient(to top, ${deviceTypeColors[device.type] || '#00d4ff'}, transparent)`;
streamLine.style.left = `${x}%`;
streamLine.style.top = `${y}%`;
streamLine.style.animationDelay = `${Math.random() * 3}s`;
earthSphere.appendChild(streamLine);
}
});
}
// 更新设备详情显示函数
function showDeviceDetails(device) {
// 创建模态框
const modal = document.createElement('div');
modal.className = 'device-modal';
modal.innerHTML = `
设备类型: ${device.type}
位置: ${device.latitude.toFixed(4)}°N, ${device.longitude.toFixed(4)}°E
状态: ${device.status === 'online' ? '在线' : '离线'}
设备ID: ${device.id}
监测参数
${device.parameters.map(param => `${param}`).join('')}
实时数据
${device.parameters.slice(0, 6).map(param => `
${param}
${generateRandomValue(param)}
`).join('')}
`;
// 添加关闭事件
modal.querySelector('.device-modal-close').addEventListener('click', () => {
modal.remove();
});
modal.addEventListener('click', (e) => {
if (e.target === modal) {
modal.remove();
}
});
document.body.appendChild(modal);
}