signal-batch/src/main/resources/static/v2/pages/chunked-streaming.html
HeungTak Lee 89482d854f feat: Add V2 REST API with WebSocket-compatible responses
- Add GisControllerV2/GisServiceV2 for CompactVesselTrack responses
- Add nationalCode and shipKindCode fields to REST API responses
- Add flexible DateTime parsing support (multiple formats)
- Add TrackConverter utility for track data conversion
- Update SwaggerConfig with V2 API endpoints and unified tags
- Update ProdDataSourceConfig for prod-mpr profile support
- Enhance Swagger documentation for all DTOs
2026-01-20 13:38:31 +09:00

252 lines
11 KiB
HTML

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>청크 GIS 스트리밍 v2.0 - 선박 애니메이션</title>
<!-- 외부 라이브러리 CSS (폐쇄망 대응) -->
<link href="/libs/css/maplibre-gl.css" rel="stylesheet">
<link href="/libs/css/bootstrap.min.css" rel="stylesheet">
<link href="/libs/css/bootstrap-icons.css" rel="stylesheet">
<!-- 커스텀 CSS -->
<link href="/v2/css/common.css" rel="stylesheet">
<link href="/v2/css/chunked-streaming.css" rel="stylesheet">
</head>
<body>
<div id="mapContainer"></div>
<!-- 제어 패널 -->
<div class="control-panel">
<h5 class="mb-3">
<i class="bi bi-globe2"></i> 청크 GIS v2.0 + 애니메이션
</h5>
<!-- 연결 제어 -->
<div class="form-section">
<div class="btn-group w-100" role="group">
<button id="connectBtn" class="btn btn-sm btn-success" onclick="connect()">
<i class="bi bi-plug"></i> 연결
</button>
<button id="disconnectBtn" class="btn btn-sm btn-danger" onclick="disconnect()" disabled>
<i class="bi bi-plug-fill"></i> 연결 해제
</button>
</div>
</div>
<!-- 시간 설정 -->
<div class="form-section">
<div class="row g-2">
<div class="col-6">
<label class="form-label small">시작 시간</label>
<input type="datetime-local" class="form-control form-control-sm" id="startTime">
</div>
<div class="col-6">
<label class="form-label small">종료 시간</label>
<input type="datetime-local" class="form-control form-control-sm" id="endTime">
</div>
</div>
<div class="mt-2">
<button class="btn btn-sm btn-outline-secondary" onclick="setTimeRange(1)">1시간</button>
<button class="btn btn-sm btn-outline-secondary" onclick="setTimeRange(6)">6시간</button>
<button class="btn btn-sm btn-outline-secondary" onclick="setTimeRange(24)">1일</button>
<button class="btn btn-sm btn-outline-secondary" onclick="setTimeRange(72)">3일</button>
<button class="btn btn-sm btn-outline-secondary" onclick="setTimeRange(168)">7일</button>
</div>
</div>
<!-- 영역 설정 -->
<div class="form-section">
<div class="d-flex justify-content-between align-items-center mb-2">
<label class="form-label small mb-0">현재 뷰포트</label>
<span class="badge bg-primary" id="currentZoom">Zoom: 6</span>
</div>
<div class="row g-2">
<div class="col-6">
<input type="number" class="form-control form-control-sm" id="minLon" value="124" placeholder="Min Lon" readonly>
</div>
<div class="col-6">
<input type="number" class="form-control form-control-sm" id="maxLon" value="132" placeholder="Max Lon" readonly>
</div>
</div>
<div class="row g-2 mt-1">
<div class="col-6">
<input type="number" class="form-control form-control-sm" id="minLat" value="33" placeholder="Min Lat" readonly>
</div>
<div class="col-6">
<input type="number" class="form-control form-control-sm" id="maxLat" value="38" placeholder="Max Lat" readonly>
</div>
</div>
<div class="small text-muted mt-1">
<i class="bi bi-info-circle"></i> 현재 맵 뷰포트와 줌 레벨을 사용합니다
</div>
</div>
<!-- 렌더링 옵션 -->
<div class="form-section">
<h6 class="mb-2">렌더링 옵션</h6>
<div class="render-options">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="showTracks" checked>
<label class="form-check-label small" for="showTracks">궤적 표시</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="showVessels" checked>
<label class="form-check-label small" for="showVessels">선박 아이콘 표시</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="colorBySpeed" checked>
<label class="form-check-label small" for="colorBySpeed">속도별 색상</label>
</div>
<div class="mt-2">
<label class="form-label small">궤적 투명도</label>
<input type="range" class="form-range" id="trackOpacity" min="0" max="100" value="60">
</div>
</div>
</div>
<!-- 쿼리 실행 -->
<button id="startBtn" class="btn btn-primary w-100" onclick="startQuery()" disabled>
<i class="bi bi-play-circle"></i> 스트리밍 시작
</button>
<button id="cancelBtn" class="btn btn-warning w-100 mt-2" onclick="cancelQuery()" style="display: none;">
<i class="bi bi-stop-circle"></i> 취소
</button>
<!-- 진행률 -->
<div class="progress mt-3" style="display: none;" id="progressContainer">
<div class="progress-bar progress-bar-striped progress-bar-animated"
id="progressBar" style="width: 0%">0%</div>
</div>
</div>
<!-- 통계 패널 -->
<div class="stats-panel">
<h6 class="mb-3"><i class="bi bi-speedometer2"></i> 실시간 통계</h6>
<div class="stat-card">
<div class="stat-label">청크 수신</div>
<div class="stat-value" id="chunksReceived">0</div>
</div>
<div class="stat-card">
<div class="stat-label">선박 수</div>
<div class="stat-value" id="vesselCount">0</div>
</div>
<div class="stat-card">
<div class="stat-label">포인트 수</div>
<div class="stat-value" id="pointCount">0</div>
</div>
<div class="stat-card">
<div class="stat-label">데이터 크기</div>
<div class="stat-value" id="dataSize">0</div>
<div class="stat-label">KB</div>
</div>
<div class="stat-card">
<div class="stat-label">처리 시간</div>
<div class="stat-value" id="processTime">0</div>
<div class="stat-label"></div>
</div>
</div>
<!-- 타임라인 패널 -->
<div class="timeline-panel" style="display: none;" id="timelinePanel">
<button class="btn btn-sm btn-close position-absolute" style="top: 10px; right: 10px;" onclick="resetAll()" title="닫기"></button>
<div class="timeline-controls">
<button class="btn btn-sm btn-primary" id="playBtn" onclick="togglePlay()">
<i class="bi bi-play-fill"></i>
</button>
<div class="speed-control">
<label class="small mb-0">속도:</label>
<button class="btn btn-sm btn-outline-secondary btn-speed" onclick="setSpeed(0.5)">0.5x</button>
<button class="btn btn-sm btn-secondary btn-speed" onclick="setSpeed(1)">1x</button>
<button class="btn btn-sm btn-outline-secondary btn-speed" onclick="setSpeed(2)">2x</button>
<button class="btn btn-sm btn-outline-secondary btn-speed" onclick="setSpeed(5)">5x</button>
<button class="btn btn-sm btn-outline-secondary btn-speed" onclick="setSpeed(50)">50x</button>
<button class="btn btn-sm btn-outline-secondary btn-speed" onclick="setSpeed(100)">100x</button>
<button class="btn btn-sm btn-outline-secondary btn-speed" onclick="setSpeed(500)">500x</button>
</div>
<div class="time-display">
<div id="currentDateDisplay" style="font-size: 12px; color: #6c757d;">----/--/--</div>
<div id="currentTimeDisplay">--:--:--</div>
</div>
</div>
<input type="range" class="form-range timeline-slider"
id="timeSlider" min="0" max="100" value="0">
<div class="d-flex justify-content-between small text-muted">
<span id="startTimeDisplay">--:--</span>
<span id="endTimeDisplay">--:--</span>
</div>
</div>
<!-- 범례 -->
<div class="legend" style="display: none;" id="legend">
<h6 class="mb-2">속도 범례</h6>
<div class="legend-item">
<div class="legend-color" style="background: #1e90ff;"></div>
<span>0-5 knots</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background: #00ff00;"></div>
<span>5-10 knots</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background: #ffff00;"></div>
<span>10-15 knots</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background: #ff8c00;"></div>
<span>15-20 knots</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background: #ff0000;"></div>
<span>20+ knots</span>
</div>
<hr class="my-2">
<h6 class="mb-2">선박 아이콘</h6>
<div class="legend-item">
<div class="vessel-icon" style="background: #00ff00;"></div>
<span>이동중</span>
</div>
<div class="legend-item">
<div class="vessel-icon" style="background: #ffff00;"></div>
<span>저속</span>
</div>
<div class="legend-item">
<div class="vessel-icon" style="background: #ff0000;"></div>
<span>정지</span>
</div>
</div>
<!-- 로그 패널 -->
<div class="log-panel">
<div class="d-flex justify-content-between align-items-center mb-2">
<h6 class="mb-0"><i class="bi bi-terminal"></i> 로그</h6>
<button class="btn btn-sm btn-outline-secondary" onclick="clearLog()">초기화</button>
</div>
<div id="logContainer"></div>
</div>
<!-- 툴팁 -->
<div id="vesselTooltip"></div>
<!-- 외부 라이브러리 JS (폐쇄망 대응) -->
<script src="/libs/js/sockjs.min.js"></script>
<script src="/libs/js/stomp.min.js"></script>
<script src="/libs/js/maplibre-gl.js"></script>
<script src="/libs/js/deck.gl.min.js"></script>
<!-- 메인 애플리케이션 스크립트 -->
<script type="module" src="/v2/js/pages/chunked-streaming-app.js"></script>
</body>
</html>