From f87274d41a08f512b44c8fd8c2e3b5361c6c794c Mon Sep 17 00:00:00 2001 From: DmitriyA Date: Fri, 6 Jun 2025 07:25:32 -0400 Subject: [PATCH] improving charts --- src/Charts2/Components/LineChartComponent.jsx | 177 ++++++++++-------- src/Charts2/Components/StatusLogTable.jsx | 28 ++- src/Charts2/PrometheusChart.jsx | 31 ++- 3 files changed, 135 insertions(+), 101 deletions(-) diff --git a/src/Charts2/Components/LineChartComponent.jsx b/src/Charts2/Components/LineChartComponent.jsx index 40b9aa7..e09476f 100644 --- a/src/Charts2/Components/LineChartComponent.jsx +++ b/src/Charts2/Components/LineChartComponent.jsx @@ -37,7 +37,8 @@ const getStatusText = (status) => { 0: 'Нет соединения', 1: 'Норма', 2: 'Отклонение', - 3: 'Критично' + 3: 'Критично', + 4: 'Авария' }[status] || 'Неизвестно'; }; @@ -46,7 +47,8 @@ const getStatusDescription = (status) => { 0: 'Устройство не отвечает', 1: 'Параметры в норме', 2: 'Обнаружены отклонения от нормы', - 3: 'Критическое состояние системы' + 3: 'Критическое состояние системы', + 4: 'Авария' }[status] || 'Статус неизвестен'; }; @@ -139,66 +141,73 @@ const LineChartComponent = ({ return areas.map((area, i) => ( + key={`area-${i}`} + x1={area.start} + x2={area.end} + fill={getStatusColor(area.status)} + fillOpacity={0.12} + stroke={getStatusColor(area.status)} + strokeWidth={1} + strokeOpacity={0.5} +/> + )); }; - const renderRangeAreas = () => { - if (!ranges || ranges.length === 0) return null; - - return ranges.map((range, index) => { - const hasData = data && data.length > 0; - const minX = hasData ? data[0].timestamp : 0; - const maxX = hasData ? data[data.length - 1].timestamp : 0; - - return ( - - ); - }); - }; - const renderRangeLines = () => { if (!ranges || ranges.length === 0) return null; - - const uniqueValues = new Set(); - ranges.forEach(range => { - uniqueValues.add(range.min); - uniqueValues.add(range.max); + + // Собираем только уникальные граничные значения, исключая дубликаты на стыках диапазонов + const boundaryValues = []; + ranges.forEach((range, index) => { + // Для первого диапазона добавляем и min и max + if (index === 0) { + boundaryValues.push(range.min); + boundaryValues.push(range.max); + } + // Для остальных добавляем только max (min будет совпадать с max предыдущего) + else { + boundaryValues.push(range.max); + } + }); + + return boundaryValues.map((value, index) => { + // Находим диапазон, к которому принадлежит эта граница + const range = ranges.find(r => r.min === value || r.max === value); + const status = range ? range.status : 1; + + const lineStyle = { + 1: { strokeWidth: 1, strokeDasharray: "none", opacity: 0.7 }, + 2: { strokeWidth: 2, strokeDasharray: "none", opacity: 0.9 }, + 3: { strokeWidth: 2, strokeDasharray: "none", opacity: 1 }, + 4: { strokeWidth: 2, strokeDasharray: "none", opacity: 1 } + }[status] || { strokeWidth: 1, strokeDasharray: "3 3", opacity: 0.7 }; + + return ( + + ); }); - - return Array.from(uniqueValues).map((value, index) => ( - - )); }; const renderStatusBoundaries = () => { @@ -279,33 +288,34 @@ const LineChartComponent = ({ )} - - - new Date(ts).toLocaleTimeString()} - /> - - {renderRangeLines()} - {renderRangeAreas()} - {renderStatusBoundaries()} {/* Добавляем отображение границ */} - {getStatusAreas()} - } /> - - } - activeDot={{ r: 8 }} - isAnimationActive={false} - name={title} - /> - + + + new Date(ts).toLocaleTimeString()} + /> + + {renderRangeLines()} + {renderStatusBoundaries()} + {getStatusAreas()} + } /> + + } + activeDot={{ r: 8 }} + isAnimationActive={false} + name={title} + /> + + + {/* Легенда статусов */} @@ -320,6 +330,7 @@ const LineChartComponent = ({ { status: 1, label: '1 - Норма' }, { status: 2, label: '2 - Отклонение' }, { status: 3, label: '3 - Критично' }, + { status: 4, label: '4 - Авария' }, { status: 0, label: '0 - Нет связи' } ].map(item => (
diff --git a/src/Charts2/Components/StatusLogTable.jsx b/src/Charts2/Components/StatusLogTable.jsx index 33dbc06..ccffd23 100644 --- a/src/Charts2/Components/StatusLogTable.jsx +++ b/src/Charts2/Components/StatusLogTable.jsx @@ -1,4 +1,3 @@ -// src/Components/StatusLogTable.jsx import React from 'react'; import { Table, @@ -12,11 +11,13 @@ import { Typography } from '@mui/material'; +// Используем те же цвета, что и в LineChartComponent const statusColors = { - '0': 'default', - '1': 'success', - '2': 'warning', - '3': 'error' + '0': '#757575', // серый (нет связи) + '1': '#4CAF50', // зеленый (норма) + '2': '#FFC107', // желтый (отклонение) + '3': '#FF9800', // оранжевый (критично) + '4': '#F44336' // красный (авария) }; const StatusLogTable = ({ logs }) => { @@ -42,9 +43,14 @@ const StatusLogTable = ({ logs }) => { {log.device} {log.source_id?.split('$')[1]} - @@ -62,13 +68,14 @@ const StatusLogTable = ({ logs }) => { ); }; -// Вспомогательные функции +// Вспомогательные функции (оставляем без изменений) const getStatusText = (status) => { const statusMap = { '0': 'Нет соединения', '1': 'Норма', '2': 'Отклонение', - '3': 'Критично' + '3': 'Критично', + '4': 'Авария' }; return statusMap[status] || 'Неизвестно'; }; @@ -78,7 +85,8 @@ const getStatusDescription = (status) => { '0': 'Устройство не отвечает', '1': 'Параметры в норме', '2': 'Обнаружены отклонения от нормы', - '3': 'Критическое состояние системы' + '3': 'Критическое состояние системы', + '4': 'Аварийное состояние системы' }; return descriptions[status] || 'Статус неизвестен'; }; diff --git a/src/Charts2/PrometheusChart.jsx b/src/Charts2/PrometheusChart.jsx index bca8ac6..65f0fb2 100644 --- a/src/Charts2/PrometheusChart.jsx +++ b/src/Charts2/PrometheusChart.jsx @@ -53,6 +53,19 @@ const PrometheusChart = ({ metricInfo, chartHeight = 580 }) => { .sort((a, b) => a.timestamp - b.timestamp); }; + const downsampleData = (data, maxPoints = 500) => { + if (data.length <= maxPoints) return data; + + const ratio = Math.ceil(data.length / maxPoints); + return data.filter((_, index) => index % ratio === 0); + }; + + const calculateStep = (startTime, endTime, maxPoints = 10000) => { + const seconds = (endTime.getTime() - startTime.getTime()) / 1000; + return Math.max(Math.ceil(seconds / maxPoints), 1); // в секундах + }; + + // Обновляем логи при изменении данных useEffect(() => { if (chartData.length > 0) { @@ -78,15 +91,17 @@ const PrometheusChart = ({ metricInfo, chartHeight = 580 }) => { ...(source_id && { source_id: source_id.toString() }) }; - const data = await metricsService.fetchMetricsRange( - metricName, - Math.floor(start.getTime() / 1000), - Math.floor(end.getTime() / 1000), - 15, - extendedFilters - ); + const step = calculateStep(start, end); +const data = await metricsService.fetchMetricsRange( + metricName, + Math.floor(start.getTime() / 1000), + Math.floor(end.getTime() / 1000), + step, + extendedFilters +); - const formattedData = formatMetricData(data); + + const formattedData = downsampleData(formatMetricData(data), 100); //КОЛИЧЕСТВО ТОЧЕК НА ГРАФИКЕ if (formattedData.length > 0) { setMetricMeta({ type: data[0]?.type,