Корректировка ошибок. Стили, прокрутка, шрифты

This commit is contained in:
Maxim
2026-06-22 10:41:29 +03:00
parent 5d15f215be
commit 827210d29a
8 changed files with 318 additions and 94 deletions

View File

@@ -19,13 +19,13 @@ import {
setBars,
setSignal,
setAudioIndicator,
DOM
DOM,
updateAllChannels
} from "./ui.js";
import { initAccordion } from "./accordion.js";
import { drawChart } from "./chart.js";
import { initResize } from "./layout.js";
import { initCamera } from "./camera.js";
import { updateAllChannels } from './ui.js';
import { audioEngine } from "./audio.js";
let lastChart: number = 0;
@@ -56,24 +56,20 @@ window.addEventListener("DOMContentLoaded", () => {
if (signalLevel !== lastSignalLevel) {
lastSignalLevel = signalLevel;
audioEngine.updateLevel(signalLevel);
// Обновляем индикатор звука
const isActive = signalLevel > 0;
setAudioIndicator(isActive, signalLevel);
setAudioIndicator(signalLevel > 0, signalLevel);
}
}
});
});
document.addEventListener('DOMContentLoaded', () => {
// Обработчик для кнопки закрытия камеры
const closeBtn = document.getElementById('camCloseBtn');
const toggleBtn = document.getElementById('camToggle');
if (closeBtn) {
closeBtn.addEventListener('click', () => {
if (toggleBtn) {
toggleBtn.click(); // Эмулируем нажатие кнопки переключения
toggleBtn.click();
}
});
}
@@ -104,17 +100,13 @@ document.addEventListener("keydown", (e: KeyboardEvent) => {
}
break;
case 'm':
// Toggle звука
if (lastSignalLevel > 0) {
// Временно отключаем
audioEngine.updateLevel(0);
setAudioIndicator(false);
console.log('[Audio] Звук отключён (M)');
// Сохраняем уровень для восстановления
window._mutedLevel = lastSignalLevel;
lastSignalLevel = 0;
} else {
// Восстанавливаем уровень
const level = window._mutedLevel || state.peakSignalLevel;
if (level > 0) {
audioEngine.updateLevel(level);
@@ -164,23 +156,33 @@ async function update(): Promise<void> {
const arr = Array.isArray(history.bytes) ? history.bytes : [];
const raw = arr[arr.length - 1] ?? 0;
// Обновляем историю сигналов в state
if (arr.length > 0 && isOnline) {
const bufferSize = health.stats?.filled ?? 0;
addSignals(arr, bufferSize);
updateAllChannels(arr);
}
const value = raw & 0x3F;
const level = (raw >> 6) & 0x3;
const percent = (value / 63) * 100;
// ===== ПАРСИНГ ДАННЫХ =====
// Биты 0-5: значение (0-63)
// Биты 6-7: уровень сигнала (0-3)
const value = raw & 0x3F; // 0-63
const level = (raw >> 6) & 0x3; // 0-3
const percent = (value / 63) * 100; // 0-100%
// ===== ОБНОВЛЯЕМ КАНАЛЫ =====
// Передаем сырые данные для отображения в каналах
updateAllChannels(arr);
if (isOnline) {
// ===== Обновляем Peak Holder (проценты) ====
const displayValue = updatePeakHolder(percent);
setBars(displayValue);
// Обновляем уровень сигнала с Peak Holder
const displaySignalLevel = updateSignalPeakHolder(level);
setSignal(displaySignalLevel);
// Обновляем звук
const currentSignalLevel = state.peakSignalLevel;
if (currentSignalLevel !== lastSignalLevel) {
lastSignalLevel = currentSignalLevel;
@@ -239,8 +241,6 @@ async function update(): Promise<void> {
if (consecutiveErrors >= MAX_ERRORS && pollTimer) {
clearInterval(pollTimer);
pollTimer = window.setInterval(update, 2000);
console.log("[app] Замедлили опрос до 2с");
}
}
}
@@ -253,7 +253,6 @@ function startPolling(): void {
window.addEventListener("focus", () => {
if (consecutiveErrors >= MAX_ERRORS) {
console.log("[app] Окно в фокусе, ускоряем опрос");
consecutiveErrors = 0;
startPolling();
}
@@ -270,4 +269,4 @@ declare global {
}
startPolling();
update();
update();

View File

@@ -237,7 +237,6 @@ function scheduleSignalPeakRelease(): void {
state.peakSignalLevel = state.currentSignalLevel;
state.signalPeakTimer = null;
state.hasPeak = false;
console.log(`[SignalPeak] Сброс пика до: ${state.peakSignalLevel}`);
notifyPeakHolderChange();
}, state.signalPeakHoldTime);
}

View File

@@ -1,4 +1,6 @@
// ui.ts (DOM слой)
// ui.ts - ИСПРАВЛЕННАЯ ВЕРСИЯ
// Канал 1 - реальные данные, каналы 2-8 - неактивны
export interface DOMElements {
serverTime: HTMLElement | null;
status: HTMLElement | null;
@@ -81,6 +83,7 @@ export function setMeta(v: string): void {
if (DOM.meta) DOM.meta.textContent = v;
}
// ===== ОСНОВНОЙ ПРОГРЕСС-БАР =====
export function setBars(p: number, noConnection: boolean = false): void {
const el = DOM.barFill;
if (!el) return;
@@ -90,10 +93,16 @@ export function setBars(p: number, noConnection: boolean = false): void {
el.classList.add("no-connection");
} else {
el.classList.remove("no-connection");
el.style.width = `${Math.max(0, Math.min(100, p))}%`;
const percent = Math.max(0, Math.min(100, p));
el.style.width = `${percent}%`;
// Принудительно устанавливаем рыжий цвет
el.style.background = '#e6852d';
el.style.backgroundColor = '#e6852d';
el.style.backgroundImage = 'none';
}
}
// ===== ИНДИКАТОРЫ УРОВНЯ СИГНАЛА =====
export function setSignal(level: number, noConnection: boolean = false): void {
const bars = DOM.bars;
if (!bars || bars.length < 3) return;
@@ -187,6 +196,11 @@ export function initChannels() {
item.className = 'channel-item';
item.dataset.channel = String(i);
// Только канал 1 активен по умолчанию
if (i === 0) {
item.classList.add('channel-active');
}
item.innerHTML = `
<div class="channel-header" data-channel="${i}">
<span class="channel-label">Канал ${i + 1}</span>
@@ -198,7 +212,7 @@ export function initChannels() {
<div class="channel-body" id="ch-body-${i}">
<div class="channel-progress">
<div class="progress">
<div class="fill" id="ch-bar-${i}" style="width:0%"></div>
<div class="fill" id="ch-bar-${i}" style="width:0%; background: #e6852d;"></div>
</div>
<div class="signal-icon" id="ch-signal-${i}">
<div class="sig-bar sig-bar-1"></div>
@@ -250,14 +264,28 @@ export function setChannelValue(index: number, value: number, strength: number)
const ch = channels[index];
const el = channelElements[index];
if (!el) return;
if (!el) {
console.warn(`[UI] Channel ${index} element not found`);
return;
}
ch.value = value;
ch.strength = strength;
const percent = (value / 31) * 100;
el.bar.style.width = `${percent}%`;
el.value.textContent = value.toString();
const maxValue = 63;
const percent = (value / maxValue) * 100;
// Принудительно устанавливаем стили для прогресс-бара
if (el.bar) {
el.bar.style.width = `${Math.min(100, percent)}%`;
el.bar.style.background = '#e6852d';
el.bar.style.backgroundColor = '#e6852d';
el.bar.style.backgroundImage = 'none';
}
if (el.value) {
el.value.textContent = value.toString();
}
const bars = el.signal?.querySelectorAll('.sig-bar');
if (bars) {
@@ -268,22 +296,67 @@ export function setChannelValue(index: number, value: number, strength: number)
}
const strengthNames = ['Отсутствует', 'Низкая', 'Средняя', 'Высокая'];
el.stats.textContent = `${value}/31 | ${strengthNames[strength] || '---'}`;
el.item.classList.remove('no-data');
}
export function updateAllChannels(rawData: number[]) {
const latest = new Map<number, number>();
for (const byte of rawData) {
const channel = (byte >> 5) & 0x07;
const value = byte & 0x1F;
latest.set(channel, value);
if (el.stats) {
el.stats.textContent = `${value}/${maxValue} | ${strengthNames[strength] || '---'}`;
}
if (el.item) {
el.item.classList.remove('no-data');
}
}
/**
* ОБНОВЛЕНИЕ ВСЕХ КАНАЛОВ
* Канал 1 - реальные данные из эмулятора
* Каналы 2-8 - неактивны (0)
*/
export function updateAllChannels(rawData?: number[]) {
// Сначала сбрасываем все каналы в 0
for (let i = 0; i < 8; i++) {
const value = latest.get(i) ?? 0;
const strength = value >= 25 ? 3 : value >= 15 ? 2 : value >= 5 ? 1 : 0;
setChannelValue(i, value, strength);
setChannelValue(i, 0, 0);
if (channelElements[i]) {
channelElements[i].item.classList.remove('channel-active');
}
}
// Если есть данные - обновляем КАНАЛ 1
if (rawData && rawData.length > 0) {
// Берем последний байт (самый свежий)
const lastByte = rawData[rawData.length - 1];
// ПРАВИЛЬНЫЙ ПАРСИНГ:
// Биты 0-5: значение (количество сигналов) 0-63
// Биты 6-7: уровень сигнала (амплитуда/сила) 0-3
const value = lastByte & 0x3F; // маска 0b00111111 → 0-63
const strength = (lastByte >> 6) & 0x3; // маска 0b00000011 → 0-3
// Обновляем КАНАЛ 1 с реальными данными
setChannelValue(0, value, strength);
if (channelElements[0]) {
channelElements[0].item.classList.add('channel-active');
}
// Обновляем last-byte
if (DOM.lastByte) {
DOM.lastByte.textContent = value.toString();
}
// Обновляем основной прогресс-бар (для синхронизации)
const percent = (value / 63) * 100;
if (DOM.barFill) {
DOM.barFill.style.width = `${percent}%`;
DOM.barFill.style.background = '#e6852d';
DOM.barFill.style.backgroundColor = '#e6852d';
DOM.barFill.style.backgroundImage = 'none';
}
} else {
// Если данных нет - канал 1 тоже неактивен
if (DOM.lastByte) {
DOM.lastByte.textContent = '--';
}
if (DOM.barFill) {
DOM.barFill.style.width = '0%';
}
}
}
@@ -291,6 +364,9 @@ export function updateAllChannels(rawData: number[]) {
document.addEventListener('DOMContentLoaded', () => {
initChannels();
// Принудительно обновляем каналы при загрузке
updateAllChannels();
const expandAll = document.getElementById('expandAllBtn');
const collapseAll = document.getElementById('collapseAllBtn');