Add static/js/pages/history.js
This commit is contained in:
parent
391c1e6704
commit
d1e9e189a4
1 changed files with 167 additions and 0 deletions
167
static/js/pages/history.js
Normal file
167
static/js/pages/history.js
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const ctx = document.getElementById('totalRoutesChart').getContext('2d');
|
||||
let chart;
|
||||
let currentRange = '24h';
|
||||
|
||||
const timeRangeButtons = document.querySelectorAll('.btn-group .btn');
|
||||
|
||||
timeRangeButtons.forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
currentRange = button.getAttribute('data-range');
|
||||
timeRangeButtons.forEach(btn => btn.classList.remove('active'));
|
||||
button.classList.add('active');
|
||||
fetchDataAndRenderChart(currentRange);
|
||||
});
|
||||
});
|
||||
|
||||
function updateChartScale(chartInstance) {
|
||||
const visibleDatasets = chartInstance.data.datasets.filter(dataset => !dataset.hidden);
|
||||
|
||||
let pointsForScaling = [];
|
||||
visibleDatasets.forEach(dataset => {
|
||||
const validData = (dataset.data || []).filter(val => typeof val === 'number');
|
||||
pointsForScaling.push(...validData);
|
||||
});
|
||||
|
||||
let suggestedMin, suggestedMax;
|
||||
|
||||
if (pointsForScaling.length > 0) {
|
||||
const minValue = Math.min(...pointsForScaling);
|
||||
const maxValue = Math.max(...pointsForScaling);
|
||||
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 fetchDataAndRenderChart(range) {
|
||||
try {
|
||||
const response = await fetch(`/history/api/total-routes?range=${range}`);
|
||||
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
||||
const data = await response.json();
|
||||
renderChart(data);
|
||||
} catch (error) {
|
||||
console.error('Error fetching chart data:', error);
|
||||
const chartContainer = document.querySelector('.achart-wrapper-chart');
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = '<p class="text-danger text-center">Could not load chart data.</p>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderChart(data) {
|
||||
if (chart) {
|
||||
chart.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()}`;
|
||||
|
||||
chart = new Chart(ctx, {
|
||||
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)',
|
||||
},
|
||||
{
|
||||
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: {
|
||||
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',
|
||||
onClick: (e, legendItem, legend) => {
|
||||
const chartInstance = legend.chart;
|
||||
const index = legendItem.datasetIndex;
|
||||
chartInstance.data.datasets[index].hidden = !chartInstance.data.datasets[index].hidden;
|
||||
updateChartScale(chartInstance);
|
||||
}
|
||||
},
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateChartScale(chart);
|
||||
}
|
||||
|
||||
fetchDataAndRenderChart(currentRange);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue