// 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); } }