Add dynamic metric loading on chart zoom

- Add onZoomComplete callback to charts
- When zoomed to < 100 points, load detailed data from API
- Add loadDetailedMetrics function per chart
- API returns aggregated data (max 500 points) for zoomed range
- Improves performance while preserving detail on zoom
This commit is contained in:
mirivlad 2026-04-25 16:45:09 +08:00
parent 66d4d021ba
commit 36ace1e9d2
1 changed files with 60 additions and 1 deletions

View File

@ -804,7 +804,39 @@ const chart{{ metricName|replace({'-': '_', '.': '_'}) }} = new Chart(ctx{{ metr
wheel: {
enabled: true
},
mode: 'x'
mode: 'x',
onZoomComplete: function(chart) {
// Сохраняем оригинальный диапазон если ещё не сохраняли
if (!chart._originalMinIndex && !chart._originalMaxIndex) {
chart._originalMinIndex = 0;
chart._originalMaxIndex = chart.data.labels.length - 1;
}
// Получаем новый диапазон после зума
var scale = chart.scales.x;
var newMinIndex = Math.floor(scale.min);
var newMaxIndex = Math.ceil(scale.max);
// Ограничиваем индексы
newMinIndex = Math.max(0, newMinIndex);
newMaxIndex = Math.min(chart.data.labels.length - 1, newMaxIndex);
// Если зум слишком глубокий (менее 100 точек) - загружаем детальные данные
var pointsInView = newMaxIndex - newMinIndex + 1;
if (pointsInView < 100 && newMinIndex < newMaxIndex) {
// Определяем диапазон дат
var originalLabels = chart{{ metricName|replace({'-': '_', '.': '_'}) }}._originalLabels;
if (!originalLabels) {
originalLabels = chart{{ metricName|replace({'-': '_', '.': '_'}) }}._originalLabels = [...chart.data.labels];
}
var startTime = originalLabels[newMinIndex];
var endTime = originalLabels[newMaxIndex];
// Загружаем детальные данные
loadDetailedMetrics{{ metricName|replace({'-': '_', '.': '_'}) }}(startTime, endTime);
}
}
},
pan: {
enabled: true,
@ -815,6 +847,33 @@ const chart{{ metricName|replace({'-': '_', '.': '_'}) }} = new Chart(ctx{{ metr
}
});
// Функция загрузки детальных данных при зуме
function loadDetailedMetrics{{ metricName|replace({'-': '_', '.': '_'}) }}(startTime, endTime) {
var chart = chart{{ metricName|replace({'-': '_', '.': '_'}) }};
var metricName = '{{ metricName }}';
var serverId = {{ server.id }};
// Debounce - не запрашивать слишком часто
if (loadDetailedMetrics{{ metricName|replace({'-': '_', '.': '_'}) }}._loading) return;
loadDetailedMetrics{{ metricName|replace({'-': '_', '.': '_'}) }}._loading = true;
setTimeout(function() { loadDetailedMetrics{{ metricName|replace({'-': '_', '.': '_'}) }}._loading = false; }, 500);
var url = '/api/servers/' + serverId + '/metrics?start=' + encodeURIComponent(startTime) + '&end=' + encodeURIComponent(endTime);
fetch(url)
.then(function(response) { return response.json(); })
.then(function(data) {
if (data.labels && data.datasets && data.datasets[metricName]) {
chart.data.labels = data.labels;
chart.data.datasets[0].data = data.datasets[metricName];
chart.update();
}
})
.catch(function() {
console.log('Failed to load detailed metrics for ' + metricName);
});
}
// Скрывать tooltip при уходе курсора с canvas в любую сторону
chart{{ metricName|replace({'-': '_', '.': '_'}) }}.canvas.addEventListener('mouseleave', function() {
var tooltipEl = document.getElementById('chartjs-tooltip-{{ server.id }}-{{ metricName }}');