Files
go-service/cmd/server/web/js/chart.js
2026-05-09 12:39:35 +03:00

157 lines
5.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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");
const w = canvas.width;
const h = canvas.height;
// ===== ОТСТУПЫ ДЛЯ ПОДПИСЕЙ =====
const padLeft = 50; // место под значения Y слева
const padRight = 20; // отступ справа
const padTop = 15; // отступ сверху
const padBottom = 30; // отступ снизу для подписей X
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; // 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("ЗНАЧЕНИЕ (063)", 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 = 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);
}
}