Корректировка ошибок. Стили, прокрутка, шрифты
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user