import type { EditorWorkKind } from "./model/editorTypes"; // Объём данных — общий форматтер (используется и в комплексном плане). export { formatVolume } from "../../utils/dataVolume"; export const EDITOR_MONTHS = ["янв", "фев", "мар", "апр", "май", "июн", "июл", "авг", "сен", "окт", "ноя", "дек"]; export const DEFAULT_EDITOR_MODES = [ { id: "pan", label: "Панхром." }, { id: "ms", label: "Мультиспектр." }, { id: "stereo", label: "Стерео" }, { id: "scan", label: "Скан" } ]; export function kindLabel(kind: EditorWorkKind): string { switch (kind) { case "shoot": return "Съёмка"; case "downlink": return "Сброс"; } } export function kindColor(kind: EditorWorkKind): string { return kind === "shoot" ? "var(--t-optical)" : "var(--accent)"; } export function formatTime(ms: number): string { const date = new Date(ms); return `${pad(date.getHours())}:${pad(date.getMinutes())}`; } /** * Подпись деления оси с учётом шага: при шаге меньше минуты показываем секунды * (ЧЧ:ММ:СС), иначе — ЧЧ:ММ. Так при сильном зуме видно более мелкий масштаб времени. */ export function formatTick(ms: number, stepMs: number): string { const date = new Date(ms); if (stepMs < 60_000) { return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`; } return `${pad(date.getHours())}:${pad(date.getMinutes())}`; } export function formatDate(ms: number): string { const date = new Date(ms); return `${pad(date.getDate())} ${EDITOR_MONTHS[date.getMonth()]}`; } export function formatDateTime(ms: number): string { return `${formatDate(ms)} ${formatTime(ms)}`; } /** Время с секундами и одной десятой долей: ЧЧ:ММ:СС.с (локальное). */ export function formatTimeSeconds(ms: number): string { const date = new Date(ms); const tenths = Math.floor((((ms % 1000) + 1000) % 1000) / 100); return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}.${tenths}`; } /** Дата и время с десятыми долями секунды: «дд мес ЧЧ:ММ:СС.с» (локальное). */ export function formatDateTimeSeconds(ms: number): string { return `${formatDate(ms)} ${formatTimeSeconds(ms)}`; } export function formatDuration(ms: number): string { const totalSeconds = Math.max(0, Math.round(ms / 1000)); if (totalSeconds < 60) { return `${totalSeconds} с`; } if (totalSeconds < 3600) { const minutes = Math.floor(totalSeconds / 60); const seconds = totalSeconds % 60; return seconds > 0 ? `${minutes} мин ${seconds} с` : `${minutes} мин`; } const hours = ms / 3_600_000; if (hours < 24) { return `${Number.isInteger(hours) ? hours : hours.toFixed(1)} ч`; } const days = Math.floor(hours / 24); const restHours = Math.round(hours - days * 24); return restHours > 0 ? `${days} сут ${restHours} ч` : `${days} сут`; } /** Деления оси времени: {@link ticks} — отметки, {@link step} — выбранный шаг (мс). */ export type TimelineTicks = { ticks: number[]; step: number }; export function niceTicks(fromMs: number, toMs: number, pxPerMs: number, minPx: number): TimelineTicks { const minuteMs = 60_000; const hourMs = 3_600_000; const dayMs = 24 * hourMs; // От секунд до недели — чем сильнее зум, тем мельче шаг, который влезает по minPx. const steps = [ 1_000, 2_000, 5_000, 10_000, 15_000, 30_000, minuteMs, 2 * minuteMs, 5 * minuteMs, 10 * minuteMs, 15 * minuteMs, 30 * minuteMs, hourMs, 2 * hourMs, 3 * hourMs, 6 * hourMs, 12 * hourMs, dayMs, 2 * dayMs, 7 * dayMs ]; const step = steps.find((item) => item * pxPerMs >= minPx) ?? steps[steps.length - 1]; const ticks: number[] = []; const firstTick = Math.ceil(fromMs / step) * step; for (let timeMs = firstTick; timeMs <= toMs; timeMs += step) { ticks.push(timeMs); } return { ticks, step }; } function pad(value: number): string { return String(value).padStart(2, "0"); }