// 메인 JavaScript 파일
document.addEventListener('DOMContentLoaded', function() {
console.log('Flask 앱이 로드되었습니다.');
// 고흥 지역 좌표
const GOHEUNG_LAT = 34.6047;
const GOHEUNG_LNG = 127.2855;
// 지도 객체 저장
var maps = {};
// 지도 초기화 함수
function initMap(containerId, lat, lng, zoom) {
if (maps[containerId]) {
maps[containerId].invalidateSize();
return maps[containerId];
}
var container = document.getElementById(containerId);
if (!container) return null;
var map = L.map(containerId).setView([lat, lng], zoom);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
// 고흥 마커 추가
L.marker([lat, lng]).addTo(map)
.bindPopup('고흥')
.openPopup();
maps[containerId] = map;
return map;
}
// 메뉴 아이템과 페이지 콘텐츠 요소 가져오기
const menuItems = document.querySelectorAll('.menu-item');
const submenuItems = document.querySelectorAll('.submenu-item');
const pageContents = document.querySelectorAll('.page-content');
const hasSubmenuItems = document.querySelectorAll('.has-submenu');
// 페이지 전환 함수
function switchPage(pageId) {
// 모든 페이지 콘텐츠 숨기기
pageContents.forEach(function(content) {
content.classList.remove('active');
});
// 모든 메뉴 아이템 비활성화
menuItems.forEach(function(item) {
item.classList.remove('active');
});
// 모든 서브메뉴 아이템 비활성화
submenuItems.forEach(function(item) {
item.classList.remove('active');
});
// 선택된 페이지 콘텐츠 표시
const targetPage = document.getElementById(pageId);
if (targetPage) {
targetPage.classList.add('active');
}
// 선택된 메뉴 아이템 활성화
const activeMenuItem = document.querySelector('.menu-item[data-page="' + pageId + '"]');
if (activeMenuItem) {
activeMenuItem.classList.add('active');
}
// 선택된 서브메뉴 아이템 활성화
const activeSubmenuItem = document.querySelector('.submenu-item[data-page="' + pageId + '"]');
if (activeSubmenuItem) {
activeSubmenuItem.classList.add('active');
// 부모 메뉴도 활성화
const parentMenu = activeSubmenuItem.closest('.has-submenu');
if (parentMenu) {
parentMenu.querySelector('.menu-item').classList.add('active');
}
}
// 페이지별 지도 초기화
setTimeout(function() {
if (pageId === 'intro') {
initMap('map-intro', GOHEUNG_LAT, GOHEUNG_LNG, 11);
} else if (pageId === 'flood-simulation') {
Terrain3D.init('terrain-flood-3d');
loadFlood3DChart();
} else if (pageId === 'flood-monitoring') {
initMap('flood-heatmap', GOHEUNG_LAT, GOHEUNG_LNG, 12);
initMap('flood-mini-map', GOHEUNG_LAT, GOHEUNG_LNG, 13);
loadFloodMonitoringData();
} else if (pageId === 'drought-simulation') {
Terrain3D.init('terrain-drought-3d');
loadDrought3DChart();
} else if (pageId === 'drought-monitoring') {
initGridMap('drought-heatmap');
initMap('drought-mini-map', GOHEUNG_LAT, GOHEUNG_LNG, 13);
loadDroughtMonitoringData();
} else if (pageId === 'kma-test') {
loadKmaForecast();
}
}, 100);
}
// 침수 3D 시뮬레이션 차트 로드
function loadFlood3DChart() {
fetch('/api/terrain/simulation-chart')
.then(function(response) { return response.json(); })
.then(function(data) {
if (data.status === 'success' && data.image) {
var chartImg = document.getElementById('flood-simulation-chart');
if (chartImg) {
chartImg.src = 'data:image/png;base64,' + data.image;
}
}
});
}
// 가뭄 3D 시뮬레이션 차트 로드
function loadDrought3DChart() {
fetch('/api/terrain/simulation-chart')
.then(function(response) { return response.json(); })
.then(function(data) {
if (data.status === 'success' && data.image) {
var chartImg = document.getElementById('drought-simulation-chart');
if (chartImg) {
chartImg.src = 'data:image/png;base64,' + data.image;
}
}
});
}
// 침수 모니터링 데이터 로드
function loadFloodMonitoringData() {
// 히트맵 이미지 로드
fetch('/api/flood/monitoring-heatmap')
.then(function(response) { return response.json(); })
.then(function(data) {
if (data.status === 'success') {
var heatmapOverlay = document.getElementById('flood-heatmap-overlay');
if (heatmapOverlay && data.heatmap_image) {
heatmapOverlay.src = 'data:image/png;base64,' + data.heatmap_image;
}
var miniHeatmap = document.getElementById('flood-mini-heatmap');
if (miniHeatmap && data.mini_heatmap_image) {
miniHeatmap.src = 'data:image/png;base64,' + data.mini_heatmap_image;
}
// Risk Score 업데이트
var riskScoreEl = document.getElementById('flood-risk-score');
if (riskScoreEl && data.risk_score) {
riskScoreEl.textContent = data.risk_score;
}
}
});
// 월별 강수량 차트 로드
fetch('/api/flood/monthly-chart')
.then(function(response) { return response.json(); })
.then(function(data) {
if (data.status === 'success' && data.image) {
var chartImg = document.getElementById('flood-monthly-chart');
if (chartImg) {
chartImg.src = 'data:image/png;base64,' + data.image;
}
}
});
}
// 침수 모니터링 필터 변경 이벤트
var floodMapType = document.getElementById('flood-map-type');
var floodPeriod = document.getElementById('flood-period');
var floodViewType = document.getElementById('flood-view-type');
[floodMapType, floodPeriod, floodViewType].forEach(function(select) {
if (select) {
select.addEventListener('change', function() {
loadFloodMonitoringData();
});
}
});
// 침수 모니터링 버튼 이벤트
var floodDetailBtn = document.getElementById('btn-flood-detail');
if (floodDetailBtn) {
floodDetailBtn.addEventListener('click', function() {
// 시뮬레이션 페이지로 이동
switchPage('flood-simulation');
// 하위 메뉴 열기
var floodSubmenu = document.querySelector('.has-submenu:nth-child(3)');
if (floodSubmenu) {
floodSubmenu.classList.add('open');
}
});
}
var floodReportBtn = document.getElementById('btn-flood-report');
if (floodReportBtn) {
floodReportBtn.addEventListener('click', function() {
alert('보고서 출력 기능은 추후 업데이트 예정입니다.');
});
}
// 침수 수위 곡선 그래프 로드
function loadFloodGraph() {
var graphType = document.getElementById('flood-graph-type');
var graphPeriod = document.getElementById('flood-graph-period');
var graphImage = document.getElementById('flood-graph-image');
var graphPlaceholder = document.getElementById('flood-graph-placeholder');
var graphLoading = document.getElementById('flood-graph-loading');
if (!graphType || !graphPeriod) return;
var type = graphType.value;
var period = graphPeriod.value;
// 로딩 표시
if (graphLoading) graphLoading.style.display = 'block';
if (graphPlaceholder) graphPlaceholder.style.display = 'none';
fetch('/api/flood/graph?type=' + type + '&period=' + period)
.then(function(response) { return response.json(); })
.then(function(data) {
if (graphLoading) graphLoading.style.display = 'none';
if (data.status === 'success' && data.image) {
if (graphImage) {
graphImage.src = 'data:image/png;base64,' + data.image;
graphImage.style.display = 'block';
}
if (graphPlaceholder) graphPlaceholder.style.display = 'none';
// 통계 정보 업데이트
if (data.stats) {
var currentLevel = document.getElementById('flood-current-level');
var avgLevel = document.getElementById('flood-avg-level');
var maxLevel = document.getElementById('flood-max-level');
if (currentLevel) currentLevel.textContent = data.stats.current;
if (avgLevel) avgLevel.textContent = data.stats.avg;
if (maxLevel) maxLevel.textContent = data.stats.max;
}
}
})
.catch(function(error) {
if (graphLoading) graphLoading.style.display = 'none';
if (graphPlaceholder) {
graphPlaceholder.style.display = 'block';
graphPlaceholder.querySelector('span').textContent = '그래프 로드 실패';
}
});
}
// 침수 수위 곡선 버튼 이벤트
var floodGraphLoadBtn = document.getElementById('btn-flood-graph-load');
if (floodGraphLoadBtn) {
floodGraphLoadBtn.addEventListener('click', loadFloodGraph);
}
// 가뭄 시계열 변화 그래프 로드
function loadDroughtGraph() {
var graphType = document.getElementById('drought-graph-type');
var graphPeriod = document.getElementById('drought-graph-period');
var graphImage = document.getElementById('drought-graph-image');
var graphPlaceholder = document.getElementById('drought-graph-placeholder');
var graphLoading = document.getElementById('drought-graph-loading');
if (!graphType || !graphPeriod) return;
var type = graphType.value;
var period = graphPeriod.value;
// 로딩 표시
if (graphLoading) graphLoading.style.display = 'block';
if (graphPlaceholder) graphPlaceholder.style.display = 'none';
fetch('/api/drought/graph?type=' + type + '&period=' + period)
.then(function(response) { return response.json(); })
.then(function(data) {
if (graphLoading) graphLoading.style.display = 'none';
if (data.status === 'success' && data.image) {
if (graphImage) {
graphImage.src = 'data:image/png;base64,' + data.image;
graphImage.style.display = 'block';
}
if (graphPlaceholder) graphPlaceholder.style.display = 'none';
// 통계 정보 업데이트
if (data.stats) {
var currentValue = document.getElementById('drought-current-value');
var avgValue = document.getElementById('drought-avg-value');
var minValue = document.getElementById('drought-min-value');
var gradeValue = document.getElementById('drought-grade');
if (currentValue) currentValue.textContent = data.stats.current;
if (avgValue) avgValue.textContent = data.stats.avg;
if (minValue) minValue.textContent = data.stats.min;
if (gradeValue) gradeValue.textContent = data.stats.grade;
}
}
})
.catch(function(error) {
if (graphLoading) graphLoading.style.display = 'none';
if (graphPlaceholder) {
graphPlaceholder.style.display = 'block';
graphPlaceholder.querySelector('span').textContent = '그래프 로드 실패';
}
});
}
// 가뭄 시계열 변화 그래프 버튼 이벤트
var droughtGraphLoadBtn = document.getElementById('btn-drought-graph-load');
if (droughtGraphLoadBtn) {
droughtGraphLoadBtn.addEventListener('click', loadDroughtGraph);
}
// SHP 파일을 JPG로 렌더링하여 지도 영역에 표시
function initGridMap(containerId, gridSize) {
gridSize = gridSize || 500;
var container = document.getElementById(containerId);
if (!container) return;
// 기존 Leaflet 지도 제거 (이미지로 대체)
if (maps[containerId]) {
maps[containerId].remove();
delete maps[containerId];
}
// 로딩 표시
container.innerHTML = '
SHP 렌더링 중...
';
fetch('/api/drought/shp-render?grid=' + gridSize)
.then(function(response) { return response.json(); })
.then(function(data) {
if (data.status === 'success' && data.image) {
container.innerHTML = '';
var img = document.createElement('img');
img.src = 'data:image/jpeg;base64,' + data.image;
img.style.width = '100%';
img.style.height = '100%';
img.style.objectFit = 'contain';
img.alt = '가뭄 SHP 렌더링';
container.appendChild(img);
} else {
container.innerHTML = '' + (data.message || '렌더링 실패') + '
';
}
})
.catch(function(error) {
container.innerHTML = '오류: ' + error.message + '
';
});
}
// 격자 단위 버튼 이벤트
document.querySelectorAll('.grid-btn').forEach(function(btn) {
btn.addEventListener('click', function() {
document.querySelectorAll('.grid-btn').forEach(function(b) { b.classList.remove('active'); });
btn.classList.add('active');
initGridMap('drought-heatmap', parseInt(btn.dataset.grid));
});
});
// 가뭄 모니터링 데이터 로드
function loadDroughtMonitoringData() {
// 히트맵 이미지 로드
fetch('/api/drought/monitoring-heatmap')
.then(function(response) { return response.json(); })
.then(function(data) {
if (data.status === 'success') {
var heatmapOverlay = document.getElementById('drought-heatmap-overlay');
if (heatmapOverlay && data.heatmap_image) {
heatmapOverlay.src = 'data:image/png;base64,' + data.heatmap_image;
}
var miniHeatmap = document.getElementById('drought-mini-heatmap');
if (miniHeatmap && data.mini_heatmap_image) {
miniHeatmap.src = 'data:image/png;base64,' + data.mini_heatmap_image;
}
// Risk Score 업데이트
var riskScoreEl = document.getElementById('drought-risk-score');
if (riskScoreEl && data.risk_score) {
riskScoreEl.textContent = data.risk_score;
}
}
});
// 월별 가뭄 지수 차트 로드
fetch('/api/drought/monthly-chart')
.then(function(response) { return response.json(); })
.then(function(data) {
if (data.status === 'success' && data.image) {
var chartImg = document.getElementById('drought-monthly-chart');
if (chartImg) {
chartImg.src = 'data:image/png;base64,' + data.image;
}
}
});
}
// 가뭄 모니터링 필터 변경 이벤트
var droughtMapType = document.getElementById('drought-map-type');
var droughtPeriod = document.getElementById('drought-period');
var droughtViewType = document.getElementById('drought-view-type');
[droughtMapType, droughtPeriod, droughtViewType].forEach(function(select) {
if (select) {
select.addEventListener('change', function() {
loadDroughtMonitoringData();
});
}
});
// 가뭄 모니터링 버튼 이벤트
var droughtDetailBtn = document.getElementById('btn-drought-detail');
if (droughtDetailBtn) {
droughtDetailBtn.addEventListener('click', function() {
// 시뮬레이션 페이지로 이동
switchPage('drought-simulation');
// 하위 메뉴 열기
var droughtSubmenu = document.querySelector('.has-submenu:nth-child(4)');
if (droughtSubmenu) {
droughtSubmenu.classList.add('open');
}
});
}
var droughtReportBtn = document.getElementById('btn-drought-report');
if (droughtReportBtn) {
droughtReportBtn.addEventListener('click', function() {
alert('보고서 출력 기능은 추후 업데이트 예정입니다.');
});
}
// 가뭄 탭 버튼 이벤트 (탭 전환만, 페이지 이동 없음)
document.querySelectorAll('.drought-tab-btn').forEach(function(btn) {
btn.addEventListener('click', function() {
document.querySelectorAll('.drought-tab-btn').forEach(function(b) { b.classList.remove('active'); });
btn.classList.add('active');
});
});
// 메뉴 클릭 이벤트 리스너 등록
menuItems.forEach(function(item) {
item.addEventListener('click', function(e) {
e.preventDefault();
const parentLi = this.parentElement;
// 하위 메뉴가 있는 경우 토글
if (parentLi.classList.contains('has-submenu')) {
parentLi.classList.toggle('open');
}
const pageId = this.getAttribute('data-page');
switchPage(pageId);
});
});
// 서브메뉴 클릭 이벤트 리스너 등록
submenuItems.forEach(function(item) {
item.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
const pageId = this.getAttribute('data-page');
switchPage(pageId);
});
});
// API 호출 함수
function callApi(apiUrl, container) {
const loading = container.querySelector('.loading');
const plotImage = container.querySelector('.plot-image');
const plotMessage = container.querySelector('.plot-message');
// 로딩 표시
loading.style.display = 'block';
plotImage.style.display = 'none';
plotMessage.style.display = 'none';
fetch(apiUrl)
.then(function(response) {
return response.json();
})
.then(function(data) {
loading.style.display = 'none';
if (data.status === 'success' && data.image) {
plotImage.src = 'data:image/png;base64,' + data.image;
plotImage.style.display = 'block';
} else {
plotMessage.textContent = data.message || '결과를 불러올 수 없습니다.';
plotMessage.style.display = 'block';
}
})
.catch(function(error) {
loading.style.display = 'none';
plotMessage.textContent = '오류가 발생했습니다: ' + error.message;
plotMessage.style.display = 'block';
});
}
// API 버튼 클릭 이벤트 리스너 등록
const apiBtns = document.querySelectorAll('.api-btn');
apiBtns.forEach(function(btn) {
btn.addEventListener('click', function() {
const apiUrl = this.getAttribute('data-api');
const container = this.parentElement.querySelector('.plot-container');
callApi(apiUrl, container);
});
});
// 침수 3D 시뮬레이션 버튼 클릭 이벤트
var floodSimBtn = document.getElementById('btn-flood-simulation');
if (floodSimBtn) {
floodSimBtn.addEventListener('click', function() {
loadFlood3DChart();
// 통계 업데이트 (랜덤 시뮬레이션)
var areaEl = document.querySelector('.flood-stat-area');
var buildingEl = document.querySelector('.flood-stat-building');
var costEl = document.querySelector('.flood-stat-cost');
if (areaEl) {
var area = Math.floor(Math.random() * 3000) + 3000;
areaEl.innerHTML = area.toLocaleString() + ' ㎡';
}
if (buildingEl) {
var building = Math.floor(Math.random() * 100) + 80;
buildingEl.innerHTML = building.toLocaleString() + ' 동';
}
if (costEl) {
var cost = (Math.random() * 15 + 10).toFixed(1);
costEl.innerHTML = cost + ' 억원';
}
});
}
// 가뭄 3D 시뮬레이션 버튼 클릭 이벤트
var droughtSimBtn = document.getElementById('btn-drought-simulation');
if (droughtSimBtn) {
droughtSimBtn.addEventListener('click', function() {
loadDrought3DChart();
// 통계 업데이트 (랜덤 시뮬레이션)
var areaEl = document.querySelector('.drought-stat-area');
var farmEl = document.querySelector('.drought-stat-farm');
var costEl = document.querySelector('.drought-stat-cost');
if (areaEl) {
var area = Math.floor(Math.random() * 5000) + 5000;
areaEl.innerHTML = area.toLocaleString() + ' ㎡';
}
if (farmEl) {
var farm = Math.floor(Math.random() * 2000) + 2000;
farmEl.innerHTML = farm.toLocaleString() + ' ㎡';
}
if (costEl) {
var cost = (Math.random() * 10 + 8).toFixed(1);
costEl.innerHTML = cost + ' 억원';
}
});
}
// ========== Water Body 추출 기능 (Drag & Drop) ==========
var wbDropzone = document.getElementById('wb-dropzone');
var wbFileInput = document.getElementById('wb-file-input');
var wbBrowseBtn = document.getElementById('btn-wb-browse');
var wbRemoveBtn = document.getElementById('btn-wb-remove');
var wbExtractBtn = document.getElementById('btn-waterbody-extract');
var wbDropzoneContent = document.getElementById('wb-dropzone-content');
var wbPreview = document.getElementById('wb-preview');
var wbInputImage = document.getElementById('wb-input-image');
var wbOutputImage = document.getElementById('wb-output-image');
var wbResultPlaceholder = document.getElementById('wb-result-placeholder');
var wbResultContainer = document.getElementById('wb-result-container');
var wbExtractLoading = document.getElementById('wb-extract-loading');
var wbResultInfo = document.getElementById('wb-result-info');
// 업로드된 파일 저장
var uploadedFile = null;
// 파일 선택 버튼 클릭
if (wbBrowseBtn) {
wbBrowseBtn.addEventListener('click', function(e) {
e.preventDefault();
wbFileInput.click();
});
}
// 파일 선택 이벤트
if (wbFileInput) {
wbFileInput.addEventListener('change', function(e) {
var file = e.target.files[0];
if (file) {
handleFileUpload(file);
}
});
}
// 드래그 이벤트
if (wbDropzone) {
// 드래그 오버
wbDropzone.addEventListener('dragover', function(e) {
e.preventDefault();
e.stopPropagation();
wbDropzone.classList.add('dragover');
});
// 드래그 리브
wbDropzone.addEventListener('dragleave', function(e) {
e.preventDefault();
e.stopPropagation();
wbDropzone.classList.remove('dragover');
});
// 드롭
wbDropzone.addEventListener('drop', function(e) {
e.preventDefault();
e.stopPropagation();
wbDropzone.classList.remove('dragover');
var file = e.dataTransfer.files[0];
if (file && file.type.startsWith('image/')) {
handleFileUpload(file);
} else {
alert('이미지 파일만 업로드 가능합니다.');
}
});
}
// 파일 업로드 처리
function handleFileUpload(file) {
uploadedFile = file;
// 이미지 미리보기
var reader = new FileReader();
reader.onload = function(e) {
wbInputImage.src = e.target.result;
wbDropzoneContent.style.display = 'none';
wbPreview.style.display = 'block';
// 추출 버튼 활성화
if (wbExtractBtn) {
wbExtractBtn.disabled = false;
}
};
reader.readAsDataURL(file);
// 결과 영역 초기화
resetOutputArea();
}
// 이미지 제거 버튼
if (wbRemoveBtn) {
wbRemoveBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
resetInputArea();
resetOutputArea();
});
}
// 입력 영역 초기화
function resetInputArea() {
uploadedFile = null;
wbInputImage.src = '';
wbDropzoneContent.style.display = 'flex';
wbPreview.style.display = 'none';
wbFileInput.value = '';
if (wbExtractBtn) {
wbExtractBtn.disabled = true;
}
}
// 출력 영역 초기화
function resetOutputArea() {
wbOutputImage.src = '';
wbOutputImage.style.display = 'none';
wbResultPlaceholder.style.display = 'flex';
wbResultInfo.style.display = 'none';
}
// 추출 버튼 클릭
if (wbExtractBtn) {
wbExtractBtn.addEventListener('click', function() {
if (!uploadedFile) {
alert('이미지를 먼저 업로드해주세요.');
return;
}
// 로딩 표시
wbExtractBtn.style.display = 'none';
wbExtractLoading.style.display = 'flex';
wbResultPlaceholder.style.display = 'none';
// FormData로 이미지 전송
var formData = new FormData();
formData.append('image', uploadedFile);
fetch('/api/waterbody/predict', {
method: 'POST',
body: formData
})
.then(function(response) { return response.json(); })
.then(function(data) {
wbExtractBtn.style.display = 'flex';
wbExtractLoading.style.display = 'none';
if (data.status === 'success') {
// 결과 이미지 표시
wbOutputImage.src = 'data:image/png;base64,' + data.output_image;
wbOutputImage.style.display = 'block';
wbResultPlaceholder.style.display = 'none';
// 결과 정보 표시
if (data.data) {
document.getElementById('wb-area').textContent = data.data.area || '-';
document.getElementById('wb-ratio').textContent = data.data.ratio || '-';
document.getElementById('wb-count').textContent = data.data.count ? data.data.count + '개' : '-';
document.getElementById('wb-confidence').textContent = data.data.confidence || '-';
}
wbResultInfo.style.display = 'flex';
} else {
alert('추출 실패: ' + (data.message || '알 수 없는 오류'));
wbResultPlaceholder.style.display = 'flex';
}
})
.catch(function(error) {
wbExtractBtn.style.display = 'flex';
wbExtractLoading.style.display = 'none';
wbResultPlaceholder.style.display = 'flex';
alert('오류가 발생했습니다: ' + error.message);
});
});
}
// ========== Intro 대시보드 기능 ==========
// 현재 날짜/시간 표시
function updateCurrentDateTime() {
var now = new Date();
var days = ['일', '월', '화', '수', '목', '금', '토'];
var dateStr = now.getFullYear() + '.' +
String(now.getMonth() + 1).padStart(2, '0') + '.' +
String(now.getDate()).padStart(2, '0') + ' (' + days[now.getDay()] + ')';
var dateTimeEl = document.getElementById('current-datetime');
if (dateTimeEl) {
dateTimeEl.textContent = dateStr;
}
}
// 날짜 셀렉터 초기화
function initDateSelector() {
var now = new Date();
var yearSelect = document.getElementById('select-year');
var monthSelect = document.getElementById('select-month');
var daySelect = document.getElementById('select-day');
if (!yearSelect || !monthSelect || !daySelect) return;
// 현재 날짜로 설정
yearSelect.value = now.getFullYear();
monthSelect.value = now.getMonth() + 1;
// 일 옵션 업데이트
updateDayOptions();
daySelect.value = now.getDate();
// 월 변경 시 일 옵션 업데이트
yearSelect.addEventListener('change', updateDayOptions);
monthSelect.addEventListener('change', updateDayOptions);
}
// 일 옵션 업데이트
function updateDayOptions() {
var yearSelect = document.getElementById('select-year');
var monthSelect = document.getElementById('select-month');
var daySelect = document.getElementById('select-day');
if (!yearSelect || !monthSelect || !daySelect) return;
var year = parseInt(yearSelect.value);
var month = parseInt(monthSelect.value);
var daysInMonth = new Date(year, month, 0).getDate();
var currentDay = parseInt(daySelect.value) || 1;
daySelect.innerHTML = '';
for (var i = 1; i <= daysInMonth; i++) {
var option = document.createElement('option');
option.value = i;
option.textContent = i + '일';
daySelect.appendChild(option);
}
daySelect.value = Math.min(currentDay, daysInMonth);
}
// 모니터링 데이터 업데이트 (시뮬레이션)
function updateMonitoringData() {
// 침수 예측 확률 업데이트
var floodProb = Math.floor(Math.random() * 40) + 10;
var floodProbEl = document.getElementById('flood-prob');
var floodFill = document.querySelector('.flood-fill');
var floodStatus = document.querySelector('.monitoring-card.flood .prob-status');
if (floodProbEl) floodProbEl.textContent = floodProb;
if (floodFill) floodFill.style.width = floodProb + '%';
if (floodStatus) {
if (floodProb < 30) {
floodStatus.className = 'prob-status safe';
floodStatus.textContent = '낮음';
} else if (floodProb < 60) {
floodStatus.className = 'prob-status warning';
floodStatus.textContent = '주의';
} else {
floodStatus.className = 'prob-status danger';
floodStatus.textContent = '위험';
}
}
// 가뭄 예측 확률 업데이트
var droughtProb = Math.floor(Math.random() * 50) + 30;
var droughtProbEl = document.getElementById('drought-prob');
var droughtFill = document.querySelector('.drought-fill');
var droughtStatus = document.querySelector('.monitoring-card.drought .prob-status');
if (droughtProbEl) droughtProbEl.textContent = droughtProb;
if (droughtFill) droughtFill.style.width = droughtProb + '%';
if (droughtStatus) {
if (droughtProb < 30) {
droughtStatus.className = 'prob-status safe';
droughtStatus.textContent = '낮음';
} else if (droughtProb < 60) {
droughtStatus.className = 'prob-status warning';
droughtStatus.textContent = '주의';
} else {
droughtStatus.className = 'prob-status danger';
droughtStatus.textContent = '위험';
}
}
// 종합 위험도 업데이트
var overallRisk = Math.floor((floodProb + droughtProb) / 2);
var gaugeValue = document.querySelector('.gauge-value');
var gaugeLabel = document.querySelector('.gauge-label');
var gaugeFill = document.querySelector('.gauge-fill');
if (gaugeValue) gaugeValue.textContent = overallRisk;
if (gaugeFill) {
gaugeFill.setAttribute('stroke-dasharray', overallRisk + ', 100');
if (overallRisk < 30) {
gaugeFill.className.baseVal = 'gauge-fill safe';
if (gaugeLabel) {
gaugeLabel.textContent = '안전';
gaugeLabel.style.color = '#27ae60';
}
} else if (overallRisk < 60) {
gaugeFill.className.baseVal = 'gauge-fill warning';
if (gaugeLabel) {
gaugeLabel.textContent = '보통';
gaugeLabel.style.color = '#f39c12';
}
} else {
gaugeFill.className.baseVal = 'gauge-fill danger';
if (gaugeLabel) {
gaugeLabel.textContent = '위험';
gaugeLabel.style.color = '#e74c3c';
}
}
}
// 예보 미니 업데이트
var floodForecasts = document.querySelectorAll('.monitoring-card.flood .fc-value');
floodForecasts.forEach(function(el) {
el.textContent = (floodProb + Math.floor(Math.random() * 10) - 5) + '%';
});
var droughtForecasts = document.querySelectorAll('.monitoring-card.drought .fc-value');
droughtForecasts.forEach(function(el) {
el.textContent = (droughtProb + Math.floor(Math.random() * 10) - 5) + '%';
});
}
// 날짜 조회 버튼 클릭
var dateSearchBtn = document.getElementById('btn-date-search');
if (dateSearchBtn) {
dateSearchBtn.addEventListener('click', function() {
updateMonitoringData();
var year = document.getElementById('select-year').value;
var month = document.getElementById('select-month').value;
var day = document.getElementById('select-day').value;
var dateTimeEl = document.getElementById('current-datetime');
var selectedDate = new Date(year, month - 1, day);
var days = ['일', '월', '화', '수', '목', '금', '토'];
var dateStr = year + '.' +
String(month).padStart(2, '0') + '.' +
String(day).padStart(2, '0') + ' (' + days[selectedDate.getDay()] + ')';
if (dateTimeEl) {
dateTimeEl.textContent = dateStr;
}
});
}
// ========== 테스트용 화면 (기상청 단기예보 - 고흥) ==========
var KMA_DISPLAY_COLS = [
{ key: 'numEf', label: '예보차수' },
{ key: 'wf', label: '날씨' },
{ key: 'ta', label: '예상기온(℃)' },
{ key: 'rnSt', label: '강수확률(%)' },
{ key: 'rnYn', label: '강수형태' },
{ key: 'wd1', label: '풍향(1)' },
{ key: 'wd2', label: '풍향(2)' },
{ key: 'wsIt', label: '풍속강도' },
{ key: 'wfCd', label: '하늘상태' }
];
var KMA_RNYN_NAMES = {
'0': '없음', '1': '비', '2': '비/눈', '3': '눈', '4': '소나기'
};
var KMA_WSLT_NAMES = {
'1': '약', '2': '약간강', '3': '강', '4': '매우강'
};
var kmaCache = null;
function loadKmaForecast() {
var placeholder = document.getElementById('kma-placeholder');
var loading = document.getElementById('kma-loading');
var dataContainer = document.getElementById('kma-data-container');
var summary = document.getElementById('kma-summary');
// 캐시가 있으면 재사용
if (kmaCache) {
renderKmaTable(kmaCache);
return;
}
if (placeholder) placeholder.style.display = 'none';
if (summary) summary.style.display = 'none';
loading.style.display = 'flex';
dataContainer.style.display = 'none';
fetch('/api/kma/forecast')
.then(function(res) { return res.json(); })
.then(function(result) {
loading.style.display = 'none';
if (!result.success) {
if (placeholder) placeholder.style.display = 'block';
return;
}
kmaCache = result;
renderKmaTable(result);
})
.catch(function(err) {
loading.style.display = 'none';
if (placeholder) placeholder.style.display = 'block';
});
}
function renderKmaTable(result) {
var summary = document.getElementById('kma-summary');
var dataContainer = document.getElementById('kma-data-container');
document.getElementById('kma-count').textContent = result.count + '건';
// 발표시간 표시
var rows = result.rows || [];
if (rows.length > 0 && rows[0].announceTime) {
var s = String(rows[0].announceTime);
var formatted = s.length >= 10
? s.substring(0,4) + '.' + s.substring(4,6) + '.' + s.substring(6,8) + ' ' + s.substring(8,10) + ':00'
: s;
document.getElementById('kma-announce-time').textContent = formatted;
}
if (summary) summary.style.display = 'flex';
var rows = result.rows || [];
var tableHead = document.getElementById('kma-table-head');
var tableBody = document.getElementById('kma-table-body');
tableHead.innerHTML = '';
tableBody.innerHTML = '';
if (rows.length > 0) {
var headRow = '';
KMA_DISPLAY_COLS.forEach(function(col) {
headRow += '| ' + col.label + ' | ';
});
headRow += '
';
tableHead.innerHTML = headRow;
rows.forEach(function(row) {
var tr = '';
KMA_DISPLAY_COLS.forEach(function(col) {
var val = row[col.key];
if (col.key === 'rnYn' && KMA_RNYN_NAMES[String(val)] !== undefined) {
val = KMA_RNYN_NAMES[String(val)];
}
if (col.key === 'wsIt' && KMA_WSLT_NAMES[String(val)] !== undefined) {
val = KMA_WSLT_NAMES[String(val)];
}
if (col.key === 'numEf') {
var efNames = {0:'오늘밤', 1:'내일오전', 2:'내일오후', 3:'모레오전', 4:'모레오후', 5:'+3일오전', 6:'+3일오후', 7:'+4일오전', 8:'+4일오후'};
if (efNames[val] !== undefined) val = efNames[val];
}
tr += '| ' + (val !== null && val !== undefined && val !== '' ? val : '-') + ' | ';
});
tr += '
';
tableBody.innerHTML += tr;
});
dataContainer.style.display = 'block';
}
}
var btnKmaFetch = document.getElementById('btn-kma-fetch');
if (btnKmaFetch) {
btnKmaFetch.addEventListener('click', function() {
kmaCache = null; // 수동 조회 시 캐시 초기화
loadKmaForecast();
});
}
// 초기화
updateCurrentDateTime();
initDateSelector();
// 초기 페이지 지도 로드
setTimeout(function() {
initMap('map-intro', GOHEUNG_LAT, GOHEUNG_LNG, 11);
}, 200);
});