Router-tools/static/js/pages/history.js

229 lines
No EOL
8.1 KiB
JavaScript

document.addEventListener('DOMContentLoaded', function () {
const ipv4Ctx = document.getElementById('ipv4RoutesChart').getContext('2d');
const ipv6Ctx = document.getElementById('ipv6RoutesChart').getContext('2d');
let ipv4Chart, ipv6Chart;
let currentRange = '24h';
const timeRangeButtons = document.querySelectorAll('.btn-group .btn');
const customRangeBtn = document.getElementById('customRangeBtn');
const startDateInput = document.getElementById('startDate');
const endDateInput = document.getElementById('endDate');
function formatDateForInput(date) {
const pad = (num) => num.toString().padStart(2, '0');
const year = date.getFullYear();
const month = pad(date.getMonth() + 1);
const day = pad(date.getDate());
const hours = pad(date.getHours());
const minutes = pad(date.getMinutes());
return `${year}-${month}-${day}T${hours}:${minutes}`;
}
function updateDateInputs(range) {
const endDate = new Date();
let startDate = new Date();
switch (range) {
case '24h':
startDate.setHours(startDate.getHours() - 24);
break;
case '7d':
startDate.setDate(startDate.getDate() - 7);
break;
case '30d':
startDate.setDate(startDate.getDate() - 30);
break;
case '90d':
startDate.setDate(startDate.getDate() - 90);
break;
}
startDateInput.value = formatDateForInput(startDate);
endDateInput.value = formatDateForInput(endDate);
}
timeRangeButtons.forEach(button => {
button.addEventListener('click', () => {
currentRange = button.getAttribute('data-range');
timeRangeButtons.forEach(btn => btn.classList.remove('active'));
button.classList.add('active');
updateDateInputs(currentRange);
fetchDataAndRenderCharts({ range: currentRange });
});
});
customRangeBtn.addEventListener('click', () => {
const startDate = startDateInput.value;
const endDate = endDateInput.value;
if (startDate && endDate) {
timeRangeButtons.forEach(btn => btn.classList.remove('active'));
fetchDataAndRenderCharts({ startDate, endDate });
} else {
alert('Please select both a start and end date.');
}
});
function updateChartScale(chartInstance) {
const dataset = chartInstance.data.datasets[0];
const validData = (dataset.data || []).filter(val => typeof val === 'number');
let suggestedMin, suggestedMax;
if (validData.length > 0) {
const minValue = Math.min(...validData);
const maxValue = Math.max(...validData);
const padding = (maxValue - minValue) * 0.1 || 200;
suggestedMin = Math.floor(minValue - padding);
suggestedMax = Math.ceil(maxValue + padding);
} else {
suggestedMin = 0;
suggestedMax = 1000;
}
chartInstance.options.scales.y.min = suggestedMin;
chartInstance.options.scales.y.max = suggestedMax;
chartInstance.update();
}
async function fetchDataAndRenderCharts(params) {
let url = '/history/api/total-routes';
if (params.range) {
url += `?range=${params.range}`;
} else if (params.startDate && params.endDate) {
url += `?start_date=${params.startDate}&end_date=${params.endDate}`;
}
try {
const response = await fetch(url);
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const data = await response.json();
renderCharts(data);
} catch (error) {
console.error('Error fetching chart data:', error);
const chartContainers = document.querySelectorAll('.achart-wrapper-chart');
if (chartContainers) {
chartContainers.forEach(container => {
container.innerHTML = '<p class="text-danger text-center">Could not load chart data.</p>';
});
}
}
}
function renderCharts(data) {
if (ipv4Chart) ipv4Chart.destroy();
if (ipv6Chart) ipv6Chart.destroy();
const findLastValue = (arr) => {
for (let i = arr.length - 1; i >= 0; i--) {
if (arr[i] !== null && typeof arr[i] !== 'undefined') {
return arr[i];
}
}
return 'N/A';
};
const ipv4LastValue = findLastValue(data.ipv4_routes);
const ipv6LastValue = findLastValue(data.ipv6_routes);
const ipv4Label = `Total IPv4 Routes: ${ipv4LastValue.toLocaleString()}`;
const ipv6Label = `Total IPv6 Routes: ${ipv6LastValue.toLocaleString()}`;
const commonOptions = {
responsive: true,
maintainAspectRatio: false,
interaction: {
intersect: false,
mode: 'index',
},
scales: {
x: {
type: 'time',
time: {
unit: 'minute',
stepSize: 30,
displayFormats: {
minute: 'HH:mm',
hour: 'HH:mm'
}
}
},
y: { }
},
plugins: {
legend: {
position: 'top',
},
tooltip: {
callbacks: {
title: function(context) {
if (!context[0]) return '';
return new Date(context[0].parsed.x).toLocaleString([], {
year: 'numeric', month: 'short', day: 'numeric',
hour: '2-digit', minute: '2-digit', hour12: false
});
},
label: function(context) {
let label = context.dataset.label.split(':')[0] || '';
if (label) label += ': ';
if (context.parsed.y !== null) {
label += context.parsed.y.toLocaleString();
}
return label;
}
}
}
}
};
ipv4Chart = new Chart(ipv4Ctx, {
type: 'line',
data: {
labels: data.labels,
datasets: [
{
label: ipv4Label,
data: data.ipv4_routes,
borderColor: 'rgb(54, 162, 235)',
borderWidth: 1.5,
pointRadius: 2,
pointHoverRadius: 5,
spanGaps: true,
fill: true,
backgroundColor: 'rgba(54, 162, 235, 0.1)',
}
]
},
options: { ...commonOptions }
});
ipv6Chart = new Chart(ipv6Ctx, {
type: 'line',
data: {
labels: data.labels,
datasets: [
{
label: ipv6Label,
data: data.ipv6_routes,
borderColor: 'rgb(255, 99, 132)',
borderWidth: 1.5,
pointRadius: 2,
pointHoverRadius: 5,
spanGaps: true,
fill: true,
backgroundColor: 'rgba(255, 99, 132, 0.1)',
}
]
},
options: { ...commonOptions }
});
updateChartScale(ipv4Chart);
updateChartScale(ipv6Chart);
}
updateDateInputs(currentRange);
fetchDataAndRenderCharts({ range: currentRange });
});