Рефактор
This commit is contained in:
18
cmd/server/web/dist/accordion.js
vendored
18
cmd/server/web/dist/accordion.js
vendored
@@ -1,18 +0,0 @@
|
||||
// accordion.ts
|
||||
import { DOM } from "./ui.js";
|
||||
export function initAccordion() {
|
||||
if (!DOM.historyHeader || !DOM.historyBody)
|
||||
return;
|
||||
let open = false;
|
||||
DOM.historyBody.classList.add("collapsed");
|
||||
DOM.historyHeader.textContent = "▶ ПРИНЯТЫЕ ДАННЫЕ";
|
||||
DOM.historyHeader.addEventListener("click", () => {
|
||||
open = !open;
|
||||
if (DOM.historyHeader) {
|
||||
DOM.historyHeader.textContent = (open ? "▼" : "▶") + " ПРИНЯТЫЕ ДАННЫЕ";
|
||||
}
|
||||
if (DOM.historyBody) {
|
||||
DOM.historyBody.classList.toggle("collapsed", !open);
|
||||
}
|
||||
});
|
||||
}
|
||||
138
cmd/server/web/dist/app.js
vendored
138
cmd/server/web/dist/app.js
vendored
@@ -1,138 +0,0 @@
|
||||
// app.js (оркестратор)
|
||||
import { fetchHealth, fetchHistory } from "./data.js";
|
||||
import { state, smooth, addSignals, resetBufferTracking } from "./state.js";
|
||||
import { initDOM, setStatus, setMeta, setBars, setSignal, DOM } from "./ui.js";
|
||||
import { initAccordion } from "./accordion.js";
|
||||
import { drawChart } from "./chart.js";
|
||||
import { initResize } from "./layout.js";
|
||||
import { initCamera } from "./camera.js";
|
||||
let lastChart = 0;
|
||||
let connectionLost = false;
|
||||
let consecutiveErrors = 0;
|
||||
const MAX_ERRORS = 3;
|
||||
let pollTimer = null;
|
||||
// ================= INIT =================
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
initDOM();
|
||||
initAccordion();
|
||||
initResize();
|
||||
initCamera();
|
||||
});
|
||||
document.addEventListener("keydown", (e) => {
|
||||
const leftPanel = document.getElementById("leftPanel");
|
||||
const rightPanel = document.getElementById("rightPanel");
|
||||
switch (e.key.toLowerCase()) {
|
||||
case 'c':
|
||||
const camBtn = document.getElementById('camToggle');
|
||||
if (camBtn)
|
||||
camBtn.click();
|
||||
break;
|
||||
case 'f':
|
||||
if (leftPanel) {
|
||||
leftPanel.style.width = "100%";
|
||||
if (rightPanel)
|
||||
rightPanel.style.display = "none";
|
||||
}
|
||||
break;
|
||||
case 'escape':
|
||||
if (rightPanel)
|
||||
rightPanel.style.display = "flex";
|
||||
if (leftPanel && rightPanel) {
|
||||
const total = window.innerWidth;
|
||||
const leftWidth = total * 0.6;
|
||||
leftPanel.style.flex = `0 0 ${leftWidth}px`;
|
||||
rightPanel.style.flex = `0 0 ${total - leftWidth}px`;
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
// ================= UPDATE =================
|
||||
async function update() {
|
||||
try {
|
||||
const [health, history] = await Promise.all([
|
||||
fetchHealth(),
|
||||
fetchHistory()
|
||||
]);
|
||||
consecutiveErrors = 0;
|
||||
if (connectionLost) {
|
||||
console.log("[app] Соединение восстановлено");
|
||||
}
|
||||
const isOnline = health.pipe_alive && health.has_data;
|
||||
if (isOnline) {
|
||||
setStatus("На связи");
|
||||
connectionLost = false;
|
||||
}
|
||||
else {
|
||||
setStatus("Нет связи", true);
|
||||
if (!connectionLost)
|
||||
resetBufferTracking();
|
||||
connectionLost = true;
|
||||
}
|
||||
const arr = Array.isArray(history.bytes) ? history.bytes : [];
|
||||
const raw = arr[arr.length - 1] ?? 0;
|
||||
if (arr.length > 0 && isOnline) {
|
||||
const bufferSize = health.stats?.filled ?? 0;
|
||||
addSignals(arr, bufferSize);
|
||||
}
|
||||
const value = raw & 0x3F;
|
||||
const level = (raw >> 6) & 0x3;
|
||||
const percent = (value / 63) * 100;
|
||||
if (isOnline) {
|
||||
setBars(smooth(percent));
|
||||
setSignal(level);
|
||||
}
|
||||
else {
|
||||
setBars(0, true);
|
||||
setSignal(0, true);
|
||||
}
|
||||
if (DOM.lastByte) {
|
||||
DOM.lastByte.textContent = isOnline ? value.toString() : "--";
|
||||
}
|
||||
const uptime = Math.round(health.uptime_sec || 0);
|
||||
const filled = health.stats?.filled ?? 0;
|
||||
const Bps = Math.round(health.stats?.bytes_per_sec ?? 0);
|
||||
setMeta(`Работа: ${uptime}s | Буфер: ${filled} | Приём: ${Bps} B/s`);
|
||||
if (DOM.history) {
|
||||
DOM.history.innerHTML = arr
|
||||
.map((b, i) => `[${i}] ${(b & 0xFF).toString(2).padStart(8, "0")} = ${b & 0xFF}`)
|
||||
.join("<br>");
|
||||
}
|
||||
const now = performance.now();
|
||||
if (now - lastChart > 100 && DOM.canvas) {
|
||||
drawChart(DOM.canvas, state.signalHistory);
|
||||
lastChart = now;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
consecutiveErrors++;
|
||||
if (consecutiveErrors === 1)
|
||||
console.warn("[app] Сервер недоступен, ждём...");
|
||||
setStatus("СЕРВЕР НЕДОСТУПЕН", true);
|
||||
setBars(0, true);
|
||||
setSignal(0, true);
|
||||
resetBufferTracking();
|
||||
if (DOM.lastByte)
|
||||
DOM.lastByte.textContent = "--";
|
||||
if (consecutiveErrors >= MAX_ERRORS && pollTimer) {
|
||||
clearInterval(pollTimer);
|
||||
pollTimer = window.setInterval(update, 2000);
|
||||
console.log("[app] Замедлили опрос до 2с");
|
||||
}
|
||||
}
|
||||
}
|
||||
function startPolling() {
|
||||
if (pollTimer)
|
||||
clearInterval(pollTimer);
|
||||
if (consecutiveErrors > 0)
|
||||
update();
|
||||
pollTimer = window.setInterval(update, 500);
|
||||
}
|
||||
window.addEventListener("focus", () => {
|
||||
if (consecutiveErrors >= MAX_ERRORS) {
|
||||
console.log("[app] Окно в фокусе, ускоряем опрос");
|
||||
consecutiveErrors = 0;
|
||||
startPolling();
|
||||
}
|
||||
});
|
||||
startPolling();
|
||||
update();
|
||||
148
cmd/server/web/dist/camera.js
vendored
148
cmd/server/web/dist/camera.js
vendored
@@ -1,148 +0,0 @@
|
||||
// camera.ts
|
||||
import { updateResizerVisibility } from './layout.js';
|
||||
let rightPanel = null;
|
||||
let camImage = null;
|
||||
let crosshair = null;
|
||||
let isOpen = false;
|
||||
let streamCheckInterval = null;
|
||||
export function initCamera() {
|
||||
rightPanel = document.getElementById("rightPanel");
|
||||
camImage = document.getElementById("camImage");
|
||||
crosshair = document.getElementById("crosshair");
|
||||
// Проверяем доступность потока
|
||||
checkStreamAvailability();
|
||||
const btn = document.getElementById("camToggle");
|
||||
const streamUrl = "/api/cam";
|
||||
function open() {
|
||||
if (isOpen)
|
||||
return;
|
||||
isOpen = true;
|
||||
if (rightPanel) {
|
||||
rightPanel.classList.remove("hidden");
|
||||
}
|
||||
// Показываем перекрестие
|
||||
if (crosshair) {
|
||||
crosshair.style.display = "block";
|
||||
}
|
||||
if (camImage) {
|
||||
camImage.src = streamUrl;
|
||||
}
|
||||
if (btn) {
|
||||
const textSpan = btn.querySelector('.cam-btn-text');
|
||||
if (textSpan)
|
||||
textSpan.textContent = 'Скрыть';
|
||||
}
|
||||
console.log("[camera] opened");
|
||||
updateResizerVisibility();
|
||||
// Запускаем мониторинг потока
|
||||
startStreamMonitoring();
|
||||
}
|
||||
function close() {
|
||||
if (!isOpen)
|
||||
return;
|
||||
isOpen = false;
|
||||
// Скрываем перекрестие
|
||||
if (crosshair) {
|
||||
crosshair.style.display = "none";
|
||||
}
|
||||
// остановка stream
|
||||
if (camImage) {
|
||||
camImage.src = "";
|
||||
}
|
||||
if (rightPanel) {
|
||||
rightPanel.classList.add("hidden");
|
||||
}
|
||||
if (btn) {
|
||||
const textSpan = btn.querySelector('.cam-btn-text');
|
||||
if (textSpan)
|
||||
textSpan.textContent = 'Камера';
|
||||
}
|
||||
console.log("[camera] closed");
|
||||
updateResizerVisibility();
|
||||
// Останавливаем мониторинг
|
||||
stopStreamMonitoring();
|
||||
}
|
||||
function toggle() {
|
||||
if (isOpen) {
|
||||
close();
|
||||
}
|
||||
else {
|
||||
open();
|
||||
}
|
||||
}
|
||||
if (camImage) {
|
||||
camImage.onload = () => {
|
||||
console.log("[camera] stream started");
|
||||
if (crosshair) {
|
||||
crosshair.style.opacity = '1';
|
||||
}
|
||||
};
|
||||
camImage.onerror = (e) => {
|
||||
console.error("[camera] stream error", e);
|
||||
if (crosshair) {
|
||||
crosshair.style.opacity = '0.3';
|
||||
}
|
||||
};
|
||||
}
|
||||
btn?.addEventListener("click", toggle);
|
||||
// Проверка доступности камеры
|
||||
async function checkStreamAvailability() {
|
||||
try {
|
||||
const response = await fetch('/api/stream');
|
||||
const data = await response.json();
|
||||
if (data.available && data.cam) {
|
||||
console.log("[camera] stream available:", data.source);
|
||||
// Автозапуск если камера доступна
|
||||
if (!isOpen) {
|
||||
open();
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log("[camera] stream not available");
|
||||
if (crosshair) {
|
||||
crosshair.style.display = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log("[camera] check failed:", error);
|
||||
}
|
||||
}
|
||||
// Мониторинг состояния потока
|
||||
function startStreamMonitoring() {
|
||||
stopStreamMonitoring();
|
||||
streamCheckInterval = window.setInterval(() => {
|
||||
if (isOpen && camImage) {
|
||||
if (!camImage.complete || camImage.naturalWidth === 0) {
|
||||
if (crosshair) {
|
||||
crosshair.style.opacity = '0.3';
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (crosshair) {
|
||||
crosshair.style.opacity = '1';
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
function stopStreamMonitoring() {
|
||||
if (streamCheckInterval) {
|
||||
clearInterval(streamCheckInterval);
|
||||
streamCheckInterval = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Экспортируем для возможности ручного управления
|
||||
export function showCrosshair(show = true) {
|
||||
const crosshairElem = document.getElementById("crosshair");
|
||||
if (crosshairElem) {
|
||||
crosshairElem.style.display = show ? "block" : "none";
|
||||
}
|
||||
}
|
||||
export function setCrosshairOpacity(opacity) {
|
||||
const crosshairElem = document.getElementById("crosshair");
|
||||
if (crosshairElem) {
|
||||
crosshairElem.style.opacity = String(opacity);
|
||||
}
|
||||
}
|
||||
114
cmd/server/web/dist/chart.js
vendored
114
cmd/server/web/dist/chart.js
vendored
@@ -1,114 +0,0 @@
|
||||
// chart.js
|
||||
export function drawChart(canvas, history) {
|
||||
if (!canvas || !history?.length)
|
||||
return;
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const displayHeight = rect.height || 200;
|
||||
const displayWidth = rect.width || 800;
|
||||
canvas.width = displayWidth;
|
||||
canvas.height = displayHeight;
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx)
|
||||
return;
|
||||
const w = canvas.width;
|
||||
const h = canvas.height;
|
||||
const padLeft = 45;
|
||||
const padRight = 15;
|
||||
const padTop = 10;
|
||||
const padBottom = 25;
|
||||
const plotW = w - padLeft - padRight;
|
||||
const plotH = h - padTop - padBottom;
|
||||
// Фон
|
||||
ctx.fillStyle = "#0a0f0a";
|
||||
ctx.fillRect(0, 0, w, h);
|
||||
// Сетка
|
||||
const maxVal = 63;
|
||||
const gridLines = 4;
|
||||
ctx.strokeStyle = "#0d2a0d";
|
||||
ctx.lineWidth = 0.5;
|
||||
ctx.setLineDash([4, 4]);
|
||||
for (let i = 0; i <= gridLines; i++) {
|
||||
const val = (maxVal / gridLines) * i;
|
||||
const y = padTop + plotH - (val / maxVal) * plotH;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(padLeft, y);
|
||||
ctx.lineTo(w - padRight, y);
|
||||
ctx.stroke();
|
||||
ctx.fillStyle = "#00ff88";
|
||||
ctx.font = "11px monospace";
|
||||
ctx.textAlign = "right";
|
||||
ctx.fillText(Math.round(val).toString(), padLeft - 8, y + 4);
|
||||
}
|
||||
ctx.setLineDash([]);
|
||||
// Подписи осей
|
||||
ctx.fillStyle = "#00ff88";
|
||||
ctx.font = "bold 11px monospace";
|
||||
ctx.save();
|
||||
ctx.translate(12, padTop + plotH / 2);
|
||||
ctx.rotate(-Math.PI / 2);
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText("ЗНАЧЕНИЕ", 0, 0);
|
||||
ctx.restore();
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText("БУФЕР ПРИНЯТЫХ ДАННЫХ", padLeft + plotW / 2, h - 4);
|
||||
const hasSignal = history.some(v => v > 0);
|
||||
if (!hasSignal) {
|
||||
ctx.fillStyle = "#ff4444";
|
||||
ctx.font = "14px monospace";
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText("Ожидание сигнала...", w / 2, h / 2);
|
||||
return;
|
||||
}
|
||||
let plotData = history;
|
||||
if (history.length > plotW) {
|
||||
const step = history.length / plotW;
|
||||
plotData = [];
|
||||
for (let i = 0; i < plotW; i++) {
|
||||
const idx = Math.floor(i * step);
|
||||
plotData.push(history[idx]);
|
||||
}
|
||||
}
|
||||
ctx.strokeStyle = "#e6852d";
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.shadowColor = "#e6852d";
|
||||
ctx.shadowBlur = 3;
|
||||
ctx.beginPath();
|
||||
const stepX = plotW / Math.max(plotData.length - 1, 1);
|
||||
for (let i = 0; i < plotData.length; i++) {
|
||||
const x = padLeft + i * stepX;
|
||||
const y = padTop + plotH - (plotData[i] / maxVal) * plotH;
|
||||
if (i === 0)
|
||||
ctx.moveTo(x, y);
|
||||
else
|
||||
ctx.lineTo(x, y);
|
||||
}
|
||||
ctx.stroke();
|
||||
ctx.shadowBlur = 0;
|
||||
if (history.length > 0) {
|
||||
const lastVal = history[history.length - 1];
|
||||
const lastX = padLeft + (plotData.length - 1) * stepX;
|
||||
const lastY = padTop + plotH - (lastVal / maxVal) * plotH;
|
||||
ctx.fillStyle = "#c46b1f";
|
||||
ctx.beginPath();
|
||||
ctx.arc(lastX, lastY, 4, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
const labelText = `${lastVal}`;
|
||||
const labelWidth = ctx.measureText(labelText).width;
|
||||
ctx.fillStyle = "rgba(0,0,0,0.8)";
|
||||
ctx.fillRect(lastX - labelWidth / 2 - 4, lastY - 22, labelWidth + 8, 18);
|
||||
ctx.fillStyle = "#00ff88";
|
||||
ctx.font = "bold 12px monospace";
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText(labelText, lastX, lastY - 8);
|
||||
const peak = Math.max(...history);
|
||||
const min = Math.min(...history);
|
||||
ctx.fillStyle = "rgba(0,0,0,0.7)";
|
||||
ctx.fillRect(w - 120, padTop, 110, 42);
|
||||
ctx.fillStyle = "#00ff88";
|
||||
ctx.font = "10px monospace";
|
||||
ctx.textAlign = "left";
|
||||
ctx.fillText(`Пик: ${peak}`, w - 110, padTop + 14);
|
||||
ctx.fillText(`Мин: ${min}`, w - 110, padTop + 28);
|
||||
ctx.fillText(`Точек: ${history.length}`, w - 110, padTop + 42);
|
||||
}
|
||||
}
|
||||
12
cmd/server/web/dist/data.js
vendored
12
cmd/server/web/dist/data.js
vendored
@@ -1,12 +0,0 @@
|
||||
export async function fetchHealth() {
|
||||
const r = await fetch("/api/health");
|
||||
if (!r.ok)
|
||||
throw new Error(`HTTP ${r.status}`);
|
||||
return r.json();
|
||||
}
|
||||
export async function fetchHistory() {
|
||||
const r = await fetch("/api/history");
|
||||
if (!r.ok)
|
||||
throw new Error(`HTTP ${r.status}`);
|
||||
return r.json();
|
||||
}
|
||||
79
cmd/server/web/dist/layout.js
vendored
79
cmd/server/web/dist/layout.js
vendored
@@ -1,79 +0,0 @@
|
||||
// layout.ts
|
||||
let leftPanel = null;
|
||||
let rightPanel = null;
|
||||
let dragBar = null;
|
||||
let isDragging = false;
|
||||
let pendingX = null;
|
||||
export function initResize() {
|
||||
leftPanel = document.getElementById("leftPanel");
|
||||
rightPanel = document.getElementById("rightPanel");
|
||||
dragBar = document.getElementById("dragBar");
|
||||
if (!leftPanel || !rightPanel || !dragBar)
|
||||
return;
|
||||
const savedRatio = localStorage.getItem('layoutRatio');
|
||||
if (savedRatio) {
|
||||
applyRatio(parseFloat(savedRatio));
|
||||
}
|
||||
dragBar.addEventListener("mousedown", (e) => {
|
||||
if (rightPanel.classList.contains("hidden"))
|
||||
return;
|
||||
isDragging = true;
|
||||
document.body.style.cursor = "col-resize";
|
||||
e.preventDefault();
|
||||
});
|
||||
document.addEventListener("mouseup", () => {
|
||||
if (!isDragging)
|
||||
return;
|
||||
isDragging = false;
|
||||
document.body.style.cursor = "default";
|
||||
if (rightPanel && !rightPanel.classList.contains("hidden")) {
|
||||
const total = window.innerWidth;
|
||||
const leftWidth = leftPanel.getBoundingClientRect().width;
|
||||
localStorage.setItem('layoutRatio', String(leftWidth / total));
|
||||
}
|
||||
});
|
||||
document.addEventListener("mousemove", (e) => {
|
||||
if (!isDragging)
|
||||
return;
|
||||
if (rightPanel && rightPanel.classList.contains("hidden"))
|
||||
return;
|
||||
pendingX = e.clientX;
|
||||
requestAnimationFrame(() => {
|
||||
if (pendingX === null)
|
||||
return;
|
||||
if (!leftPanel || !rightPanel || !dragBar)
|
||||
return;
|
||||
const total = window.innerWidth;
|
||||
let leftWidth = pendingX;
|
||||
const min = 300;
|
||||
if (leftWidth < min)
|
||||
leftWidth = min;
|
||||
if (leftWidth > total - min)
|
||||
leftWidth = total - min;
|
||||
const rightWidth = total - leftWidth - dragBar.offsetWidth;
|
||||
leftPanel.style.flex = `0 0 ${leftWidth}px`;
|
||||
rightPanel.style.flex = `0 0 ${rightWidth}px`;
|
||||
pendingX = null;
|
||||
});
|
||||
});
|
||||
}
|
||||
function applyRatio(ratio) {
|
||||
const total = window.innerWidth;
|
||||
const leftWidth = Math.floor(total * ratio);
|
||||
const rightWidth = total - leftWidth;
|
||||
if (leftPanel && rightPanel) {
|
||||
leftPanel.style.flex = `0 0 ${leftWidth}px`;
|
||||
rightPanel.style.flex = `0 0 ${rightWidth}px`;
|
||||
}
|
||||
}
|
||||
export function updateResizerVisibility() {
|
||||
if (!dragBar || !rightPanel || !leftPanel)
|
||||
return;
|
||||
if (rightPanel.classList.contains("hidden")) {
|
||||
dragBar.classList.add("hidden");
|
||||
leftPanel.style.flex = "1";
|
||||
}
|
||||
else {
|
||||
dragBar.classList.remove("hidden");
|
||||
}
|
||||
}
|
||||
33
cmd/server/web/dist/state.js
vendored
33
cmd/server/web/dist/state.js
vendored
@@ -1,33 +0,0 @@
|
||||
export const state = {
|
||||
maxPoints: 1000,
|
||||
signalHistory: [],
|
||||
smoothValue: 0,
|
||||
lastBufferSize: 0,
|
||||
};
|
||||
export function smooth(target) {
|
||||
state.smoothValue += 0.2 * (target - state.smoothValue);
|
||||
return state.smoothValue;
|
||||
}
|
||||
export function addSignal(value) {
|
||||
state.signalHistory.push(value);
|
||||
if (state.signalHistory.length > state.maxPoints) {
|
||||
state.signalHistory = state.signalHistory.slice(-state.maxPoints);
|
||||
}
|
||||
}
|
||||
export function addSignals(values, bufferSize) {
|
||||
if (!Array.isArray(values) || values.length === 0)
|
||||
return;
|
||||
const newBytes = bufferSize - state.lastBufferSize;
|
||||
if (newBytes > 0 && newBytes <= values.length) {
|
||||
const fresh = values.slice(-newBytes);
|
||||
const decoded = fresh.map(b => b & 0x3F);
|
||||
state.signalHistory.push(...decoded);
|
||||
}
|
||||
state.lastBufferSize = bufferSize;
|
||||
if (state.signalHistory.length > state.maxPoints) {
|
||||
state.signalHistory = state.signalHistory.slice(-state.maxPoints);
|
||||
}
|
||||
}
|
||||
export function resetBufferTracking() {
|
||||
state.lastBufferSize = 0;
|
||||
}
|
||||
86
cmd/server/web/dist/ui.js
vendored
86
cmd/server/web/dist/ui.js
vendored
@@ -1,86 +0,0 @@
|
||||
export const DOM = {
|
||||
status: null,
|
||||
meta: null,
|
||||
latest: null,
|
||||
lastByte: null,
|
||||
history: null,
|
||||
canvas: null,
|
||||
bars: document.querySelectorAll(".sig-bar"),
|
||||
barFill: null,
|
||||
historyHeader: null,
|
||||
historyBody: null,
|
||||
};
|
||||
export function initDOM() {
|
||||
DOM.status = document.getElementById("status");
|
||||
DOM.meta = document.getElementById("meta");
|
||||
DOM.latest = document.getElementById("latest");
|
||||
DOM.lastByte = document.getElementById("last-byte");
|
||||
DOM.history = document.getElementById("history");
|
||||
DOM.canvas = document.getElementById("signalChart");
|
||||
DOM.barFill = document.getElementById("bar1");
|
||||
DOM.historyHeader = document.getElementById("history-header");
|
||||
DOM.historyBody = document.getElementById("history-body");
|
||||
DOM.bars = document.querySelectorAll(".sig-bar");
|
||||
}
|
||||
export function setStatus(v, isError = false) {
|
||||
if (!DOM.status)
|
||||
return;
|
||||
DOM.status.textContent = v;
|
||||
DOM.status.classList.remove("status-ok", "status-error", "status-lost");
|
||||
if (isError) {
|
||||
if (v === "Нет связи") {
|
||||
DOM.status.classList.add("status-lost");
|
||||
}
|
||||
else {
|
||||
DOM.status.classList.add("status-error");
|
||||
}
|
||||
}
|
||||
else {
|
||||
DOM.status.classList.add("status-ok");
|
||||
}
|
||||
}
|
||||
export function setMeta(v) {
|
||||
if (DOM.meta)
|
||||
DOM.meta.textContent = v;
|
||||
}
|
||||
export function setBars(p, noConnection = false) {
|
||||
const el = DOM.barFill;
|
||||
if (!el)
|
||||
return;
|
||||
if (noConnection) {
|
||||
el.style.width = "0%";
|
||||
el.classList.add("no-connection");
|
||||
}
|
||||
else {
|
||||
el.classList.remove("no-connection");
|
||||
el.style.width = `${Math.max(0, Math.min(100, p))}%`;
|
||||
}
|
||||
}
|
||||
export function setSignal(level, noConnection = false) {
|
||||
const bars = DOM.bars;
|
||||
if (!bars || bars.length < 3)
|
||||
return;
|
||||
bars.forEach(bar => {
|
||||
bar.classList.remove("active-1", "active-2", "active-3", "dim", "no-connection");
|
||||
if (noConnection) {
|
||||
bar.classList.add("no-connection");
|
||||
}
|
||||
else {
|
||||
bar.classList.add("dim");
|
||||
}
|
||||
});
|
||||
if (noConnection)
|
||||
return;
|
||||
if (level >= 1) {
|
||||
bars[0].classList.add("active-1");
|
||||
bars[0].classList.remove("dim");
|
||||
}
|
||||
if (level >= 2) {
|
||||
bars[1].classList.add("active-2");
|
||||
bars[1].classList.remove("dim");
|
||||
}
|
||||
if (level >= 3) {
|
||||
bars[2].classList.add("active-3");
|
||||
bars[2].classList.remove("dim");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user