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 = '

Could not load chart data.

'; }); } } } 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 }); });