You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1182 lines
40 KiB
HTML

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>海洋数据成果展示</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.0/echarts.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts-gl/2.0.0/echarts-gl.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Arial, sans-serif;
}
body {
background: linear-gradient(135deg, #0c1a2d 0%, #0d2b4a 100%);
color: #e0f0ff;
overflow-x: hidden;
min-height: 100vh;
}
/* 新增顶部标题栏样式 */
.topDiv {
width: 100%;
height: 8vh;
background: url('/assets/img/topBg.png') top no-repeat;
background-size: 100% 115%;
display: flex;
justify-content: center;
z-index: 990;
position: relative;
/* background-color: rgba(12, 42, 73, 0.8); */
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.topDiv .center {
font-family: PangMenZhengDao, 'Source Han Sans CN';
font-weight: 400;
font-size: 4.1vh;
color: #ffffff;
align-self: center;
margin-top: -40px;
}
.topDiv .left {
position: absolute;
top: 3vh;
left: 1vw;
color: #ffffff;
}
.topDiv .left span:nth-child(1) {
font-weight: bold;
font-size: 0.8vw;
margin-right: 0.5vh;
}
.topDiv .left span:nth-child(2) {
font-weight: bold;
font-size: 1.2vw;
}
.topDiv .right {
position: absolute;
top: 3vh;
right: 0;
color: #ffffff;
display: flex;
align-items: center;
}
.topDiv .right img:nth-child(1) {}
.topDiv .right span {
font-weight: bold;
font-size: 1.2vw;
}
.topDiv .icon-home {
position: absolute;
top: 1vh;
right: 8vw;
width: 4vh;
cursor: pointer;
}
/* 控制面板 */
.control-panel {
width: 100%;
padding: 15px 20px;
background: rgba(12, 42, 73, 0.7);
backdrop-filter: blur(10px);
border-bottom: 1px solid rgba(64, 156, 255, 0.3);
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 15px;
}
.control-group {
display: flex;
align-items: center;
gap: 10px;
}
.control-label {
font-size: 0.9rem;
color: #a0d2ff;
}
.control-select {
background: rgba(25, 55, 95, 0.8);
border: 1px solid rgba(64, 156, 255, 0.5);
border-radius: 4px;
color: #e0f0ff;
padding: 6px 12px;
font-size: 0.9rem;
cursor: pointer;
}
.control-button {
background: linear-gradient(90deg, #1a6aa9 0%, #4fc3f7 100%);
border: none;
border-radius: 4px;
color: #ffffff;
padding: 6px 15px;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.3s ease;
}
.control-button:hover {
background: linear-gradient(90deg, #4fc3f7 0%, #1a6aa9 100%);
box-shadow: 0 0 10px rgba(79, 195, 247, 0.5);
}
/* 仪表盘布局 */
.dashboard {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: repeat(6, 1fr);
gap: 15px;
padding: 15px;
height: calc(100vh - 8vh - 80px);
}
.dashboard-item {
background: rgba(12, 42, 73, 0.7);
backdrop-filter: blur(10px);
border: 1px solid rgba(64, 156, 255, 0.3);
border-radius: 8px;
overflow: hidden;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
transition: all 0.3s ease;
position: relative;
}
.dashboard-item:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.4);
border-color: rgba(79, 195, 247, 0.5);
}
.dashboard-item-header {
background: url(/assets/img/common/homeTitle2.png) no-repeat;
background-position: center;
background-size: 120% 120%;
height: 50px;
padding: 10px 15px;
border-bottom: 1px solid rgba(79, 195, 247, 0.3);
text-align: center;
/* height: 40px;
background: linear-gradient(to right, #1a3a5f, #2a5a8f);
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 15px;
border-bottom: 1px solid rgba(79, 195, 247, 0.3);
text-align: center; */
}
.dashboard-item-title {
font-size: 1.2rem;
font-weight: 600;
color: #ffffff;
}
.dashboard-item-controls {
display: flex;
gap: 5px;
}
.dashboard-item-control {
background: rgba(255, 255, 255, 0.1);
border: none;
border-radius: 3px;
color: #e0f2ff;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.2s ease;
}
.dashboard-item-control:hover {
background: rgba(255, 255, 255, 0.2);
}
.dashboard-item-content {
height: calc(100% - 50px);
padding: 10px;
}
/* 特定布局 */
.earth-globe {
grid-column: 1 / 9;
grid-row: 1 / 5;
}
.time-series {
grid-column: 9 / 13;
grid-row: 1 / 4;
}
.stats-cards {
grid-column: 1 / 5;
grid-row: 5 / 7;
}
.profile-chart {
grid-column: 5 / 9;
grid-row: 5 / 7;
}
.data-table {
grid-column: 9 / 13;
grid-row: 4 / 7;
}
/* 统计卡片组 */
.stats-container {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
gap: 10px;
height: 100%;
}
.stat-card {
background: rgba(25, 55, 95, 0.6);
border-radius: 8px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
/* padding: 15px; */
border: 1px solid rgba(64, 156, 255, 0.2);
transition: all 0.3s ease;
}
.stat-card:hover {
transform: scale(1.03);
border-color: rgba(79, 195, 247, 0.5);
box-shadow: 0 0 15px rgba(79, 195, 247, 0.3);
}
.stat-value {
font-size: 2rem;
font-weight: bold;
color: #4fc3f7;
margin-bottom: 5px;
text-shadow: 0 0 10px rgba(79, 195, 247, 0.5);
}
.stat-label {
font-size: 0.9rem;
color: #a0d2ff;
text-align: center;
}
/* 数据表格 */
.data-table-content {
height: 100%;
overflow-y: auto;
}
.data-table-row {
display: flex;
justify-content: space-between;
padding: 10px 5px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.data-table-row:last-child {
border-bottom: none;
}
.data-table-cell {
flex: 1;
text-align: center;
font-size: 0.9rem;
}
.data-table-header {
font-weight: bold;
color: #4fc3f7;
border-bottom: 1px solid rgba(79, 195, 247, 0.3);
padding-bottom: 8px;
}
/* 响应式调整 */
@media (max-width: 1200px) {
.dashboard {
grid-template-columns: repeat(6, 1fr);
grid-template-rows: repeat(8, 1fr);
}
.earth-globe {
grid-column: 1 / 7;
grid-row: 1 / 5;
}
.time-series {
grid-column: 1 / 7;
grid-row: 5 / 7;
}
.stats-cards {
grid-column: 1 / 4;
grid-row: 7 / 9;
}
.profile-chart {
grid-column: 4 / 7;
grid-row: 7 / 9;
}
.data-table {
grid-column: 1 / 7;
grid-row: 9 / 11;
}
}
/* 滚动条样式 */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: rgba(12, 42, 73, 0.3);
border-radius: 4px;
}
::-webkit-scrollbar-thumb {
background: rgba(106, 149, 201, 0.5);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(106, 149, 201, 0.7);
}
/* 动画效果 */
@keyframes pulse {
0% {
box-shadow: 0 0 0 0 rgba(79, 195, 247, 0.4);
}
70% {
box-shadow: 0 0 0 10px rgba(79, 195, 247, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(79, 195, 247, 0);
}
}
.pulse {
animation: pulse 2s infinite;
}
</style>
</head>
<body>
<!-- 顶部标题栏 -->
<div class="topDiv">
<div class="left">
<span id="current-date">2025年9月17日</span>
<span id="current-time">15:18:00</span>
</div>
<div class="center">全球海洋环境综合监测与分析平台</div>
<div class="right">
<img src="/common/images/logo_gt.png" alt="" />
</div>
</div>
<!-- 控制面板 -->
<div class="control-panel">
<div class="control-group">
<span class="control-label">数据类型:</span>
<select class="control-select" id="dataTypeSelect">
<option value="temperature">海水温度</option>
<option value="chlorophyll">叶绿素浓度</option>
<option value="salinity">盐度</option>
<option value="wave">波浪数据</option>
</select>
</div>
<div class="control-group">
<span class="control-label">时间范围:</span>
<select class="control-select" id="timeRangeSelect">
<option value="24h">过去24小时</option>
<option value="7d">过去7天</option>
<option value="30d">过去30天</option>
<option value="custom">自定义</option>
</select>
</div>
<div class="control-group">
<span class="control-label">地理区域:</span>
<select class="control-select" id="regionSelect">
<option value="global">全球</option>
<option value="pacific">太平洋</option>
<option value="atlantic">大西洋</option>
<option value="indian">印度洋</option>
<option value="south-china-sea">南海</option>
</select>
</div>
<div class="control-group">
<button class="control-button" id="playAnimation">
<i class="fas fa-play"></i> 播放动画
</button>
<button class="control-button" id="pauseAnimation">
<i class="fas fa-pause"></i> 暂停
</button>
<button class="control-button" id="resetView">
<i class="fas fa-sync"></i> 重置视图
</button>
</div>
</div>
<!-- 仪表盘 -->
<div class="dashboard">
<!-- 3D地球模型 -->
<div class="dashboard-item earth-globe">
<div class="dashboard-item-header">
<div class="dashboard-item-title">全球海洋温度分布</div>
<!-- <div class="dashboard-item-controls">
<button class="dashboard-item-control"><i class="fas fa-expand"></i></button>
</div> -->
</div>
<div class="dashboard-item-content" id="earthGlobe"></div>
</div>
<!-- 时序图 -->
<div class="dashboard-item time-series">
<div class="dashboard-item-header">
<div class="dashboard-item-title">特定区域时序变化</div>
<!-- <div class="dashboard-item-controls">
<button class="dashboard-item-control"><i class="fas fa-expand"></i></button>
</div> -->
</div>
<div class="dashboard-item-content" id="timeSeriesChart"></div>
</div>
<!-- 统计卡片组 -->
<div class="dashboard-item stats-cards">
<div class="dashboard-item-header">
<div class="dashboard-item-title">关键指标</div>
<!-- <div class="dashboard-item-controls">
<button class="dashboard-item-control"><i class="fas fa-sync"></i></button>
</div> -->
</div>
<div class="dashboard-item-content">
<div class="stats-container">
<div class="stat-card pulse">
<div class="stat-value" id="avgTemp">24.7°C</div>
<div class="stat-label">平均温度</div>
</div>
<div class="stat-card">
<div class="stat-value" id="maxWave">12.3m</div>
<div class="stat-label">最大波高</div>
</div>
<div class="stat-card">
<div class="stat-value" id="anomalyCount">8</div>
<div class="stat-label">异常区域数量</div>
</div>
<div class="stat-card">
<div class="stat-value" id="avgSalinity">35.2‰</div>
<div class="stat-label">平均盐度</div>
</div>
</div>
</div>
</div>
<!-- 剖面图 -->
<div class="dashboard-item profile-chart">
<div class="dashboard-item-header">
<div class="dashboard-item-title">温度/盐度垂直剖面</div>
<!-- <div class="dashboard-item-controls">
<button class="dashboard-item-control"><i class="fas fa-expand"></i></button>
</div> -->
</div>
<div class="dashboard-item-content" id="profileChart"></div>
</div>
<!-- 数据表格 -->
<div class="dashboard-item data-table">
<div class="dashboard-item-header">
<div class="dashboard-item-title">区域数据详情</div>
<!-- <div class="dashboard-item-controls">
<button class="dashboard-item-control"><i class="fas fa-download"></i></button>
</div> -->
</div>
<div class="dashboard-item-content">
<div class="data-table-content" id="dataTableContent">
<!-- 表格内容将通过JavaScript动态生成 -->
</div>
</div>
</div>
</div>
<script>
// 全局变量
let earthChart, timeSeriesChart, profileChart;
let animationInterval;
let currentDataType = 'temperature';
let currentTimeRange = '24h';
let currentRegion = 'global';
// 数据存储
let timeSeriesData = {
time: [],
temperature: [],
chlorophyll: [],
salinity: []
};
let profileData = {
depth: [],
temperature: [],
salinity: []
};
let tableData = [];
// 初始化函数
function init() {
// 更新当前时间
updateCurrentTime();
setInterval(updateCurrentTime, 1000);
// 初始化数据
initData();
// 初始化图表
initEarthGlobe();
initTimeSeriesChart();
initProfileChart();
initDataTable();
// 添加事件监听器
document.getElementById('dataTypeSelect').addEventListener('change', function (e) {
currentDataType = e.target.value;
updateAllCharts();
});
document.getElementById('timeRangeSelect').addEventListener('change', function (e) {
currentTimeRange = e.target.value;
updateAllCharts();
});
document.getElementById('regionSelect').addEventListener('change', function (e) {
currentRegion = e.target.value;
updateAllCharts();
});
document.getElementById('playAnimation').addEventListener('click', startAnimation);
document.getElementById('pauseAnimation').addEventListener('click', pauseAnimation);
document.getElementById('resetView').addEventListener('click', resetView);
// 启动数据更新定时器
setInterval(updateAllData, 3000);
}
// 初始化数据
function initData() {
// 初始化时序数据
const now = new Date();
for (let i = 23; i >= 0; i--) {
const time = new Date(now);
time.setHours(now.getHours() - i);
timeSeriesData.time.push(time.getHours() + ':00');
// 生成模拟数据
timeSeriesData.temperature.push(20 + Math.sin(i / 3) * 5 + Math.random() * 2);
timeSeriesData.chlorophyll.push(0.2 + Math.sin(i / 4) * 0.15 + Math.random() * 0.1);
timeSeriesData.salinity.push(34 + Math.cos(i / 5) * 1 + Math.random() * 0.5);
}
// 初始化剖面数据
for (let i = 0; i <= 1000; i += 50) {
profileData.depth.push(i);
// 生成模拟数据并保留两位小数
const temp = parseFloat(25 - (i / 1000) * 20 + Math.random() * 2).toFixed(2);
const salinity = parseFloat(34 + (i / 1000) * 1 + Math.random() * 0.5).toFixed(2);
profileData.temperature.push(parseFloat(temp)); // 转换回数字用于计算
profileData.salinity.push(parseFloat(salinity)); // 转换回数字用于计算
}
// 初始化表格数据
tableData = [
{ region: '南海', temperature: 28.5, salinity: 34.1, chlorophyll: 0.32 },
{ region: '东海', temperature: 22.3, salinity: 33.8, chlorophyll: 0.45 },
{ region: '黄海', temperature: 18.7, salinity: 32.5, chlorophyll: 0.28 },
{ region: '渤海', temperature: 16.2, salinity: 31.2, chlorophyll: 0.51 },
{ region: '西太平洋', temperature: 26.8, salinity: 35.1, chlorophyll: 0.18 }
];
}
// 更新当前时间
function updateCurrentTime() {
const now = new Date();
const dateStr = `${now.getFullYear()}${now.getMonth() + 1}${now.getDate()}`;
const timeStr = now.toLocaleTimeString('zh-CN', { hour12: false });
document.getElementById('current-date').textContent = dateStr;
document.getElementById('current-time').textContent = timeStr;
}
// 初始化3D地球
function initEarthGlobe() {
const chartContainer = document.getElementById('earthGlobe');
earthChart = echarts.init(chartContainer, null, { renderer: 'canvas' });
// 配置项
const option = {
backgroundColor: 'transparent',
globe: {
baseTexture: "/assets/img/earth-topology.png",
heightTexture: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAyNCIgaGVpZ2h0PSI1MTIiIHZpZXdCb3g9IjAgMCAxMDI0IDUxMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjEwMjQiIGhlaWdodD0iNTEyIiBmaWxsPSIjMGMxYTJkIi8+CjxwYXRoIGQ9Ik01MTIgMjU2QzUxMiAzOTcuODgzIDM5Ny44ODMgNTEyIDI1NiA1MTIgMTA0LjExNyA1MTIgMCAzOTcuODgzIDAgMjU2QzAgMTE0LjExNyAxMDQuMTE3IDAgMjU2IDBDMzk3Ljg4MyAwIDUxMiAxMTQuMTE3IDUxMiAyNTZaIiBmaWxsPSIjMWIzZDc5Ii8+Cjwvc3ZnPg==",
displacementScale: 0.04,
displacementQuality: 'medium',
environment: "/assets/img/night-sky.png",
globeRadius: 100,
globeOuterRadius: 120,
shading: 'realistic',
realisticMaterial: {
roughness: 0.8,
metalness: 0
},
postEffect: {
enable: true,
bloom: {
enable: true,
intensity: 0.1
}
},
light: {
main: {
intensity: 2,
shadow: true
},
ambientCubemap: {
texture: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAyNCIgaGVpZ2h0PSI1MTIiIHZpZXdCb3g9IjAgMCAxMDI0IDUxMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjEwMjQiIGhlaWdodD0iNTEyIiBmaWxsPSIjMGMxYTJkIi8+Cjwvc3ZnPg=='
}
},
viewControl: {
autoRotate: true,
autoRotateSpeed: 1,
// autoRotateDirection: 'left', // 固定向左旋转
targetCoord: [105, 35], // 默认视角对准中国 (经度105, 纬度35)
zoom: 1.2 // 适当的缩放级别
},
layers: [
{
type: 'blend',
blendTo: 'emission',
texture: "/assets/img/earth-night.jpg",
intensity: 1.5
}
]
},
series: [] // 初始时系列为空
};
earthChart.setOption(option);
// 添加温度数据层
updateEarthData();
}
function updateEarthData() {
const temperatureData = [];
// 生成模拟温度数据
for (let i = 0; i < 1000; i++) {
const lat = Math.random() * 180 - 90;
const lng = Math.random() * 360 - 180;
const temp = 10 + Math.random() * 25; // 10-35°C
// 使用4个值[经度, 纬度, 高度(设为0使数据贴合地球表面), 温度值]
temperatureData.push([lng, lat, 0, temp]);
}
// 只更新系列数据,使用 replaceMerge 确保不重置其他配置
const option = {
series: [{
type: 'scatter3D',
coordinateSystem: 'globe',
blendMode: 'lighter',
symbolSize: 2,
itemStyle: {
color: function (params) {
const temp = params.value[3]; // 温度值现在是第4个元素
if (temp < 15) return '#4A90E2'; // 冷色
if (temp < 20) return '#7ED321'; // 凉色
if (temp < 25) return '#F5A623'; // 暖色
return '#D0021B'; // 热色
},
opacity: 0.8
},
data: temperatureData
}]
};
// 使用 replaceMerge 方式更新,避免重置视图
earthChart.setOption(option, {
replaceMerge: ['series']
});
}
// 初始化时序图
function initTimeSeriesChart() {
const chartContainer = document.getElementById('timeSeriesChart');
timeSeriesChart = echarts.init(chartContainer, null, { renderer: 'canvas' });
updateTimeSeriesChart();
}
function updateTimeSeriesChart() {
const option = {
backgroundColor: 'transparent',
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function (params) {
let result = params[0].name + '<br/>';
params.forEach(param => {
// 保留两位小数
const value = parseFloat(param.value).toFixed(2);
result += `${param.seriesName}: ${value}${param.seriesName.includes('温度') ? '°C' : param.seriesName.includes('叶绿素') ? 'mg/m³' : '‰'}<br/>`;
});
return result;
}
},
legend: {
data: ['温度', '叶绿素', '盐度'],
textStyle: {
color: '#e0f0ff'
},
top: 10
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '20%',
containLabel: true
},
xAxis: {
type: 'category',
data: timeSeriesData.time,
axisLine: {
lineStyle: {
color: '#4fc3f7'
}
},
axisLabel: {
color: '#a0d2ff'
}
},
yAxis: [
{
type: 'value',
name: '温度(°C)',
position: 'left',
axisLine: {
lineStyle: {
color: '#ff7043'
}
},
axisLabel: {
formatter: '{value} °C',
color: '#a0d2ff'
},
splitLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.1)'
}
}
},
{
type: 'value',
name: '叶绿素(mg/m³)',
position: 'right',
axisLine: {
lineStyle: {
color: '#66bb6a'
}
},
axisLabel: {
formatter: '{value} mg/m³',
color: '#a0d2ff'
},
splitLine: {
show: false
}
}
],
series: [
{
name: '温度',
type: 'line',
smooth: true,
lineStyle: {
width: 3,
color: '#ff7043'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: 'rgba(255, 112, 67, 0.5)'
}, {
offset: 1, color: 'rgba(255, 112, 67, 0.1)'
}]
}
},
data: timeSeriesData.temperature.map(value => parseFloat(value).toFixed(2))
},
{
name: '叶绿素',
type: 'line',
smooth: true,
yAxisIndex: 1,
lineStyle: {
width: 3,
color: '#66bb6a'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: 'rgba(102, 187, 106, 0.5)'
}, {
offset: 1, color: 'rgba(102, 187, 106, 0.1)'
}]
}
},
data: timeSeriesData.chlorophyll.map(value => parseFloat(value).toFixed(2))
},
{
name: '盐度',
type: 'line',
smooth: true,
lineStyle: {
width: 3,
color: '#4fc3f7'
},
data: timeSeriesData.salinity.map(value => parseFloat(value).toFixed(2))
}
]
};
timeSeriesChart.setOption(option);
}
// 初始化剖面图
function initProfileChart() {
const chartContainer = document.getElementById('profileChart');
profileChart = echarts.init(chartContainer, null, { renderer: 'canvas' });
updateProfileChart();
}
// 修改 updateProfileChart 函数中的 tooltip formatter 部分
function updateProfileChart() {
const option = {
backgroundColor: 'transparent',
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
},
formatter: function (params) {
// 自定义提示框内容,只显示需要的信息,并保留两位小数
let result = '';
params.forEach((param, index) => {
if (index === 0) {
result += `深度: ${param.data[1]}m<br/>`;
}
// 保留两位小数
const value = parseFloat(param.data[0]).toFixed(2);
result += `${param.seriesName}: ${value}${param.seriesName.includes('温度') ? '°C' : '‰'}<br/>`;
});
return result;
}
},
legend: {
data: ['温度', '盐度'],
textStyle: {
color: '#e0f0ff'
},
top: 10
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '15%',
containLabel: true
},
xAxis: [
{
type: 'value',
name: '温度(°C)',
position: 'bottom',
axisLine: {
lineStyle: {
color: '#ff7043'
}
},
axisLabel: {
formatter: '{value} °C',
color: '#a0d2ff'
},
splitLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.1)'
}
}
},
{
type: 'value',
name: '盐度(‰)',
position: 'top',
axisLine: {
lineStyle: {
color: '#4fc3f7'
}
},
axisLabel: {
formatter: '{value} ‰',
color: '#a0d2ff'
},
splitLine: {
show: false
}
}
],
yAxis: {
type: 'value',
name: '深度(m)',
inverse: true,
axisLine: {
lineStyle: {
color: '#a0d2ff'
}
},
axisLabel: {
formatter: '{value} m',
color: '#a0d2ff'
},
splitLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.1)'
}
}
},
series: [
{
name: '温度',
type: 'line',
xAxisIndex: 0,
smooth: true,
lineStyle: {
width: 3,
color: '#ff7043'
},
data: profileData.temperature.map((temp, index) => [parseFloat(temp).toFixed(2), profileData.depth[index]])
},
{
name: '盐度',
type: 'line',
xAxisIndex: 1,
smooth: true,
lineStyle: {
width: 3,
color: '#4fc3f7'
},
data: profileData.salinity.map((salinity, index) => [parseFloat(salinity).toFixed(2), profileData.depth[index]])
}
]
};
profileChart.setOption(option);
}
// 初始化数据表格
function initDataTable() {
updateDataTable();
}
// 更新数据表格
function updateDataTable() {
const container = document.getElementById('dataTableContent');
let html = `
<div class="data-table-row data-table-header">
<div class="data-table-cell">区域</div>
<div class="data-table-cell">温度(°C)</div>
<div class="data-table-cell">盐度(‰)</div>
<div class="data-table-cell">叶绿素(mg/m³)</div>
</div>
`;
tableData.forEach(item => {
html += `
<div class="data-table-row">
<div class="data-table-cell">${item.region}</div>
<div class="data-table-cell">${item.temperature.toFixed(1)}</div>
<div class="data-table-cell">${item.salinity.toFixed(1)}</div>
<div class="data-table-cell">${item.chlorophyll.toFixed(2)}</div>
</div>
`;
});
container.innerHTML = html;
}
// 修改 updateAllData 函数中的剖面数据更新部分
function updateAllData() {
// 更新时序数据
const now = new Date();
timeSeriesData.time.shift();
timeSeriesData.time.push(now.getHours() + ':' + now.getMinutes().toString().padStart(2, '0'));
timeSeriesData.temperature.shift();
timeSeriesData.temperature.push(20 + Math.sin(now.getHours() / 3) * 5 + Math.random() * 2);
timeSeriesData.chlorophyll.shift();
timeSeriesData.chlorophyll.push(0.2 + Math.sin(now.getHours() / 4) * 0.15 + Math.random() * 0.1);
timeSeriesData.salinity.shift();
timeSeriesData.salinity.push(34 + Math.cos(now.getHours() / 5) * 1 + Math.random() * 0.5);
// 更新剖面数据并保留两位小数
profileData.temperature = profileData.temperature.map(temp =>
parseFloat(Math.max(5, Math.min(30, temp + (Math.random() - 0.5) * 0.5)).toFixed(2))
);
profileData.salinity = profileData.salinity.map(salinity =>
parseFloat(Math.max(30, Math.min(38, salinity + (Math.random() - 0.5) * 0.2)).toFixed(2))
);
// 更新表格数据
tableData = tableData.map(item => ({
region: item.region,
temperature: Math.max(10, Math.min(35, item.temperature + (Math.random() - 0.5) * 0.3)),
salinity: Math.max(30, Math.min(38, item.salinity + (Math.random() - 0.5) * 0.1)),
chlorophyll: Math.max(0.1, Math.min(0.8, item.chlorophyll + (Math.random() - 0.5) * 0.05))
}));
// 更新统计卡片
updateStatsCards();
// 更新所有图表
updateAllCharts();
}
// 更新所有图表
function updateAllCharts() {
//updateEarthData();
updateTimeSeriesChart();
updateProfileChart();
updateDataTable();
}
// 更新统计卡片
function updateStatsCards() {
// 计算平均值
const avgTemp = timeSeriesData.temperature.reduce((a, b) => a + b, 0) / timeSeriesData.temperature.length;
const avgSalinity = timeSeriesData.salinity.reduce((a, b) => a + b, 0) / timeSeriesData.salinity.length;
// 更新卡片数据
document.getElementById('avgTemp').textContent = avgTemp.toFixed(1) + '°C';
document.getElementById('maxWave').textContent = (8 + Math.random() * 5).toFixed(1) + 'm';
document.getElementById('anomalyCount').textContent = Math.floor(3 + Math.random() * 8);
document.getElementById('avgSalinity').textContent = avgSalinity.toFixed(1) + '‰';
}
// 开始动画
function startAnimation() {
if (animationInterval) {
clearInterval(animationInterval);
}
animationInterval = setInterval(() => {
updateAllData();
}, 2000);
document.getElementById('playAnimation').disabled = true;
document.getElementById('pauseAnimation').disabled = false;
}
// 暂停动画
function pauseAnimation() {
if (animationInterval) {
clearInterval(animationInterval);
animationInterval = null;
}
document.getElementById('playAnimation').disabled = false;
document.getElementById('pauseAnimation').disabled = true;
}
// 重置视图
function resetView() {
// 重置所有选择器
document.getElementById('dataTypeSelect').value = 'temperature';
document.getElementById('timeRangeSelect').value = '24h';
document.getElementById('regionSelect').value = 'global';
// 更新当前选择
currentDataType = 'temperature';
currentTimeRange = '24h';
currentRegion = 'global';
// 重新初始化数据
initData();
// 更新图表
updateAllCharts();
// 暂停动画
pauseAnimation();
}
// 窗口大小改变时调整图表大小
window.addEventListener('resize', function () {
if (earthChart) earthChart.resize();
if (timeSeriesChart) timeSeriesChart.resize();
if (profileChart) profileChart.resize();
});
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>