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.

1395 lines
58 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>
<!-- <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css">
<link href="https://demo.axureux.com/fontawesome/5.7.2/pro/css/all.min.css" type="text/css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script> -->
<link rel="stylesheet" href="/common/css/bootstrap.min.css">
<link href="https://demo.axureux.com/fontawesome/5.7.2/pro/css/all.min.css" type="text/css" rel="stylesheet" />
<!-- <link href="/common/css/all.min.css" type="text/css" rel="stylesheet" /> -->
<script src="/common/script/chart.min.js"></script>
<style>
/* 整个滚动条 */
::-webkit-scrollbar {
width: 8px;
height: 6px;
}
/* 滚动条轨道 */
::-webkit-scrollbar-track {
background: #f1f3f5;
border-radius: 10px;
}
/* 滚动条滑块 */
::-webkit-scrollbar-thumb {
background: #a5b4fc;
border-radius: 10px;
border: 2px solid #f1f3f5;
}
/* 滚动条滑块悬停状态 */
::-webkit-scrollbar-thumb:hover {
background: #7c3aed;
}
/* 滚动条角落 */
::-webkit-scrollbar-corner {
background: #f1f3f5;
}
/* 数据表格容器滚动条 */
.data-table-container::-webkit-scrollbar {
width: 8px;
height: 8px;
}
.data-table-container::-webkit-scrollbar-track {
background: #f8f9fa;
border-radius: 4px;
}
.data-table-container::-webkit-scrollbar-thumb {
background: linear-gradient(180deg, #4da6ff, #1a6bc9);
border-radius: 4px;
}
.data-table-container::-webkit-scrollbar-thumb:hover {
background: linear-gradient(180deg, #1a6bc9, #0d4a8a);
}
:root {
--primary-blue: #1a6bc9;
--secondary-blue: #2c8ce0;
--light-blue: #e6f2ff;
--dark-blue: #0d4a8a;
--accent-blue: #4da6ff;
}
body {
font-family: 'Microsoft YaHei', sans-serif;
background-color: #f5f9ff;
color: #333;
}
.header {
background: linear-gradient(135deg, var(--primary-blue), var(--dark-blue));
color: white;
padding: 15px 20px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
text-align: center;
}
/* 修改标签页样式,使用浅灰色背景 */
.nav-tabs {
background-color: #f8f9fa;
/* 浅灰色背景 */
border-bottom: 2px solid #dee2e6;
/* 浅灰色边框 */
padding: 0 10px;
/* 添加内边距 */
border-radius: 0 0 8px 8px;
/* 添加圆角 */
}
.nav-tabs .nav-link {
color: #495057;
/* 深灰色文字 */
font-weight: bold;
border: none;
padding: 12px 20px;
border-radius: 8px 8px 0 0 !important;
margin-right: 5px;
/* 添加右侧间距 */
transition: all 0.3s ease;
/* 添加过渡效果 */
}
.nav-tabs .nav-link.active {
background-color: #ffffff;
/* 白色背景 */
color: #1a6bc9;
/* 蓝色文字 */
border: none;
box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.1);
/* 添加阴影效果 */
}
.nav-tabs .nav-link:hover:not(.active) {
background-color: #e9ecef;
/* 悬停时的浅灰色 */
color: #1a6bc9;
/* 蓝色文字 */
}
/* 确保卡片高度一致 */
.card {
height: 100%;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
border: 1px solid #dee2e6;
/* 添加边框 */
margin-bottom: 20px;
/* 恢复margin-bottom */
}
/* 左侧上部卡片(监测站点和监测指标)的特殊处理 */
.row>.col-md-6>.row>.col-md-6>.card {
height: calc(100% - 20px);
/* 调整高度以适应margin */
margin-bottom: 20px;
}
/* 左侧地图卡片 */
.row>.col-md-6>.card {
height: calc(100% - 215px);
/* 与其他卡片保持一致的高度计算 */
margin-bottom: 0;
}
/* 右侧设备状态卡片高度调整 */
#realtime .col-md-6:last-child .card:last-child {
height: calc(100% - 20px);
}
/* 右侧设备状态卡片高度调整 */
#realtime .col-md-6:last-child .card:last-child {
height: calc(100% - 20px);
/* 与地图卡片高度一致 */
}
.card-header {
background: linear-gradient(to right, var(--secondary-blue), var(--accent-blue));
color: white;
font-weight: bold;
border-radius: 8px 8px 0 0 !important;
border-bottom: 1px solid #dee2e6;
}
.monitor-section {
background-color: white;
padding: 20px;
border-radius: 8px;
}
.data-item {
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px dashed #ddd;
}
.data-label {
font-weight: bold;
color: var(--dark-blue);
}
/* 地图容器样式调整 */
.map-container {
height: 100%;
/* 减去card-header的高度 */
background-color: #eef7ff;
border-radius: 8px;
border: 1px solid #cce5ff;
position: relative;
}
.tab-content {
/* padding: 20px; */
background-color: white;
border-radius: 0 0 8px 8px;
}
.warning-panel {
background-color: #fff4e6;
border-left: 4px solid #ff9900;
padding: 15px;
margin-bottom: 20px;
}
.btn-action {
background-color: var(--secondary-blue);
color: white;
margin-right: 10px;
margin-bottom: 10px;
}
.btn-action:hover {
background-color: var(--primary-blue);
color: white;
}
.btn-export {
background-color: #28a745;
color: white;
}
.data-table {
font-size: 14px;
}
.data-table th {
background-color: var(--light-blue);
}
.chart-container {
position: relative;
height: 300px;
width: 100%;
}
.risk-chart {
height: calc(100vh - 615px);
overflow: hidden;
/* 防止出现滚动条 */
}
.kpi-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 15px;
}
.kpi-item {
background: #f8f9fa;
border-radius: 8px;
padding: 20px 10px;
text-align: center;
border: 1px solid #dee2e6;
}
.kpi-value {
font-size: 16px;
font-weight: bold;
color: #0d6efd;
margin-bottom: 5px;
}
.kpi-label {
font-size: 12px;
color: #6c757d;
}
/* 数据查询区域样式 */
.data-query-container {
display: flex;
height: calc(100vh - 150px);
gap: 20px;
}
.data-chart-section {
flex: 3;
display: flex;
flex-direction: column;
}
.data-table-section {
flex: 1;
display: flex;
flex-direction: column;
}
.data-table-container {
flex: 1;
overflow-y: auto;
max-height: calc(100vh - 208px);
}
.chart-wrapper {
height: calc(100vh - 320px);
}
.chart-wrapper canvas {
width: 100% !important;
height: 100% !important;
max-height: calc(100vh - 320px);
}
/* 地图工具栏按钮选中状态样式 - 改进版本 */
.btn-map-tool.active {
background-color: #ff6b35 !important;
/* 使用更醒目的橙色 */
border-color: #e55a2b !important;
box-shadow: 0 0 0 0.2rem rgba(255, 107, 53, 0.35);
color: white !important;
}
/* 悬停状态也保持一致性 */
.btn-map-tool.active:hover {
background-color: #e55a2b !important;
border-color: #cc481f !important;
}
.btn-map-tool:focus {
box-shadow: 0 0 0 0.2rem rgba(26, 107, 201, 0.25);
}
/* 确保工具栏按钮有一致的样式 */
.btn-map-tool {
margin-bottom: 2px;
}
/* 应急处理按钮布局优化 */
.emergency-actions {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
}
/* 在小屏幕上使用单列布局 */
@media (max-width: 768px) {
.emergency-actions {
grid-template-columns: 1fr;
}
}
/* 应急处理按钮样式优化 */
.btn-emergency {
background: linear-gradient(135deg, #ff6b6b, #ee5a24);
color: white;
border: none;
padding: 12px 15px;
font-weight: bold;
transition: all 0.3s ease;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
text-align: center;
width: 100%;
}
.btn-emergency:hover {
background: linear-gradient(135deg, #ee5a24, #ff6b6b);
transform: translateY(-2px);
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);
color: white;
}
.btn-emergency:active {
transform: translateY(0);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.btn-emergency i {
margin-right: 8px;
}
</style>
</head>
<body>
<div class="header d-flex justify-content-between align-items-center">
<h2 class="mb-0">海底监测与灾害预警系统管理平台</h2>
<img src="/common/images/logo_gt.png" alt="Logo" style="height: 50px; width: auto;">
</div>
<ul class="nav nav-tabs" id="mainTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="realtime-tab" data-bs-toggle="tab" data-bs-target="#realtime"
type="button" role="tab">实时监控</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="data-tab" data-bs-toggle="tab" data-bs-target="#data" type="button"
role="tab">数据管理</button>
</li>
</ul>
<div class="tab-content container-fluid mt-3" id="mainTabContent">
<!-- 实时监控面板 -->
<div class="tab-pane fade show active" id="realtime" role="tabpanel">
<div class="row">
<!-- 左侧内容 -->
<div class="col-md-6">
<div class="row">
<div class="col-md-6">
<div class="card">
<div class="card-header">监测站点</div>
<div class="card-body">
<div class="data-item">
<span class="data-label">站点名称:</span>
<select class="form-select form-select-sm"
style="display: inline-block; width: auto;">
<option selected>东营监测站</option>
<option>青岛监测站</option>
<option>烟台监测站</option>
<option>日照监测站</option>
<option>潍坊监测站</option>
</select>
</div>
<div class="data-item">
<span class="data-label">分布区域:</span> 东营市河西仙镇
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header">监测指标</div>
<div class="card-body">
<div class="data-item">
<span class="data-label">水文:</span> 波浪 温盐 海流
</div>
<div class="data-item">
<span class="data-label">水质:</span> 浊度 PH 溶解氧 叶绿素
</div>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header">地图</div>
<div class="card-body p-0">
<div class="map-container">
<div id="map" style="width: 100%; height: 100%; position: relative;"></div>
<!-- 地图工具栏 -->
<div id="map-toolbar"
style="position: absolute; top: 10px; right: 10px; z-index: 1000;">
<div class="btn-group-vertical" role="group">
<button id="btn-locate" class="btn btn-primary btn-sm btn-map-tool" title="定位">
<i class="fas fa-location-arrow"></i>
</button>
<button id="btn-draw-point" class="btn btn-primary btn-sm btn-map-tool"
title="绘制点">
<i class="fas fa-map-marker-alt"></i>
</button>
<button id="btn-draw-line" class="btn btn-primary btn-sm btn-map-tool"
title="绘制线">
<i class="fas fa-minus"></i>
</button>
<button id="btn-draw-polygon" class="btn btn-primary btn-sm btn-map-tool"
title="绘制多边形">
<i class="fas fa-draw-polygon"></i>
</button>
<button id="btn-draw-circle" class="btn btn-primary btn-sm btn-map-tool"
title="绘制圆形">
<i class="fas fa-circle"></i>
</button>
<button id="btn-measure" class="btn btn-primary btn-sm btn-map-tool"
title="测量距离">
<i class="fas fa-ruler"></i>
</button>
<button id="btn-delete" class="btn btn-danger btn-sm btn-map-tool" title="删除">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
<!-- 经纬度显示 - 移动到左上角 -->
<!-- <div id="mouse-position"
style="position: absolute; top: 70px; left: 20px; background: rgba(255,255,255,0.8); padding: 5px 10px; border-radius: 4px; font-size: 12px; z-index: 1000; box-shadow: 0 0 5px rgba(0,0,0,0.3);">
经纬度: 0.000000, 0.000000
</div> -->
<!-- 比例尺 -->
<div id="scale-line" style="position: absolute; bottom: 10px; left: 15px;"></div>
</div>
</div>
</div>
</div>
<!-- 右侧内容 -->
<div class="col-md-6">
<ul class="nav nav-tabs" id="realtimeSubTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="monitor-data-tab" data-bs-toggle="tab"
data-bs-target="#monitor-data" type="button" role="tab">监测数据</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="warning-info-tab" data-bs-toggle="tab"
data-bs-target="#warning-info" type="button" role="tab">告警信息</button>
</li>
</ul>
<div class="tab-content" id="realtimeSubTabContent">
<!-- 监测数据子面板 -->
<div class="tab-pane fade show active" id="monitor-data" role="tabpanel">
<div class="data-item" style="padding-top: 15px;">
<span class="data-label">数据更新时间:</span> 2025-09-17 15:18:00
</div>
<div class="data-item">
<span class="data-label">运行状态:</span> <span class="text-success">正常运行</span>
</div>
<div class="card mt-3">
<div class="card-header bg-info text-white">水文</div>
<div class="card-body">
<div class="kpi-grid">
<div class="kpi-item">
<div class="kpi-value">15 cm</div>
<div class="kpi-label">平均波高</div>
</div>
<div class="kpi-item">
<div class="kpi-value">9.9 s</div>
<div class="kpi-label">平均波周期</div>
</div>
<div class="kpi-item">
<div class="kpi-value">25.2 cm</div>
<div class="kpi-label">1/3波高</div>
</div>
<div class="kpi-item">
<div class="kpi-value">9.9 s</div>
<div class="kpi-label">1/3波周期</div>
</div>
<div class="kpi-item">
<div class="kpi-value">20.1 cm</div>
<div class="kpi-label">1/10波高</div>
</div>
<div class="kpi-item">
<div class="kpi-value">9.1 s</div>
<div class="kpi-label">1/10波周期</div>
</div>
<div class="kpi-item">
<div class="kpi-value">26.4 cm</div>
<div class="kpi-label">最大波高</div>
</div>
<div class="kpi-item">
<div class="kpi-value">10 s</div>
<div class="kpi-label">最大波周期</div>
</div>
<div class="kpi-item">
<div class="kpi-value">135 °</div>
<div class="kpi-label">主波向</div>
</div>
<div class="kpi-item">
<div class="kpi-value">28.13 ℃</div>
<div class="kpi-label">水温</div>
</div>
<div class="kpi-item">
<div class="kpi-value">23 mS/cm</div>
<div class="kpi-label">电导率</div>
</div>
<div class="kpi-item">
<div class="kpi-value">23 m</div>
<div class="kpi-label">潮位</div>
</div>
<div class="kpi-item">
<div class="kpi-value">38 mm/s</div>
<div class="kpi-label">流速</div>
</div>
<div class="kpi-item">
<div class="kpi-value">156 °</div>
<div class="kpi-label">流向</div>
</div>
</div>
</div>
</div>
<div class="card mt-3">
<div class="card-header bg-info text-white">水质</div>
<div class="card-body">
<div class="kpi-grid">
<div class="kpi-item">
<div class="kpi-value">15 NTU</div>
<div class="kpi-label">浊度</div>
</div>
<div class="kpi-item">
<div class="kpi-value">7.9</div>
<div class="kpi-label">PH</div>
</div>
<div class="kpi-item">
<div class="kpi-value">6 mg/L</div>
<div class="kpi-label">溶解氧</div>
</div>
<div class="kpi-item">
<div class="kpi-value">0.8 μg/L</div>
<div class="kpi-label">叶绿素</div>
</div>
</div>
</div>
</div>
<!-- 修改设备状态卡片部分 -->
<div class="card mt-3" style="height: calc(100% - 20px);">
<div class="card-header bg-info text-white">设备状态</div>
<div class="card-body">
<div class="data-item">
<span class="data-label">水文监测设备:</span> <span class="text-success">正常运行</span>
</div>
<div class="data-item">
<span class="data-label">水质监测设备:</span> <span class="text-success">正常运行</span>
</div>
</div>
</div>
</div>
<!-- 告警信息子面板 -->
<div class="tab-pane fade" id="warning-info" role="tabpanel">
<div class="warning-panel">
<h5>警告信息</h5>
<p>当前系统检测到异常波动,请注意查看风险预报图。</p>
</div>
<div class="card">
<div class="card-header">风险预报图</div>
<div class="card-body">
<div class="risk-chart">
<canvas id="riskChart"></canvas>
</div>
</div>
</div>
<div class="card mt-3">
<div class="card-header">应急处理</div>
<div class="card-body">
<div class="emergency-actions">
<button class="btn btn-emergency">
<i class="fas fa-plug"></i>断开波浪设备电源
</button>
<button class="btn btn-emergency">
<i class="fas fa-plug"></i>断开海流设备电源
</button>
<button class="btn btn-emergency">
<i class="fas fa-plug"></i>断开水质设备电源
</button>
<button class="btn btn-emergency">
<i class="fas fa-redo"></i>补发当天数据
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 数据管理面板 -->
<div class="tab-pane fade" id="data" role="tabpanel">
<div class="data-query-container">
<!-- 左侧图表 -->
<div class="data-chart-section">
<div class="card h-100">
<div class="card-header">数据查询</div>
<div class="card-body">
<div class="row mb-3">
<div class="col-md-5">
<label class="form-label">开始时间:</label>
<input type="date" class="form-control" id="startDate" value="2025-09-16">
</div>
<div class="col-md-5">
<label class="form-label">结束时间:</label>
<input type="date" class="form-control" id="endDate" value="2025-09-22">
</div>
<div class="col-md-2">
<label class="form-label">数据类型:</label>
<select class="form-select" id="dataTypeSelect">
<option value="流速" selected>流速</option>
<option value="波浪">波浪</option>
<option value="温盐">温盐</option>
<option value="海流">海流</option>
<option value="浊度">浊度</option>
<option value="PH">PH</option>
<option value="溶解氧">溶解氧</option>
<option value="叶绿素">叶绿素</option>
<option value="电导率">电导率</option>
<option value="潮位">潮位</option>
<option value="流向">流向</option>
</select>
</div>
</div>
<div class="chart-wrapper">
<canvas id="dataChart"></canvas>
</div>
</div>
</div>
</div>
<!-- 右侧数据表格 -->
<div class="data-table-section">
<div class="card h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<span>数据列表</span>
<button class="btn btn-sm btn-export">数据导出</button>
</div>
<div class="data-table-container">
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-striped table-hover data-table mb-0">
<thead>
<tr>
<th>时间</th>
<th id="dataColumnType">流速(m/s)</th>
</tr>
</thead>
<tbody id="dataTableBody">
<!-- 数据将通过JavaScript动态生成 -->
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<link rel="stylesheet" href="/common/plugin/map/ol/v6.12.0/css/ol.css" type="text/css" />
<script src="/common/plugin/map/ol/v6.12.0/build/ol.js"></script>
<link rel="stylesheet" href="/common/plugin/map/ol/ol-ext-master/ol-ext.css" />
<script type="text/javascript" src="/common/plugin/map/ol/ol-ext-master/ol-ext.js"></script>
<script src="/common/script/bootstrap.bundle.min.js"></script>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script> -->
<script>
var TDT_API_KEY = "a4f4b6000cb9d1bf148bb77452000f30";
// 地图初始化
document.addEventListener('DOMContentLoaded', function () {
// 存储图表实例的全局变量
window.charts = {
riskChart: null,
dataChart: null
};
// 存储地图实例的全局变量
window.mapInstance = null;
// 节流函数,防止频繁触发
function throttle(func, limit) {
let inThrottle;
return function () {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
}
}
// 处理窗口大小改变事件
const handleResize = throttle(function () {
// 重绘风险预报图
if (window.charts.riskChart) {
window.charts.riskChart.resize();
}
// 重绘数据图表
if (window.dataChartInstance) {
window.dataChartInstance.resize();
}
// 调整地图大小
if (window.mapInstance) {
setTimeout(() => {
window.mapInstance.updateSize();
}, 100);
}
}, 200);
// 监听窗口大小改变事件
window.addEventListener('resize', handleResize);
var osm = [
new ol.layer.Tile({
source: new ol.source.XYZ({
url: "http://t{0-7}.tianditu.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=" + TDT_API_KEY
})
}),
new ol.layer.Tile({
source: new ol.source.XYZ({
url: "http://t{0-7}.tianditu.com/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=" + TDT_API_KEY
}),
// visible: false
}),
]
// 创建地图
const map = new ol.Map({
target: 'map',
layers: osm,
view: new ol.View({
center: ol.proj.fromLonLat([118.6, 37.5]), // 东营坐标
zoom: 9
})
});
// 添加比例尺控件
const scaleLine = new ol.control.ScaleLine({
target: 'scale-line',
units: 'metric'
});
map.addControl(scaleLine);
// 当前选中的工具按钮
let activeToolButton = null;
// 当前的绘制交互
let currentDraw = null;
// 矢量图层源
const source = new ol.source.Vector();
const vector = new ol.layer.Vector({
source: source
});
map.addLayer(vector);
// 格式化距离显示
function formatLength(line) {
const length = ol.sphere.getLength(line);
let output;
if (length > 1000) {
output = (Math.round(length / 1000 * 100) / 100) + ' km';
} else {
output = (Math.round(length * 100) / 100) + ' m';
}
return output;
}
// 更新工具按钮的选中状态
function updateToolButtonState(button) {
// 如果之前有选中的按钮,取消选中状态
if (activeToolButton) {
activeToolButton.classList.remove('active');
}
// 如果点击的是同一个按钮,则取消选中(相当于关闭工具)
if (activeToolButton === button) {
// 移除当前的绘制交互
if (currentDraw) {
map.removeInteraction(currentDraw);
currentDraw = null;
}
activeToolButton = null;
return false; // 表示工具已关闭
} else {
// 设置新的选中按钮
button.classList.add('active');
activeToolButton = button;
return true; // 表示工具已激活
}
}
// 定位按钮功能
document.getElementById('btn-locate').addEventListener('click', function () {
const isActivated = updateToolButtonState(this);
if (isActivated) {
// 这里可以添加实际的定位功能
const view = map.getView();
view.setCenter(ol.proj.fromLonLat([118.6, 37.5]));
view.setZoom(12);
// 定位功能执行后自动取消激活状态
setTimeout(() => {
if (activeToolButton === this) {
this.classList.remove('active');
activeToolButton = null;
}
}, 300);
}
});
// 绘制点
document.getElementById('btn-draw-point').addEventListener('click', function () {
const isActivated = updateToolButtonState(this);
// 移除之前的绘制交互
if (currentDraw) {
map.removeInteraction(currentDraw);
currentDraw = null;
}
if (isActivated) {
currentDraw = new ol.interaction.Draw({
source: source,
type: 'Point'
});
map.addInteraction(currentDraw);
}
});
// 绘制线
document.getElementById('btn-draw-line').addEventListener('click', function () {
const isActivated = updateToolButtonState(this);
// 移除之前的绘制交互
if (currentDraw) {
map.removeInteraction(currentDraw);
currentDraw = null;
}
if (isActivated) {
currentDraw = new ol.interaction.Draw({
source: source,
type: 'LineString'
});
map.addInteraction(currentDraw);
}
});
// 绘制多边形
document.getElementById('btn-draw-polygon').addEventListener('click', function () {
const isActivated = updateToolButtonState(this);
// 移除之前的绘制交互
if (currentDraw) {
map.removeInteraction(currentDraw);
currentDraw = null;
}
if (isActivated) {
currentDraw = new ol.interaction.Draw({
source: source,
type: 'Polygon'
});
map.addInteraction(currentDraw);
}
});
// 绘制圆形
document.getElementById('btn-draw-circle').addEventListener('click', function () {
const isActivated = updateToolButtonState(this);
// 移除之前的绘制交互
if (currentDraw) {
map.removeInteraction(currentDraw);
currentDraw = null;
}
if (isActivated) {
currentDraw = new ol.interaction.Draw({
source: source,
type: 'Circle'
});
map.addInteraction(currentDraw);
}
});
// 测量功能
document.getElementById('btn-measure').addEventListener('click', function () {
const isActivated = updateToolButtonState(this);
// 移除之前的绘制交互
if (currentDraw) {
map.removeInteraction(currentDraw);
currentDraw = null;
}
if (isActivated) {
currentDraw = new ol.interaction.Draw({
source: source,
type: 'LineString',
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'rgba(0, 0, 255, 0.5)',
lineDash: [10, 10],
width: 2
}),
image: new ol.style.Circle({
radius: 5,
stroke: new ol.style.Stroke({
color: 'rgba(0, 0, 255, 0.5)'
}),
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.2)'
})
})
})
});
// 监听绘制结束事件
currentDraw.on('drawend', function (evt) {
// 获取绘制的要素
const feature = evt.feature;
const line = feature.getGeometry();
// 计算距离
const distance = formatLength(line);
// 创建包含线条和文本的样式数组
const styles = [
// 保留原有的线条样式
new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'rgba(0, 0, 255, 0.5)',
lineDash: [10, 10],
width: 2
})
}),
// 添加文本标注样式
new ol.style.Style({
text: new ol.style.Text({
font: '14px sans-serif',
text: distance,
fill: new ol.style.Fill({
color: 'rgba(0, 0, 0, 1)'
}),
stroke: new ol.style.Stroke({
color: 'rgba(255, 255, 255, 1)',
width: 3
}),
// 将文本放置在线条的中点位置
placement: 'line',
textAlign: 'center'
})
})
];
// 应用样式数组到要素
feature.setStyle(styles);
});
map.addInteraction(currentDraw);
}
});
// 删除功能
document.getElementById('btn-delete').addEventListener('click', function () {
const isActivated = updateToolButtonState(this);
if (isActivated) {
// 清除所有绘制内容
source.clear();
// 移除当前的绘制交互
if (currentDraw) {
map.removeInteraction(currentDraw);
currentDraw = null;
}
// 删除功能执行后自动取消激活状态
setTimeout(() => {
if (activeToolButton === this) {
this.classList.remove('active');
activeToolButton = null;
}
}, 300);
}
});
// 点击地图其他区域时取消绘制
map.on('click', function (e) {
// 可以在这里添加点击事件处理
});
// 修改风险预报图初始化代码,存储实例
const riskCtx = document.getElementById('riskChart').getContext('2d');
window.charts.riskChart = new Chart(riskCtx, {
type: 'bar',
data: {
labels: ['波浪', '海流', '电导率', '潮位', '水温', '溶解氧', '叶绿素', '浊度', 'PH值'],
datasets: [{
label: '风险指数',
data: [15, 65, 20, 60, 25, 18, 22, 55, 85],
backgroundColor: [
'rgba(75, 192, 192, 0.7)',
'rgba(255, 206, 86, 0.7)',
'rgba(75, 192, 192, 0.7)',
'rgba(255, 206, 86, 0.7)',
'rgba(75, 192, 192, 0.7)',
'rgba(75, 192, 192, 0.7)',
'rgba(75, 192, 192, 0.7)',
'rgba(255, 206, 86, 0.7)',
'rgba(255, 99, 132, 0.7)'
],
borderColor: [
'rgba(75, 192, 192, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(75, 192, 192, 1)',
'rgba(75, 192, 192, 1)',
'rgba(255, 206, 86, 1)',
'rgba(255, 99, 132, 1)'
],
borderWidth: 1,
barPercentage: 0.5,
categoryPercentage: 0.8
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: '风险指数'
},
max: 100
}
},
plugins: {
legend: {
display: true,
position: 'top',
labels: {
usePointStyle: true,
generateLabels: function (chart) {
return [
{
text: '无风险',
fillStyle: 'rgba(75, 192, 192, 0.7)',
strokeStyle: 'rgba(75, 192, 192, 1)',
lineWidth: 1,
pointStyle: 'rect',
fontColor: '#666'
},
{
text: '一般风险',
fillStyle: 'rgba(255, 206, 86, 0.7)',
strokeStyle: 'rgba(255, 206, 86, 1)',
lineWidth: 1,
pointStyle: 'rect',
fontColor: '#666'
},
{
text: '重大风险',
fillStyle: 'rgba(255, 99, 132, 0.7)',
strokeStyle: 'rgba(255, 99, 132, 1)',
lineWidth: 1,
pointStyle: 'rect',
fontColor: '#666'
}
];
}
}
},
tooltip: {
callbacks: {
label: function (context) {
let label = context.dataset.label || '';
if (label) {
label += ': ';
}
if (context.parsed.y !== null) {
label += context.parsed.y + '分';
}
return label;
}
}
}
}
}
});
// 数据类型对应的单位
const dataUnits = {
'流速': 'm/s',
'波浪': 'cm',
'温盐': '‰',
'海流': 'cm/s',
'浊度': 'NTU',
'PH': '',
'溶解氧': 'mg/L',
'叶绿素': 'μg/L',
'电导率': 'mS/cm',
'潮位': 'm',
'流向': '°'
};
// 全局变量存储图表实例
window.dataChartInstance = null;
// 模拟数据
function generateMockData(dataType, startDate, endDate) {
const start = new Date(startDate);
const end = new Date(endDate);
const data = [];
// 计算时间间隔10分钟
const interval = 10 * 60 * 1000; // 10分钟毫秒数
const points = Math.min(100, Math.floor((end - start) / interval)); // 最多100个点
for (let i = 0; i <= points; i++) {
const time = new Date(start.getTime() + i * interval);
const timeStr = time.toISOString().slice(0, 16).replace('T', ' ');
// 根据数据类型生成不同的模拟数据
let value;
switch (dataType) {
case '流速':
value = (0.4 + Math.random() * 0.3).toFixed(3);
break;
case '波浪':
value = (10 + Math.random() * 20).toFixed(1);
break;
case '温盐':
value = (30 + Math.random() * 5).toFixed(1);
break;
case '海流':
value = (20 + Math.random() * 30).toFixed(1);
break;
case '浊度':
value = (10 + Math.random() * 10).toFixed(1);
break;
case 'PH':
value = (7.5 + Math.random() * 0.8).toFixed(1);
break;
case '溶解氧':
value = (5 + Math.random() * 3).toFixed(1);
break;
case '叶绿素':
value = (0.5 + Math.random() * 0.5).toFixed(2);
break;
case '电导率':
value = (20 + Math.random() * 10).toFixed(1);
break;
case '潮位':
value = (2 + Math.random() * 2).toFixed(1);
break;
case '流向':
value = Math.floor(Math.random() * 360);
break;
default:
value = (Math.random() * 100).toFixed(2);
}
data.push({
time: timeStr,
value: value
});
}
return data;
}
// 修改数据图表更新函数,确保存储实例
function updateChartData() {
const dataType = document.getElementById('dataTypeSelect').value;
const startDate = document.getElementById('startDate').value;
const endDate = document.getElementById('endDate').value;
document.getElementById('dataColumnType').textContent = `${dataType}(${dataUnits[dataType]})`;
const data = generateMockData(dataType, startDate, endDate);
const tableBody = document.getElementById('dataTableBody');
tableBody.innerHTML = '';
data.forEach(item => {
const row = document.createElement('tr');
row.innerHTML = `
<td>${item.time}</td>
<td>${item.value}</td>
`;
tableBody.appendChild(row);
});
const labels = data.map(item => item.time);
const values = data.map(item => parseFloat(item.value));
if (window.dataChartInstance) {
window.dataChartInstance.destroy();
}
const chartContainer = document.querySelector('.chart-wrapper');
const canvas = document.getElementById('dataChart');
canvas.style.height = '100%';
canvas.style.width = '100%';
const dataCtx = canvas.getContext('2d');
window.dataChartInstance = new Chart(dataCtx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: `${dataType} (${dataUnits[dataType]})`,
data: values,
borderColor: 'rgba(26, 107, 201, 1)',
backgroundColor: 'transparent',
borderWidth: 2,
tension: 0.4,
fill: false,
pointRadius: 3,
pointBackgroundColor: 'rgba(26, 107, 201, 1)',
pointBorderColor: '#fff',
pointBorderWidth: 1,
pointHoverRadius: 6,
pointHoverBackgroundColor: 'rgba(26, 107, 201, 1)',
pointHoverBorderColor: '#fff'
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
labels: {
color: '#333',
font: {
size: 14
}
}
}
},
scales: {
y: {
beginAtZero: false,
title: {
display: true,
text: `${dataType} (${dataUnits[dataType]})`,
color: '#333',
font: {
size: 14
}
},
grid: {
color: 'rgba(0, 0, 0, 0.1)'
},
ticks: {
color: '#666'
}
},
x: {
title: {
display: true,
text: '时间',
color: '#333',
font: {
size: 14
}
},
grid: {
color: 'rgba(0, 0, 0, 0.1)'
},
ticks: {
maxRotation: 45,
minRotation: 45,
color: '#666',
callback: function (value, index) {
const step = Math.ceil(labels.length / 9);
if (index % step === 0 || index === labels.length - 1) {
return labels[index].slice(11);
}
return '';
}
}
}
}
}
});
setTimeout(() => {
if (window.dataChartInstance) {
window.dataChartInstance.resize();
}
}, 100);
}
// 初始化图表和数据
updateChartData();
// 监听选择变化
document.getElementById('dataTypeSelect').addEventListener('change', updateChartData);
document.getElementById('startDate').addEventListener('change', updateChartData);
document.getElementById('endDate').addEventListener('change', updateChartData);
});
</script>
</body>
</html>