/** * 공통 헬퍼 함수 */ import { ABNORMAL_TYPE_LABELS, ABNORMAL_TYPE_DESCRIPTIONS, ABNORMAL_TYPE_COLORS } from './constants.js'; /** * 날짜 범위 설정 * @param {number} days - 일 수 * @returns {Object} 시작일과 종료일 */ export function getDateRange(days) { const endDate = new Date(); const startDate = new Date(); startDate.setDate(endDate.getDate() - days); return { startDate: startDate.toISOString().split('T')[0], endDate: endDate.toISOString().split('T')[0] }; } /** * 날짜를 시간 차이로 변환 * @param {string} startDate - 시작 날짜 * @returns {number} 현재로부터의 시간 차이 */ export function getHoursFromNow(startDate) { const start = new Date(startDate); const now = new Date(); return Math.ceil((now - start) / (1000 * 60 * 60)); } /** * 비정상 유형 라벨 가져오기 * @param {string} type - 비정상 유형 * @returns {string} 라벨 */ export function getTypeLabel(type) { return ABNORMAL_TYPE_LABELS[type] || type; } /** * 비정상 유형 설명 가져오기 * @param {string} type - 비정상 유형 * @returns {string} 설명 */ export function getTypeDescription(type) { return ABNORMAL_TYPE_DESCRIPTIONS[type] || '비정상 궤적'; } /** * 비정상 유형별 색상 가져오기 * @param {string} type - 비정상 유형 * @returns {Array} RGB 색상 배열 */ export function getColorByType(type) { return [...(ABNORMAL_TYPE_COLORS[type] || [128, 128, 128]), 200]; } /** * CSS 선택자용 ID 이스케이프 * @param {string} id - 이스케이프할 ID * @returns {string} 이스케이프된 ID */ export function escapeSelector(id) { return id.replace(/:/g, '-'); } /** * 조회 기간 레이블 생성 * @param {string} startDate - 시작 날짜 * @param {string} endDate - 종료 날짜 * @returns {string} 기간 레이블 */ export function getPeriodLabel(startDate, endDate) { if (!startDate || !endDate) return '전체'; const start = new Date(startDate); const end = new Date(endDate); const diffDays = Math.ceil((end - start) / (1000 * 60 * 60 * 24)) + 1; if (startDate === endDate) { return start.toLocaleDateString('ko-KR'); } else { return `${start.toLocaleDateString('ko-KR')} ~ ${end.toLocaleDateString('ko-KR')} (${diffDays}일간)`; } } /** * 숫자 포맷팅 * @param {number} number - 포맷할 숫자 * @param {number} decimals - 소수점 자리수 * @returns {string} 포맷된 숫자 */ export function formatNumber(number, decimals = 0) { if (number === null || number === undefined) return '-'; return Number(number).toFixed(decimals); } /** * 거리 포맷팅 * @param {number} distance - 거리 (nm) * @returns {string} 포맷된 거리 */ export function formatDistance(distance) { if (!distance) return '-'; return `${formatNumber(distance, 2)}nm`; } /** * 속도 포맷팅 * @param {number} speed - 속도 (knots) * @returns {string} 포맷된 속도 */ export function formatSpeed(speed) { if (!speed) return '-'; return `${formatNumber(speed, 1)}kts`; } /** * 날짜/시간 포맷팅 * @param {string|Date} date - 날짜 * @returns {string} 포맷된 날짜/시간 */ export function formatDateTime(date) { if (!date) return '-'; return new Date(date).toLocaleString('ko-KR'); } /** * 디바운스 함수 * @param {Function} func - 실행할 함수 * @param {number} wait - 대기 시간 (ms) * @returns {Function} 디바운스된 함수 */ export function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } /** * 쓰로틀 함수 * @param {Function} func - 실행할 함수 * @param {number} limit - 제한 시간 (ms) * @returns {Function} 쓰로틀된 함수 */ export function throttle(func, limit) { let inThrottle; return function(...args) { if (!inThrottle) { func.apply(this, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; } /** * 깊은 복사 * @param {*} obj - 복사할 객체 * @returns {*} 복사된 객체 */ export function deepClone(obj) { if (obj === null || typeof obj !== 'object') return obj; if (obj instanceof Date) return new Date(obj.getTime()); if (obj instanceof Array) return obj.map(item => deepClone(item)); if (obj instanceof Object) { const cloned = {}; for (const key in obj) { if (obj.hasOwnProperty(key)) { cloned[key] = deepClone(obj[key]); } } return cloned; } } /** * URL 쿼리 파라미터 파싱 * @param {string} url - URL * @returns {Object} 파라미터 객체 */ export function parseQueryParams(url = window.location.search) { const params = new URLSearchParams(url); const result = {}; for (const [key, value] of params) { result[key] = value; } return result; } /** * 객체를 쿼리 스트링으로 변환 * @param {Object} params - 파라미터 객체 * @returns {string} 쿼리 스트링 */ export function objectToQueryString(params) { return Object.keys(params) .filter(key => params[key] !== null && params[key] !== undefined) .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`) .join('&'); }