'use client' import React from 'react' interface ChartDataPoint { critical?: number warning?: number label?: string timestamp?: string } interface AreaChartProps { className?: string data?: ChartDataPoint[] } const AreaChart: React.FC = ({ className = '', data }) => { const width = 635 const height = 280 const margin = { top: 40, right: 30, bottom: 50, left: 60 } const plotWidth = width - margin.left - margin.right const plotHeight = height - margin.top - margin.bottom const baselineY = margin.top + plotHeight const safeData = (Array.isArray(data) && data.length > 0) ? data : Array.from({ length: 7 }, () => ({ critical: 0, warning: 0 })) const maxVal = Math.max(...safeData.map(d => Math.max(d.critical || 0, d.warning || 0)), 1) const stepX = safeData.length > 1 ? plotWidth / (safeData.length - 1) : plotWidth // Точки для критических событий (красная линия) const criticalPoints = safeData.map((d, i) => { const x = margin.left + i * stepX const y = baselineY - (Math.min(d.critical || 0, maxVal) / maxVal) * plotHeight return { x, y } }) // Точки для предупреждений (оранжевая линия) const warningPoints = safeData.map((d, i) => { const x = margin.left + i * stepX const y = baselineY - (Math.min(d.warning || 0, maxVal) / maxVal) * plotHeight return { x, y } }) const criticalLinePath = criticalPoints.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x},${p.y}`).join(' ') const criticalAreaPath = `${criticalLinePath} L${width - margin.right},${baselineY} L${margin.left},${baselineY} Z` const warningLinePath = warningPoints.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x},${p.y}`).join(' ') const warningAreaPath = `${warningLinePath} L${width - margin.right},${baselineY} L${margin.left},${baselineY} Z` // Генерируем Y-оси метки const ySteps = 4 const yLabels = Array.from({ length: ySteps + 1 }, (_, i) => { const value = (maxVal / ySteps) * (ySteps - i) const y = margin.top + (i * plotHeight) / ySteps return { value: value.toFixed(1), y } }) // Генерируем X-оси метки (показываем каждую 2-ю или 3-ю точку) const xLabelStep = Math.ceil(safeData.length / 5) const xLabels = safeData .map((d, i) => { const x = margin.left + i * stepX const label = d.label || d.timestamp || `${i + 1}` return { label, x, index: i } }) .filter((_, i) => i % xLabelStep === 0 || i === safeData.length - 1) return (
{/* Сетка Y */} {yLabels.map((label, i) => ( ))} {/* Ось X */} {/* Ось Y */} {/* Y-оси метки и подписи */} {yLabels.map((label, i) => ( {label.value} ))} {/* X-оси метки и подписи */} {xLabels.map((label, i) => ( {typeof label.label === 'string' ? label.label.substring(0, 10) : `${label.index + 1}`} ))} {/* Подпись оси Y */} Количество {/* Подпись оси X */} Время {/* График предупреждений (оранжевый) - рисуем первым чтобы был на заднем плане */} {/* Точки данных для предупреждений */} {warningPoints.map((p, i) => ( ))} {/* График критических событий (красный) - рисуем поверх */} {/* Точки данных для критических */} {criticalPoints.map((p, i) => ( ))} {/* Легенда - горизонтально над графиком */} Критические Предупреждения
) } export default AreaChart