diff --git a/cmd/server/web/css/style.css b/cmd/server/web/css/style.css
index 4662c86..2c2f5ec 100644
--- a/cmd/server/web/css/style.css
+++ b/cmd/server/web/css/style.css
@@ -145,7 +145,7 @@ h1 {
flex: 1;
border-radius: 2px;
min-width: 5px;
- border: 1.5px solid #00ff88;
+ border: 1.5px solid #e6852d;
background-color: transparent;
transition: background-color 0.3s, border-color 0.3s;
}
@@ -164,8 +164,8 @@ h1 {
.sig-bar.active-1,
.sig-bar.active-2,
.sig-bar.active-3 {
- background-color: #00ff88;
- border-color: #00ff88;
+ background-color: #e6852d;
+ border-color: #c46b1f;
}
/* Нет связи - сигнальные бары */
@@ -186,7 +186,7 @@ h1 {
#signalChart {
width: 100%;
background: #050805;
- border: 1px solid #00ff88;
+ border: 1px solid #e6852d;
border-radius: 8px;
}
diff --git a/cmd/server/web/dashboard.html b/cmd/server/web/dashboard.html
index eb9db6b..1cc9c5e 100644
--- a/cmd/server/web/dashboard.html
+++ b/cmd/server/web/dashboard.html
@@ -60,7 +60,7 @@
-
ГРАФИК СИГНАЛА (последние 1000)
+ ГРАФИК СИГНАЛА
diff --git a/cmd/server/web/js/chart.js b/cmd/server/web/js/chart.js
index 47b7149..c803a7b 100644
--- a/cmd/server/web/js/chart.js
+++ b/cmd/server/web/js/chart.js
@@ -3,7 +3,7 @@ export function drawChart(canvas, history) {
if (!canvas || !history?.length) return;
const rect = canvas.getBoundingClientRect();
- const displayHeight = rect.height || 120;
+ const displayHeight = rect.height || 200; // увеличил для подписей
const displayWidth = rect.width || 800;
canvas.width = displayWidth;
@@ -13,22 +13,145 @@ export function drawChart(canvas, history) {
const w = canvas.width;
const h = canvas.height;
- ctx.clearRect(0, 0, w, h);
+ // ===== ОТСТУПЫ ДЛЯ ПОДПИСЕЙ =====
+ const padLeft = 50; // место под значения Y слева
+ const padRight = 20; // отступ справа
+ const padTop = 15; // отступ сверху
+ const padBottom = 30; // отступ снизу для подписей X
- const stepX = w / history.length;
- const scaleY = h / 63;
+ const plotW = w - padLeft - padRight;
+ const plotH = h - padTop - padBottom;
- ctx.strokeStyle = "#00ff88";
- ctx.lineWidth = 2;
+ // ===== ФОН ГРАФИКА =====
+ ctx.fillStyle = "#0a0f0a";
+ ctx.fillRect(0, 0, w, h);
+
+ // ===== СЕТКА =====
+ const maxVal = 63;
+ const gridLines = 4; // 4 линии + 0 = 5 уровней: 0, 16, 32, 48, 64
+
+ 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), padLeft - 8, y + 4);
+ }
+
+ // Вертикальные линии (временные метки)
+ const timeMarks = 5;
+ ctx.setLineDash([4, 4]);
+ for (let i = 0; i <= timeMarks; i++) {
+ const x = padLeft + (plotW / timeMarks) * i;
+ ctx.beginPath();
+ ctx.moveTo(x, padTop);
+ ctx.lineTo(x, padTop + plotH);
+ ctx.stroke();
+
+ // Подпись снизу
+ const pct = Math.round((i / timeMarks) * 100);
+ ctx.fillStyle = "#008844";
+ ctx.font = "9px monospace";
+ ctx.textAlign = "center";
+ ctx.fillText(`${100 - pct}%`, x, padTop + plotH + 16);
+ }
+
+ ctx.setLineDash([]); // сброс пунктира
+
+ // ===== ПОДПИСИ ОСЕЙ =====
+ ctx.fillStyle = "#00ff88";
+ ctx.font = "bold 12px monospace";
+
+ // Y
+ ctx.save();
+ ctx.translate(12, padTop + plotH / 2);
+ ctx.rotate(-Math.PI / 2);
+ ctx.textAlign = "center";
+ ctx.fillText("ЗНАЧЕНИЕ (0–63)", 0, 0);
+ ctx.restore();
+
+ // X
+ ctx.textAlign = "center";
+ ctx.fillText("ВРЕМЯ ← новые", w / 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;
+ }
+
+ // Линия графика
+ ctx.strokeStyle = "#e6852d";
+ ctx.lineWidth = 1.5;
+ ctx.shadowColor = "#e6852d";
+ ctx.shadowBlur = 3;
+
ctx.beginPath();
+ const stepX = plotW / Math.max(history.length - 1, 1);
+
for (let i = 0; i < history.length; i++) {
- const x = i * stepX;
- const y = h - history[i] * scaleY;
+ const x = padLeft + i * stepX;
+ const y = padTop + plotH - (history[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 lastIdx = history.length - 1;
+ const lastX = padLeft + lastIdx * stepX;
+ const lastY = padTop + plotH - (history[lastIdx] / maxVal) * plotH;
+ const lastVal = history[lastIdx];
+
+ // Кружок на последней точке
+ ctx.fillStyle = "#c46b1f";
+ ctx.beginPath();
+ ctx.arc(lastX, lastY, 4, 0, Math.PI * 2);
+ ctx.fill();
+
+ // Подпись значения над точкой
+ ctx.fillStyle = "#00ff88";
+ ctx.font = "bold 12px monospace";
+ ctx.textAlign = "left";
+ ctx.fillText(`${lastVal}`, lastX + 8, lastY - 8);
+
+ // Карточка статистики в правом верхнем углу
+ const avg = Math.round(history.reduce((a, b) => a + b, 0) / history.length);
+ const peak = Math.max(...history);
+ const min = Math.min(...history);
+
+ ctx.fillStyle = "rgba(0,0,0,0.7)";
+ ctx.fillRect(w - 140, padTop, 130, 55);
+
+ ctx.fillStyle = "#00ff88";
+ ctx.font = "10px monospace";
+ ctx.textAlign = "left";
+ ctx.fillText(`Пик: ${peak}`, w - 130, padTop + 14);
+ ctx.fillText(`Сред: ${avg}`, w - 130, padTop + 28);
+ ctx.fillText(`Мин: ${min}`, w - 130, padTop + 42);
+ ctx.fillText(`Всего: ${history.length}`, w - 130, padTop + 56);
+ }
}
\ No newline at end of file