diff --git a/cmd/server/web/js/app.ts b/cmd/server/web/js/app.ts index cc8b9b1..d43e9b8 100644 --- a/cmd/server/web/js/app.ts +++ b/cmd/server/web/js/app.ts @@ -9,7 +9,7 @@ import { resetBufferTracking, updatePeakHolder, updateSignalPeakHolder, - forceResetPeak + setPeakHolderListener } from "./state.js"; import { initDOM, @@ -36,6 +36,13 @@ window.addEventListener("DOMContentLoaded", () => { initAccordion(); initResize(); initCamera(); + + setPeakHolderListener(() => { + if (!connectionLost) { + setBars(state.peakValue); + setSignal(state.peakSignalLevel); + } + }); }); document.addEventListener("keydown", (e: KeyboardEvent) => { diff --git a/cmd/server/web/js/state.ts b/cmd/server/web/js/state.ts index ef5da20..e95017d 100644 --- a/cmd/server/web/js/state.ts +++ b/cmd/server/web/js/state.ts @@ -11,12 +11,17 @@ interface AppState { peakTimer: number | null; // Таймер для сброса пика амплитуды peakHoldTime: number; // Время удержания пика в миллисекундах - peakSignalLevel: number; // Текущий удерживаемый пиковый уровень сигнала (0-3) - currentSignalLevel: number; // Текущий реальный уровень сигнала - signalPeakTimer: number | null; // Таймер для сброса пика сигнала - signalPeakHoldTime: number; // Время удержания пика сигнала + // Peak Holder для уровня сигнала + peakSignalLevel: number; + currentSignalLevel: number; + signalPeakTimer: number | null; + signalPeakHoldTime: number; + + hasPeak: boolean; } +type PeakHolderListener = () => void; + export const state: AppState = { maxPoints: 1000, signalHistory: [], @@ -30,9 +35,59 @@ export const state: AppState = { peakSignalLevel: 0, currentSignalLevel: 0, signalPeakTimer: null, - signalPeakHoldTime: 3000, // 3 секунды + signalPeakHoldTime: 3000, + + hasPeak: false, }; +let peakHolderListener: PeakHolderListener | null = null; + +/** Обновление UI при сбросе peak holder по таймеру (между опросами API). */ +export function setPeakHolderListener(listener: PeakHolderListener | null): void { + peakHolderListener = listener; +} + +function notifyPeakHolderChange(): void { + if (peakHolderListener) { + peakHolderListener(); + } +} + +function scheduleAmplitudePeakRelease(): void { + // Сбрасываем старый таймер + if (state.peakTimer !== null) { + clearTimeout(state.peakTimer); + state.peakTimer = null; + } + + // Запускаем новый таймер на 3 секунды + state.peakTimer = window.setTimeout(() => { + state.peakValue = state.currentValue; + state.peakTimer = null; + state.hasPeak = false; + console.log(`[Peak] Сброс пика до: ${state.peakValue}`); + notifyPeakHolderChange(); + }, state.peakHoldTime); +} + +function scheduleSignalPeakRelease(): void { + // Сбрасываем старый таймер + if (state.signalPeakTimer !== null) { + clearTimeout(state.signalPeakTimer); + state.signalPeakTimer = null; + } + + // Запускаем новый таймер на 3 секунды + state.signalPeakTimer = window.setTimeout(() => { + // Сбрасываем пик к текущему уровню + state.peakSignalLevel = state.currentSignalLevel; + state.signalPeakTimer = null; + state.hasPeak = false; + console.log(`[SignalPeak] Сброс пика до: ${state.peakSignalLevel}`); + notifyPeakHolderChange(); + }, state.signalPeakHoldTime); +} + // ========== ФУНКЦИИ ДЛЯ АМПЛИТУДЫ ========== export function updatePeakHolder(target: number): number { @@ -43,127 +98,52 @@ export function updatePeakHolder(target: number): number { if (target > state.peakValue) { // Устанавливаем новый пик state.peakValue = target; - - // Сбрасываем и перезапускаем таймер - resetPeakTimer(); - startPeakTimer(); + state.hasPeak = true; + scheduleAmplitudePeakRelease(); + } else if (target < state.peakValue && state.peakTimer === null) { + // Пик выше текущего значения, но таймер пропал — перезапускаем удержание + scheduleAmplitudePeakRelease(); } - // Возвращаем текущий пик для отображения + // Возвращаем текущий пик return state.peakValue; } -/** - * Запуск таймера сброса пика - */ -function startPeakTimer(): void { - if (state.peakTimer !== null) { - clearTimeout(state.peakTimer); - } +// ========== ФУНКЦИИ ДЛЯ УРОВНЯ СИГНАЛА ========== - state.peakTimer = window.setTimeout(() => { - resetPeak(); - }, state.peakHoldTime); -} - -/** - * Сброс таймера пика - */ -function resetPeakTimer(): void { - if (state.peakTimer !== null) { - clearTimeout(state.peakTimer); - state.peakTimer = null; - } -} - -/** - * Сброс пикового значения до текущего уровня - */ -function resetPeak(): void { - state.peakValue = state.currentValue; - state.peakTimer = null; -} - -/** - * Обновление пикового уровня сигнала (peak holder для strength) - * @param level - новый уровень сигнала (0-3) - * @returns пиковый уровень для отображения - */ export function updateSignalPeakHolder(level: number): number { // Обновляем текущее значение state.currentSignalLevel = level; - // Если новый уровень выше текущего пика + // Если новый уровень больше пика — устанавливаем новый пик if (level > state.peakSignalLevel) { - // Устанавливаем новый пик state.peakSignalLevel = level; - - // Сбрасываем и перезапускаем таймер - resetSignalPeakTimer(); - startSignalPeakTimer(); - - // Опционально: лог для отладки - // console.log(`[SignalPeak] Новый пик сигнала: ${state.peakSignalLevel}`); + state.hasPeak = true; + scheduleSignalPeakRelease(); + } else if (level < state.peakSignalLevel && state.signalPeakTimer === null) { + scheduleSignalPeakRelease(); } - // Возвращаем текущий пик для отображения + // Возвращаем текущий пик return state.peakSignalLevel; } -/** - * Запуск таймера сброса пика сигнала - */ -function startSignalPeakTimer(): void { - if (state.signalPeakTimer !== null) { - clearTimeout(state.signalPeakTimer); - } +// ========== ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ========== - state.signalPeakTimer = window.setTimeout(() => { - resetSignalPeak(); - }, state.signalPeakHoldTime); -} - -/** - * Сброс таймера пика сигнала - */ -function resetSignalPeakTimer(): void { +export function forceResetSignalPeak(): void { if (state.signalPeakTimer !== null) { clearTimeout(state.signalPeakTimer); state.signalPeakTimer = null; } -} - -/** - * Сброс пикового уровня сигнала до текущего уровня - */ -function resetSignalPeak(): void { - state.peakSignalLevel = state.currentSignalLevel; - state.signalPeakTimer = null; - - // Опционально: лог для отладки - // console.log(`[SignalPeak] Сброс пика сигнала до: ${state.peakSignalLevel}`); -} - -/** - * Принудительный сброс пика сигнала (например, при потере связи) - */ -export function forceResetSignalPeak(): void { - resetSignalPeakTimer(); state.peakSignalLevel = 0; state.currentSignalLevel = 0; + state.hasPeak = false; } -/** - * Обновление времени удержания пика сигнала - * @param ms - время в миллисекундах - */ export function setSignalPeakHoldTime(ms: number): void { state.signalPeakHoldTime = ms; } -/** - * Получение текущего состояния пика сигнала (для отладки) - */ export function getSignalPeakInfo(): { peak: number; current: number; timerActive: boolean } { return { peak: state.peakSignalLevel, @@ -172,13 +152,14 @@ export function getSignalPeakInfo(): { peak: number; current: number; timerActiv }; } -// ========== ОБНОВЛЕННЫЕ ФУНКЦИИ ДЛЯ СБРОСА ========== - export function forceResetPeak(): void { - resetPeakTimer(); + if (state.peakTimer !== null) { + clearTimeout(state.peakTimer); + state.peakTimer = null; + } state.peakValue = 0; state.currentValue = 0; - + state.hasPeak = false; forceResetSignalPeak(); } @@ -209,5 +190,5 @@ export function addSignals(values: number[], bufferSize: number): void { export function resetBufferTracking(): void { state.lastBufferSize = 0; - forceResetPeak(); // Сбрасываем оба пика -} \ No newline at end of file + forceResetPeak(); +}