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.

1926 lines
60 KiB
HTML

<!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://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>
<!-- 确保这些文件路径正确 -->
<script src="./model/mars3d-cesium/Build/Cesium/Cesium.js"></script>
<link href="./model/mars3d-cesium/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
<script src="./model/mars3d/mars3d.js"></script>
<link href="./model/mars3d/mars3d.css" rel="stylesheet">
<!-- Mars3D热力图插件 - 使用正确的CDN路径 -->
<!-- <script src="https://cdn.jsdelivr.net/npm/mars3d-plugin-heatmap/dist/mars3d-plugin-heatmap.min.js"></script> -->
<style>
/* 控制面板内容区域添加滚动条 */
.control-panel-content {
flex: 1;
overflow-y: auto;
padding-right: 10px;
margin-right: -10px;
}
/* 美化控制面板内容区域的滚动条 */
.control-panel-content::-webkit-scrollbar {
width: 4px;
}
.control-panel-content::-webkit-scrollbar-track {
background: rgba(12, 42, 73, 0.3);
border-radius: 4px;
}
.control-panel-content::-webkit-scrollbar-thumb {
background: rgba(79, 195, 247, 0.5);
border-radius: 4px;
}
.control-panel-content::-webkit-scrollbar-thumb:hover {
background: rgba(79, 195, 247, 0.8);
}
/* 替换原有的过滤器样式为以下代码 */
/* 修改过滤器相关样式 */
.filter-options {
display: flex;
flex-direction: column;
gap: 12px;
}
.filter-option {
display: flex;
align-items: center;
position: relative;
padding-left: 30px;
margin-bottom: 5px;
cursor: pointer;
transition: all 0.3s ease;
}
.filter-option:hover {
transform: translateX(5px);
background: rgba(40, 80, 130, 0.3);
border-radius: 4px;
}
.filter-option input[type="checkbox"] {
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0;
}
.filter-option .checkmark {
position: absolute;
left: 0;
height: 20px;
width: 20px;
background-color: rgba(25, 55, 95, 0.6);
border: 2px solid #4fc3f7;
border-radius: 4px;
transition: all 0.3s ease;
pointer-events: all;
/* 确保可以点击 */
}
.filter-option:hover .checkmark {
background-color: rgba(79, 195, 247, 0.2);
}
.filter-option input:checked~.checkmark {
background-color: #4fc3f7;
}
.filter-option .checkmark:after {
content: "";
position: absolute;
display: none;
}
.filter-option input:checked~.checkmark:after {
display: block;
}
.filter-option .checkmark:after {
left: 6px;
top: 2px;
width: 6px;
height: 10px;
border: solid white;
border-width: 0 2px 2px 0;
transform: rotate(45deg);
}
.filter-option label {
font-size: 0.95rem;
color: #e0f0ff;
padding: 5px 0;
cursor: pointer;
width: 100%;
margin-left: 10px;
user-select: none;
/* 防止文本选择 */
}
.control-title {
font-size: 1.1rem;
margin: 15px 0 10px 0;
color: #4fc3f7;
padding-bottom: 5px;
border-bottom: 1px solid rgba(79, 195, 247, 0.3);
}
.control-group {
margin-bottom: 20px;
padding: 10px;
background: rgba(16, 36, 62, 0.3);
border-radius: 8px;
border: 1px solid rgba(64, 156, 255, 0.2);
}
/* 优化滚动条以确保内容可见 */
/* .info-panel {
overflow-y: auto;
} */
/* 美化滚动条 */
.info-panel::-webkit-scrollbar {
width: 4px;
}
.info-panel::-webkit-scrollbar-track {
background: rgba(12, 42, 73, 0.3);
border-radius: 4px;
}
.info-panel::-webkit-scrollbar-thumb {
background: rgba(79, 195, 247, 0.5);
border-radius: 4px;
}
.info-panel::-webkit-scrollbar-thumb:hover {
background: rgba(79, 195, 247, 0.8);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Arial, sans-serif;
}
body {
background: url('/assets/img/bg.png') no-repeat;
background-size: 100% 100%;
color: #e0f0ff;
overflow: hidden;
height: 100vh;
}
/* 定义本地字体 */
@font-face {
font-family: 'DS-Digital';
/* 自定义字体族名称 */
src: url('/assets/fonts/DS-Digita.TTF') format('truetype');
/* 指定字体文件路径和格式 */
font-weight: normal;
font-style: normal;
}
/* 定义本地字体 */
@font-face {
font-family: 'pmzd';
/* 自定义字体族名称 */
src: url('/assets/fonts/PMZD.TTF') format('truetype');
/* 指定字体文件路径和格式 */
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'YouSheBiaoTiHei';
/* 自定义字体族名称 */
src: url('/assets/fonts/YouSheBiaoTiHei.ttf') format('truetype');
/* 指定字体文件路径和格式 */
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'qweather';
/* 自定义字体族名称 */
src: url('/assets/fonts/qweather-icons.ttf') format('truetype');
/* 指定字体文件路径和格式 */
font-weight: normal;
font-style: normal;
}
/* 新增顶部标题栏样式 */
.topDiv {
width: 100%;
height: 8vh;
background: url('/assets/img/topBg2.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: 'pmzd', 'DS-Digital', 'PangMenZhengDao', 'Source Han Sans CN', sans-serif;
/* 优先使用 DS-Digital 字体 */
/* font-family: PangMenZhengDao, 'Source Han Sans CN'; */
font-weight: 400;
font-size: 4vh;
color: #ffffff;
align-self: center;
margin-top: -10px;
}
.topDiv .left {
position: absolute;
top: 4vh;
left: 3vw;
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;
}
.container {
display: flex;
height: calc(100vh - 8vh - 20px);
position: relative;
margin-bottom: 20px;
}
/* 左侧信息面板 */
.info-panel {
width: 300px;
height: 100%;
padding: 20px;
background: rgba(12, 42, 73, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(64, 156, 255, 0.3);
box-shadow: 5px 0 15px rgba(0, 0, 0, 0.3);
z-index: 10;
border-radius: 8px;
position: absolute;
left: 15px;
top: 0;
display: flex;
flex-direction: column;
}
/* 右侧控制面板 */
.control-panel {
width: 280px;
height: 100%;
padding: 20px;
background: rgba(12, 42, 73, 0.9);
backdrop-filter: blur(10px);
border: 1px solid rgba(64, 156, 255, 0.3);
box-shadow: -5px 0 15px rgba(0, 0, 0, 0.3);
z-index: 10;
border-radius: 8px;
position: absolute;
right: 15px;
top: 0;
display: flex;
flex-direction: column;
}
/* 卡片头部样式 */
/* .card-header {
height: 40px;
background: linear-gradient(to right, #1a3a5f, #2a5a8f);
display: flex;
justify-content: center;
align-items: center;
border-radius: 8px 8px 0 0 !important;
border-bottom: 1px solid #4fc3f7;
padding: 12px 20px;
position: relative;
margin: -20px -20px 20px -20px;
}
.card-header span {
font-size: 1.2rem;
letter-spacing: 1px;
font-family: 'Microsoft YaHei';
font-weight: 400;
color: #ffffff;
} */
.stats-container {
display: flex;
flex-direction: column;
gap: 15px;
margin-bottom: 25px;
}
.stat-card {
background: rgba(25, 55, 95, 0.6);
/* background: url('/assets/img/common/kva2.png') no-repeat; */
/* background-size: 100% 100%; */
border-radius: 10px;
padding: 15px;
border-left: 4px solid #4fc3f7;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
}
.stat-label {
font-size: 0.9rem;
color: #a0d2ff;
margin-bottom: 5px;
}
.stat-value {
font-size: 1.8rem;
font-weight: bold;
color: #4fc3f7;
}
.data-list {
flex: 1;
overflow-y: auto;
margin-top: 10px;
padding-right: 5px;
}
.data-item {
min-width: 200px;
background: rgba(25, 55, 95, 0.6);
border-radius: 8px;
padding: 10px;
border-left: 3px solid #4fc3f7;
transition: all 0.3s ease;
margin-bottom: 10px;
cursor: pointer;
}
.data-item:hover {
transform: translateX(5px);
background: rgba(40, 80, 130, 0.7);
}
.stream-device-info {
display: flex;
align-items: center;
margin-bottom: 8px;
}
.stream-device-icon {
font-size: 1.5rem;
margin-right: 10px;
}
.stream-device-details {
flex: 1;
}
.stream-device-name {
font-weight: bold;
color: #4fc3f7;
font-size: 0.9rem;
}
.stream-parameter {
font-size: 0.8rem;
color: #a0d2ff;
}
.stream-value-section {
text-align: right;
}
.stream-value {
font-weight: bold;
font-size: 1.1rem;
font-family: 'Courier New', monospace;
}
.stream-timestamp {
font-size: 0.7rem;
color: #81d4fa;
}
.control-group {
margin-bottom: 25px;
}
.control-title {
font-size: 1.2rem;
margin-bottom: 15px;
color: #4fc3f7;
}
.toggle-switch {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.switch-label {
margin-right: 10px;
font-size: 1rem;
}
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 30px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #2c3e50;
transition: .4s;
border-radius: 34px;
}
.slider:before {
position: absolute;
content: "";
height: 22px;
width: 22px;
left: 4px;
bottom: 4px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
input:checked+.slider {
background-color: #4fc3f7;
}
input:checked+.slider:before {
transform: translateX(30px);
}
.filter-options {
display: flex;
flex-direction: column;
gap: 10px;
}
.filter-option {
display: flex;
align-items: center;
}
.filter-option input {
margin-right: 10px;
}
/* 地球容器样式 */
.earth-container {
flex: 1;
height: 100%;
position: relative;
/* margin: 0 300px 0 320px; */
background: #0c1a2d;
}
#earthCanvas {
width: 100%;
height: 100%;
display: block;
}
/* 信息卡片样式 */
.info-card {
position: absolute;
background: rgba(16, 36, 62, 0.95);
backdrop-filter: blur(10px);
border-radius: 10px;
padding: 15px;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.4);
border: 1px solid rgba(64, 156, 255, 0.3);
z-index: 1000;
width: 250px;
transform: translate(-50%, -100%);
margin-top: -20px;
}
.info-card::before {
content: "";
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
border-width: 10px;
border-style: solid;
border-color: rgba(16, 36, 62, 0.95) transparent transparent transparent;
}
/* 卡片头部样式 */
.card-header {
height: 40px;
background: url('/assets/img/common/homeTitle2.png') no-repeat;
background-position: center;
background-size: 108% 120%;
display: flex;
justify-content: center;
align-items: center;
border-radius: 8px 8px 0 0 !important;
border-bottom: 1px solid var(--light-blue);
padding: 32px 20px;
position: relative;
margin: -20px -20px 0px -20px;
}
.card-header span {
font-size: 1.2rem;
letter-spacing: 1px;
font-family: 'YouSheBiaoTiHei', 'Microsoft YaHei';
font-weight: 400;
color: #ffffff;
}
.info-card-title {
font-size: 1.1rem;
color: #4fc3f7;
margin: 0;
}
.info-card-close {
background: none;
border: none;
color: #a0d2ff;
font-size: 1.2rem;
cursor: pointer;
padding: 0;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
}
.info-card-close:hover {
color: #ffffff;
}
.info-card-content {
font-size: 0.9rem;
}
.info-item {
margin: 8px 0;
display: flex;
}
.info-label {
width: 70px;
color: #a0d2ff;
font-weight: bold;
}
.info-value {
flex: 1;
color: #e0f0ff;
word-break: break-all;
}
.status-online {
color: #4caf50;
font-weight: bold;
}
.status-offline {
color: #f44336;
font-weight: bold;
}
/* 响应式调整 */
@media (max-width: 1200px) {
.info-panel,
.control-panel {
width: 260px;
}
.earth-container {
margin: 0 275px;
}
}
@media (max-width: 900px) {
.info-panel,
.control-panel {
width: 220px;
padding: 15px;
}
.earth-container {
margin: 0 235px;
}
.stat-value {
font-size: 1.5rem;
}
}
/* 滚动条样式 */
::-webkit-scrollbar {
width: 4px;
height: 4px;
}
::-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);
}
/* 警报列表样式 */
.alert-list {
/* height: 240px;
overflow-y: auto; */
height: calc(40vh - 8vh - 20px);
overflow: scroll;
}
.alert-item {
display: flex;
align-items: center;
padding: 12px 15px;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
transition: background 0.3s;
}
.alert-item:hover {
background: rgba(255, 255, 255, 0.05);
}
.alert-level {
width: 10px;
height: 10px;
border-radius: 50%;
margin-right: 10px;
}
.level-high {
background: #ff4560;
box-shadow: 0 0 8px #ff4560;
}
.level-medium {
background: #ffa726;
box-shadow: 0 0 8px #ffa726;
}
.level-low {
background: #00e396;
box-shadow: 0 0 8px #00e396;
}
.alert-content {
flex: 1;
}
.alert-title {
font-weight: bold;
margin-bottom: 5px;
}
.alert-desc {
font-size: 13px;
color: #a0c8ff;
}
.alert-time {
font-size: 12px;
color: #7a9ccc;
}
/* 图表容器样式 */
.chart-container {
width: 100%;
/* height: 200px; */
margin-top: 10px;
height: calc(40vh - 8vh - 20px);
}
/* 新增样式:实时数据监控网格布局 */
.stats-grid {
height: calc(40vh - 8vh - 20px);
overflow: scroll;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-bottom: 25px;
}
.stat-grid-item {
background: rgba(25, 55, 95, 0.6);
border-radius: 8px;
padding: 12px;
/* border-left: 3px solid #4fc3f7; */
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.stat-grid-value {
font-size: 1rem;
font-weight: bold;
margin-bottom: 5px;
}
.stat-grid-label {
font-size: 0.8rem;
color: #a0d2ff;
margin-bottom: 3px;
}
.stat-grid-status {
font-size: 0.7rem;
color: #81d4fa;
}
/* 视频会议系统样式 */
.video-conference {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-bottom: 25px;
}
.video-item {
background: rgba(25, 55, 95, 0.6);
border-radius: 8px;
padding: 12px;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
}
.video-item:hover {
transform: translateY(-3px);
background: rgba(40, 80, 130, 0.7);
}
.video-icon {
font-size: 2rem;
margin-bottom: 8px;
}
.video-name {
font-size: 0.9rem;
color: #e0f0ff;
}
/* 网络系统状态样式 */
.network-status {
margin-top: 20px;
}
.network-item {
margin-bottom: 12px;
}
.network-label {
display: flex;
justify-content: space-between;
margin-bottom: 5px;
font-size: 0.9rem;
}
.network-name {
color: #a0d2ff;
}
.network-value {
color: #4fc3f7;
}
.network-progress {
height: 8px;
background: rgba(25, 55, 95, 0.6);
border-radius: 4px;
overflow: hidden;
}
.network-progress-bar {
height: 100%;
border-radius: 4px;
transition: width 0.5s ease;
}
/* 项目监控样式 */
.project-monitor {
margin-top: 10px;
}
.project-item {
margin-bottom: 12px;
}
.project-label {
display: flex;
justify-content: space-between;
margin-bottom: 5px;
font-size: 0.9rem;
}
.project-name {
color: #a0d2ff;
}
.project-value {
color: #4fc3f7;
}
.project-progress {
height: 8px;
background: rgba(25, 55, 95, 0.6);
border-radius: 4px;
overflow: hidden;
}
.project-progress-bar {
height: 100%;
border-radius: 4px;
transition: width 0.5s ease;
}
.mars3d-popup-background {
background: var(--mars-base-bg, rgba(16, 36, 62, 0.85)) !important;
}
/* 区域选择器样式 */
.region-selector {
margin-bottom: 15px;
}
.region-selector select {
width: 100%;
padding: 8px 12px;
background: rgba(25, 55, 95, 0.6);
border: 1px solid rgba(79, 195, 247, 0.5);
border-radius: 4px;
color: #e0f0ff;
font-size: 0.9rem;
}
.region-selector select:focus {
outline: none;
border-color: #4fc3f7;
}
.region-selector label {
display: block;
margin-bottom: 5px;
font-size: 0.9rem;
color: #a0d2ff;
}
</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="container">
<!-- 地球容器 -->
<div class="earth-container">
<div id="mars3dMap" style="width:100%; height:100%;"></div>
</div>
</div>
<script>
// 全局变量
let map;
let isSimulationRunning = true;
let waterQualityChart;
let oxygenChart;
let chlorophyllChart;
let heatLayer = null
let heatLayer_clustering = null; // 添加这一行
// 替换原有的 lianyungangEcoRegions 数据为以下代码:
// 连云港生态区域数据 - 修正为正确的连云港地理坐标范围
const lianyungangEcoRegions = [
{
name: "非湿地",
type: "non-wetland",
color: "#cccccc",
coordinates: [
[[119.2, 34.8], [119.4, 34.8], [119.4, 35.0], [119.2, 35.0], [119.2, 34.8]]
]
},
{
name: "永久水域",
type: "permanent-water",
color: "#2ca25f",
coordinates: [
[[119.3, 34.6], [119.5, 34.6], [119.5, 34.8], [119.3, 34.8], [119.3, 34.6]]
]
},
{
name: "沼泽(乔木/灌木)",
type: "swamp-woody",
color: "#756bb1",
coordinates: [
[[119.1, 34.7], [119.3, 34.7], [119.3, 34.9], [119.1, 34.9], [119.1, 34.7]]
]
},
{
name: "沼泽(草本植被)",
type: "swamp-herbaceous",
color: "#dd3497",
coordinates: [
[[119.0, 34.6], [119.2, 34.6], [119.2, 34.8], [119.0, 34.8], [119.0, 34.6]]
]
},
{
name: "淹滩",
type: "flooded-beach",
color: "#fdbb84",
coordinates: [
[[119.4, 34.5], [119.6, 34.5], [119.6, 34.7], [119.4, 34.7], [119.4, 34.5]]
]
},
{
name: "盐碱地",
type: "saline-land",
color: "#b30000",
coordinates: [
[[119.5, 34.7], [119.7, 34.7], [119.7, 34.9], [119.5, 34.9], [119.5, 34.7]]
]
},
{
name: "红树林",
type: "mangrove",
color: "#41b6c4",
coordinates: [
[[119.6, 34.6], [119.8, 34.6], [119.8, 34.8], [119.6, 34.8], [119.6, 34.6]]
]
},
{
name: "盐沼",
type: "salt-marsh",
color: "#1d91c0",
coordinates: [
[[119.7, 34.5], [119.9, 34.5], [119.9, 34.7], [119.7, 34.7], [119.7, 34.5]]
]
},
{
name: "潮滩",
type: "tidal-flat",
color: "#ffff00",
coordinates: [
[[119.8, 34.4], [120.0, 34.4], [120.0, 34.6], [119.8, 34.6], [119.8, 34.4]]
]
},
{
name: "海洋",
type: "ocean",
color: "#081d58",
coordinates: [
[[119.9, 34.3], [120.1, 34.3], [120.1, 34.5], [119.9, 34.5], [119.9, 34.3]]
]
}
];
// 初始化页面
document.addEventListener('DOMContentLoaded', function () {
initDateTime();
// initWaterQualityChart();
// initOxygenChart();
// initChlorophyllChart();
initMap();
//initEventListeners();
});
// 初始化日期时间
function initDateTime() {
function updateDateTime() {
const now = new Date();
const dateStr = now.getFullYear() + '年' +
(now.getMonth() + 1) + '月' +
now.getDate() + '日';
const timeStr = now.toTimeString().substr(0, 8);
document.getElementById('current-date').textContent = dateStr;
document.getElementById('current-time').textContent = timeStr;
}
updateDateTime();
setInterval(updateDateTime, 1000);
}
// 初始化生态水质分析图表
function initWaterQualityChart() {
waterQualityChart = echarts.init(document.getElementById('waterQualityChart'));
const option = {
backgroundColor: 'transparent',
tooltip: {
trigger: 'axis'
},
legend: {
data: ['PH值', '浊度', '盐度'],
textStyle: {
color: '#e0f0ff'
},
top: '0%'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '15%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['2019', '2020', '2021', '2022', '2023'],
axisLine: {
lineStyle: {
color: '#4fc3f7'
}
},
axisLabel: {
color: '#a0d2ff'
}
},
yAxis: {
type: 'value',
axisLine: {
lineStyle: {
color: '#4fc3f7'
}
},
axisLabel: {
color: '#a0d2ff'
},
splitLine: {
lineStyle: {
color: 'rgba(79, 195, 247, 0.2)'
}
}
},
series: [
{
name: 'PH值',
type: 'line',
smooth: true,
data: [7.9, 8.0, 8.1, 8.2, 8.1],
lineStyle: {
color: '#00e396'
},
itemStyle: {
color: '#00e396'
}
},
{
name: '浊度',
type: 'line',
smooth: true,
data: [12.5, 11.8, 10.2, 9.5, 8.3],
lineStyle: {
color: '#00c6ff'
},
itemStyle: {
color: '#00c6ff'
}
},
{
name: '盐度',
type: 'line',
smooth: true,
data: [30.5, 30.8, 31.2, 31.5, 31.3],
lineStyle: {
color: '#4fc3f7'
},
itemStyle: {
color: '#4fc3f7'
}
}
]
};
waterQualityChart.setOption(option);
}
// 初始化含氧量趋势分析图表
function initOxygenChart() {
oxygenChart = echarts.init(document.getElementById('oxygenChart'));
const option = {
backgroundColor: 'transparent',
tooltip: {
trigger: 'axis'
},
legend: {
data: ['溶解氧'],
textStyle: {
color: '#e0f0ff'
},
top: '0%'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '15%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['2019', '2020', '2021', '2022', '2023'],
axisLine: {
lineStyle: {
color: '#4fc3f7'
}
},
axisLabel: {
color: '#a0d2ff'
}
},
yAxis: {
type: 'value',
name: 'mg/L',
axisLine: {
lineStyle: {
color: '#4fc3f7'
}
},
axisLabel: {
color: '#a0d2ff'
},
splitLine: {
lineStyle: {
color: 'rgba(79, 195, 247, 0.2)'
}
}
},
series: [
{
name: '溶解氧',
type: 'line',
smooth: true,
data: [6.8, 6.9, 7.1, 7.2, 7.0],
lineStyle: {
color: '#ff6b6b'
},
itemStyle: {
color: '#ff6b6b'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0,
color: 'rgba(255, 107, 107, 0.5)'
}, {
offset: 1,
color: 'rgba(255, 107, 107, 0.1)'
}]
}
}
}
]
};
oxygenChart.setOption(option);
}
// 初始化叶绿素趋势分析图表
function initChlorophyllChart() {
chlorophyllChart = echarts.init(document.getElementById('chlorophyllChart'));
const option = {
backgroundColor: 'transparent',
tooltip: {
trigger: 'axis'
},
legend: {
data: ['叶绿素a'],
textStyle: {
color: '#e0f0ff'
},
top: '0%'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '15%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['2019', '2020', '2021', '2022', '2023'],
axisLine: {
lineStyle: {
color: '#4fc3f7'
}
},
axisLabel: {
color: '#a0d2ff'
}
},
yAxis: {
type: 'value',
name: 'μg/L',
axisLine: {
lineStyle: {
color: '#4fc3f7'
}
},
axisLabel: {
color: '#a0d2ff'
},
splitLine: {
lineStyle: {
color: 'rgba(79, 195, 247, 0.2)'
}
}
},
series: [
{
name: '叶绿素a',
type: 'line',
smooth: true,
data: [3.2, 3.5, 4.1, 4.3, 4.0],
lineStyle: {
color: '#a8e6cf'
},
itemStyle: {
color: '#a8e6cf'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0,
color: 'rgba(168, 230, 207, 0.5)'
}, {
offset: 1,
color: 'rgba(168, 230, 207, 0.1)'
}]
}
}
}
]
};
chlorophyllChart.setOption(option);
}
// 初始化地图
async function initMap() {
try {
// 通过 AJAX 加载 config.json 配置文件
fetch('./config/config.json')
.then(response => response.json())
.then(config => {
// 使用配置文件初始化地图
map = new mars3d.Map("mars3dMap", config.map3d);
// 等待地图完全加载后再添加图层
map.on(mars3d.EventType.load, function () {
console.log('地图加载完成');
setTimeout(() => {
// 加载热力图
loadHeatLayer();
// 添加图例
addLegend();
}, 1000);
});
})
.catch(error => {
console.error('加载配置文件失败:', error);
// 使用默认配置
initDefaultMap();
});
} catch (error) {
console.error('初始化 Mars3D 地图时出错:', error);
initDefaultMap();
}
}
// 默认地图配置
function initDefaultMap() {
map = new mars3d.Map("mars3dMap", {
scene: {
sceneMode: Cesium.SceneMode.SCENE2D, // 设置默认为二维模式
center: { lat: 15.0, lng: 110.0, alt: 3000000, heading: 0, pitch: -45 }, // 调整为中心显示南海区域
showSun: true,
showMoon: true,
showSkyBox: true,
showSkyAtmosphere: true,
fog: true,
fxaa: true,
cameraController: {
zoomFactor: 2.0,
minimumZoomDistance: 1,
maximumZoomDistance: 50000000,
}
},
control: {
homeButton: true,
sceneModePicker: true,
baseLayerPicker: true,
navigationHelpButton: true,
animation: true,
timeline: true,
fullscreenButton: true,
vrButton: true,
},
basemaps: [
{
id: 10,
name: "天地图影像",
icon: "img/basemaps/tdt_img.png",
type: "group",
layers: [
{
name: "底图",
type: "tdt",
layer: "img_d",
},
{
name: "注记",
type: "tdt",
layer: "cia_w",
}
]
}
]
});
// 地图加载完成后添加图层
map.on(mars3d.EventType.load, function () {
console.log('默认地图加载完成');
setTimeout(() => {
// 加载热力图
loadHeatLayer();
// 添加图例
addLegend();
}, 1000);
});
}
// // 添加区域选择事件监听
// document.getElementById('region-select').addEventListener('change', function () {
// updateCharts(this.value);
// });
// 生成模拟数据
function getPointData() {
const points = [];
// 连云港区域坐标范围
const minLng = 118.5, maxLng = 120.0;
const minLat = 34.0, maxLat = 35.2;
// 生成1500个随机点位
for (let i = 0; i < 50; i++) {
const lng = minLng + Math.random() * (maxLng - minLng);
const lat = minLat + Math.random() * (maxLat - minLat);
points.push({
grid: `{"type":"Point","coordinates":[${lng.toFixed(6)},${lat.toFixed(6)}]}`,
name: `监测点${i + 1}`,
remark: '连云港海域监测点',
});
}
return points;
}
// // 正常应该为接口获取数据,我这里是自己随机生成的点位
// function getPointData() {
// return [
// {
// grid: '{"type":"Point","coordinates":[117.111,36.652]}',
// name: '济南点位',
// remark: '济南市',
// },
// {
// grid: '{"type":"Point","coordinates":[118.127,36.183]}',
// name: '枣庄点位',
// remark: '枣庄市',
// },
// // 新增28个随机点位
// ...Array.from({ length: 30 }, (_, i) => {
// // 生成山东省范围内的随机坐标
// const lng = 115 + Math.random() * 2
// const lat = 34 + Math.random() * 2
// return {
// grid: `{"type":"Point","coordinates":[${lng.toFixed(
// 6
// )},${lat.toFixed(6)}]}`,
// name: `测试点位${i + 1}`,
// remark: '随机位置',
// }
// }),
// ...Array.from({ length: 10 }, (_, i) => {
// // 生成山东省范围内的随机坐标
// const lng = 105 + Math.random() * 2
// const lat = 32 + Math.random() * 2
// return {
// grid: `{"type":"Point","coordinates":[${lng.toFixed(
// 6
// )},${lat.toFixed(6)}]}`,
// name: `测试点位${i + 1}`,
// remark: '随机位置',
// }
// }),
// ]
// }
// // 加载热力图,将数据放到图层上
// async function loadHeatLayer() {
// let arrPoints = []
// let arr = await getPointData() //这里为获取的数据
// arr.forEach((item) => {
// if (item.grid) {
// let pointData = JSON.parse(item.grid).coordinates
// arrPoints.push({ lng: pointData[0], lat: pointData[1], value: 1 })
// }
// })
// if (heatLayer) {
// map.removeLayer(heatLayer)
// heatLayer = null
// }
// // 热力图 图层
// heatLayer = new mars3d.layer.graphicLayer({
// name: 'Point',
// positions: arrPoints,
// heatStyle: {
// radius: 40,
// blur: 0.85,
// gradient: { 0.4: 'blue', 0.6: 'green', 0.9: 'yellow', 1: 'red' },
// },
// // 以下为矩形矢量对象的样式参数
// style: {
// arc: false, // 是否为曲面
// height: 10,
// },
// // flyTo: true,
// })
// map.value.addLayer(heatLayer)
// }
// 替换原有的 loadHeatLayer 函数,增加聚合功能
async function loadHeatLayer() {
try {
console.log('开始加载南海事件数据...');
// 定义文件和对应的颜色
const fileColors = {
'./data/jiison/1_lan.json': '#0000FF', // 蓝色
'./data/jiison/2_hong.json': '#FF0000', // 红色
'./data/jiison/3_cheng.json': '#FFA500', // 橙色
'./data/jiison/4_lv.json': '#008000', // 绿色
'./data/jiison/5_huang.json': '#FFFF00', // 黄色
'./data/jiison/6_zi.json': '#800080', // 紫色
'./data/jiison/7_zong.json': '#00FFFF' // 青色
};
let allPoints = [];
// 加载所有JSON文件
for (const [file, color] of Object.entries(fileColors)) {
try {
const response = await fetch(file);
const eventData = await response.json();
eventData.forEach(item => {
allPoints.push({
lng: item.经度,
lat: item.纬度,
value: 1.0,
color: color,
attr: {
事件: item.事件,
时间: item.时间,
经度: item.经度,
纬度: item.纬度
}
});
});
console.log(`加载 ${file} 完成,数据点数量:`, eventData.length);
} catch (fileError) {
console.error(`加载文件 ${file} 时出错:`, fileError);
}
}
console.log('总生成的事件数据点:', allPoints.length);
// 移除旧图层
if (heatLayer) {
map.removeLayer(heatLayer);
heatLayer = null;
}
// 创建带聚合功能的图形图层
heatLayer = new mars3d.layer.GraphicLayer({
name: '南海事件点图层',
// 启用图层级别的聚合功能
clustering: {
enabled: true,
pixelRange: 50,
minimumClusterSize: 3,
billboard: true,
showCoverageOnHover: true,
zoomOnClick: true,
style: {
// 聚合点样式
circle: {
color: "#4fc3f7",
radius: 20,
outline: true,
outlineColor: "#ffffff",
outlineWidth: 2
},
// 聚合点文字样式
label: {
font_size: 16,
color: "#ffffff",
offset_y: -20,
font_family: "Arial",
font_weight: "bold"
}
}
}
});
map.addLayer(heatLayer);
// 为每个点创建图形元素
allPoints.forEach(point => {
const graphic = new mars3d.graphic.BillboardEntity({
position: [point.lng, point.lat],
style: {
pixelSize: 10,
color: point.color,
outlineColor: '#FFFFFF',
outlineWidth: 1,
opacity: 0.8,
scaleByDistance: true,
scaleByDistance_far: 2000000,
scaleByDistance_farValue: 0.8,
scaleByDistance_near: 100000,
scaleByDistance_nearValue: 1.2
},
attr: point.attr,
popup: `
<div style="padding: 10px">
<h3 style="margin:0 0 10px 0;color:#4fc3f7">${point.attr.事件}</h3>
<p style="margin:5px 0"><strong>时间:</strong> ${point.attr.时间}</p>
<p style="margin:5px 0"><strong>纬度:</strong> ${point.attr.纬度}</p>
<p style="margin:5px 0"><strong>经度:</strong> ${point.attr.经度}</p>
</div>
`
});
heatLayer.addGraphic(graphic);
});
console.log('事件点图层创建完成,聚合功能已启用');
} catch (error) {
console.error('加载南海事件数据时出错:', error);
}
}
// 创建事件点图层(当热力图插件不可用时的备选方案)
function createEventPointLayer(points) {
if (heatLayer) {
map.removeLayer(heatLayer);
heatLayer = null;
}
// 创建图形图层来显示事件点
heatLayer = new mars3d.layer.GraphicLayer({
name: '南海事件点图层'
});
map.addLayer(heatLayer);
points.forEach(point => {
const graphic = new mars3d.graphic.PointEntity({
position: [point.lng, point.lat],
style: {
pixelSize: 10,
color: '#FF0000',
outlineColor: '#FFFFFF',
outlineWidth: 1,
opacity: 0.8
},
attr: point.attr,
popup: `
<div style="padding: 10px">
<h3 style="margin:0 0 10px 0;color:#4fc3f7">${point.attr.事件}</h3>
<p style="margin:5px 0"><strong>时间:</strong> ${point.attr.时间}</p>
<p style="margin:5px 0"><strong>纬度:</strong> ${point.attr.纬度}</p>
<p style="margin:5px 0"><strong>经度:</strong> ${point.attr.经度}</p>
</div>
`
});
heatLayer.addGraphic(graphic);
});
console.log('事件点图层创建完成');
}
// 添加生态区域图层 - 修复版本
function addEcoRegionsLayer() {
if (!map) {
console.warn('地图未初始化完成,延迟添加生态区域图层');
setTimeout(addEcoRegionsLayer, 1000);
return;
}
const colorMap = {
'non-wetland': '#808080',
'permanent-water': '#1E90FF',
'swamp-woody': '#6B8E23',
'swamp-herbaceous': '#8FBC8F',
'flooded-beach': '#D2B48C',
'saline-land': '#A0522D',
'mangrove': '#006400',
'salt-marsh': '#2E8B57',
'tidal-flat': '#BC8F8F',
'ocean': '#00008B'
};
const graphicLayer = new mars3d.layer.GraphicLayer({
name: "连云港生态区域"
});
// 先将图层添加到地图
map.addLayer(graphicLayer);
lianyungangEcoRegions.forEach((region, index) => {
region.coordinates.forEach((ring, ringIndex) => {
// 修复坐标格式,确保使用正确的经纬度顺序
const positions = ring.map(coord => [coord[0], coord[1], 0]); // 添加高度值
const polygon = new mars3d.graphic.PolygonEntity({
positions: positions,
style: {
fill: true,
color: colorMap[region.type] || '#808080',
opacity: 0.6,
outline: true,
outlineColor: "#ffffff",
outlineWidth: 1,
clampToGround: true
},
attr: {
name: region.name,
type: region.type
},
popup: "类型: " + region.name + "<br/>生态类型: " + region.type
});
// 添加到已存在的图层
graphicLayer.addGraphic(polygon);
});
});
console.log('生态区域图形图层已添加,共添加 ' + lianyungangEcoRegions.length + ' 个区域');
}
// 修改 addLegend 函数,添加按颜色分类的图例说明
function addLegend() {
const legend = document.createElement('div');
legend.style.cssText = `
position: absolute;
bottom: 20px;
left: 20px;
background: rgba(16, 36, 62, 0.85);
border: 1px solid rgba(64, 156, 255, 0.3);
border-radius: 8px;
padding: 15px;
color: #e0f0ff;
z-index: 1000;
max-width: 250px;
backdrop-filter: blur(5px);
`;
legend.innerHTML = `
<h3 style="margin: 0 0 10px 0; color: #4fc3f7; font-size: 14px;">事件类型图例</h3>
<div style="display: flex; align-items: center; margin-bottom: 8px;">
<div style="width: 12px; height: 12px; background-color: #0000FF; border-radius: 50%; margin-right: 8px;"></div>
<span style="font-size: 12px;">领海争议</span>
</div>
<div style="display: flex; align-items: center; margin-bottom: 8px;">
<div style="width: 12px; height: 12px; background-color: #FF0000; border-radius: 50%; margin-right: 8px;"></div>
<span style="font-size: 12px;">边境冲突</span>
</div>
<div style="display: flex; align-items: center; margin-bottom: 8px;">
<div style="width: 12px; height: 12px; background-color: #FFA500; border-radius: 50%; margin-right: 8px;"></div>
<span style="font-size: 12px;">低空与敌对冲突</span>
</div>
<div style="display: flex; align-items: center; margin-bottom: 8px;">
<div style="width: 12px; height: 12px; background-color: #008000; border-radius: 50%; margin-right: 8px;"></div>
<span style="font-size: 12px;">两岸海域纠纷</span>
</div>
<div style="display: flex; align-items: center; margin-bottom: 8px;">
<div style="width: 12px; height: 12px; background-color: #FFFF00; border-radius: 50%; margin-right: 8px;"></div>
<span style="font-size: 12px;">内部渔船管理与执法</span>
</div>
<div style="display: flex; align-items: center; margin-bottom: 8px;">
<div style="width: 12px; height: 12px; background-color: #800080; border-radius: 50%; margin-right: 8px;"></div>
<span style="font-size: 12px;">渔民打捞境外设备</span>
</div>
<div style="display: flex; align-items: center; margin-bottom: 5px;">
<div style="width: 12px; height: 12px; background-color: #00FFFF; border-radius: 50%; margin-right: 8px;"></div>
<span style="font-size: 12px;">生态安全环境</span>
</div>
`;
document.querySelector('.earth-container').appendChild(legend);
}
// 初始化事件监听器
function initEventListeners() {
// // 窗口大小变化时重新调整图表大小
// window.addEventListener('resize', function () {
// waterQualityChart.resize();
// oxygenChart.resize();
// chlorophyllChart.resize();
// });
}
// 更新图表数据
function updateCharts(region) {
// 根据区域更新图表数据
const regionData = {
'all': {
ph: [7.9, 8.0, 8.1, 8.2, 8.1],
turbidity: [12.5, 11.8, 10.2, 9.5, 8.3],
salinity: [30.5, 30.8, 31.2, 31.5, 31.3],
oxygen: [6.8, 6.9, 7.1, 7.2, 7.0],
chlorophyll: [3.2, 3.5, 4.1, 4.3, 4.0]
},
'lianyungang': {
ph: [7.8, 7.9, 8.0, 8.1, 8.0],
turbidity: [11.5, 10.8, 9.2, 8.5, 7.3],
salinity: [29.5, 29.8, 30.2, 30.5, 30.3],
oxygen: [6.7, 6.8, 7.0, 7.1, 6.9],
chlorophyll: [3.0, 3.3, 3.9, 4.1, 3.8]
},
'lanshan': {
ph: [8.0, 8.1, 8.2, 8.3, 8.2],
turbidity: [13.5, 12.8, 11.2, 10.5, 9.3],
salinity: [31.5, 31.8, 32.2, 32.5, 32.3],
oxygen: [6.9, 7.0, 7.2, 7.3, 7.1],
chlorophyll: [3.4, 3.7, 4.3, 4.5, 4.2]
},
'ganyu': {
ph: [7.7, 7.8, 7.9, 8.0, 7.9],
turbidity: [10.5, 9.8, 8.2, 7.5, 6.3],
salinity: [28.5, 28.8, 29.2, 29.5, 29.3],
oxygen: [6.6, 6.7, 6.9, 7.0, 6.8],
chlorophyll: [2.8, 3.1, 3.7, 3.9, 3.6]
},
'guannan': {
ph: [7.9, 8.0, 8.1, 8.2, 8.1],
turbidity: [12.0, 11.3, 9.7, 9.0, 7.8],
salinity: [30.0, 30.3, 30.7, 31.0, 30.8],
oxygen: [6.8, 6.9, 7.1, 7.2, 7.0],
chlorophyll: [3.1, 3.4, 4.0, 4.2, 3.9]
},
'guanyun': {
ph: [8.0, 8.1, 8.2, 8.3, 8.2],
turbidity: [13.0, 12.3, 10.7, 10.0, 8.8],
salinity: [31.0, 31.3, 31.7, 32.0, 31.8],
oxygen: [6.9, 7.0, 7.2, 7.3, 7.1],
chlorophyll: [3.3, 3.6, 4.2, 4.4, 4.1]
}
};
const data = regionData[region] || regionData['all'];
// 更新水质分析图表
waterQualityChart.setOption({
series: [
{ data: data.ph },
{ data: data.turbidity },
{ data: data.salinity }
]
});
// 更新含氧量趋势图表
oxygenChart.setOption({
series: [
{ data: data.oxygen }
]
});
// 更新叶绿素趋势图表
chlorophyllChart.setOption({
series: [
{ data: data.chlorophyll }
]
});
}
</script>
</body>
</html>