'use client' import React from 'react' interface ChartDataPoint { critical?: number warning?: number label?: string } interface BarChartProps { className?: string data?: ChartDataPoint[] } const BarChart: 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 barData = (Array.isArray(data) && data.length > 0) ? data.map(d => ({ critical: d.critical || 0, warning: d.warning || 0, label: d.label || '' })) : Array.from({ length: 12 }, (_, i) => ({ critical: 0, warning: 0, label: `${i + 1}` })) const maxVal = Math.max(...barData.map(b => (b.critical || 0) + (b.warning || 0)), 1) // Генерируем 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(barData.length / 8) const xLabels = barData .map((d, i) => { const barWidth = Math.max(30, plotWidth / barData.length - 8) const barSpacing = (plotWidth - barWidth * barData.length) / (barData.length - 1 || 1) const x = margin.left + i * (barWidth + barSpacing) + barWidth / 2 return { label: d.label || `${i + 1}`, x, index: i } }) .filter((_, i) => i % xLabelStep === 0 || i === barData.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, 8) : `${label.index + 1}`} ))} {/* Подпись оси Y */} Количество {/* Подпись оси X */} Период {/* Столбцы - сгруппированные по критическим и предупреждениям */} {barData.map((bar, index) => { const barWidth = Math.max(30, plotWidth / barData.length - 8) const barSpacing = (plotWidth - barWidth * barData.length) / (barData.length - 1 || 1) const groupX = margin.left + index * (barWidth + barSpacing) const totalValue = (bar.critical || 0) + (bar.warning || 0) // Ширина каждого подстолбца const subBarWidth = barWidth / 2 - 2 // Критический столбец (красный) const criticalHeight = (bar.critical / maxVal) * plotHeight const criticalY = baselineY - criticalHeight // Предупреждение столбец (оранжевый) const warningHeight = (bar.warning / maxVal) * plotHeight const warningY = baselineY - warningHeight return ( {/* Критический столбец */} {bar.critical > 0 && ( <> )} {/* Предупреждение столбец */} {bar.warning > 0 && ( <> )} ) })} {/* Легенда - горизонтально над графиком */} Критические Предупреждения
) } export default BarChart