* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
*/
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.header {
text-align: center;
margin-bottom: 30px;
color: white;
}
.header h1 {
font-size: 2.5rem;
margin-bottom: 10px;
text-shadow: 0 2px 4px rgba(0,0,0,0.3);
}
.header p {
font-size: 1.1rem;
opacity: 0.9;
}
.charts-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 30px;
margin-bottom: 30px;
}
@media (max-width: 768px) {
.charts-grid {
grid-template-columns: 1fr;
}
}
.chart-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 25px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
transition: all 0.3s ease;
}
.chart-card:hover {
transform: translateY(-5px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
}
.chart-header {
margin-bottom: 20px;
}
.chart-title {
font-size: 1.4rem;
color: #2d3748;
margin-bottom: 8px;
font-weight: 600;
}
.chart-subtitle {
color: #114693;
font-size: 0.9rem;
line-height: 1.4;
margin-top: 10px;
}
.chart-container {
position: relative;
height: 300px;
margin-bottom: 20px;
}
.pie-chart {
height: 350px;
}
.controls {
display: flex;
gap: 10px;
justify-content: center;
flex-wrap: wrap;
}
.period-btn, .download-btn {
padding: 8px 16px;
border: none;
border-radius: 25px;
cursor: pointer;
font-size: 0.9rem;
font-weight: 500;
transition: all 0.3s ease;
}
.period-btn {
background: linear-gradient(45deg, #667eea, #764ba2);
color: white;
}
.period-btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
}
.period-btn.active {
background: linear-gradient(45deg, #4c63d2, #5a4291);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.6);
}
.download-btn {
background: #0f6e37;
color: white;
}
.download-btn:hover {
background: #38a169;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(72, 187, 120, 0.4);
}
.stats-summary {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 25px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
}
.stat-item {
text-align: center;
padding: 15px;
background: linear-gradient(135deg, #f7fafc 0%, #edf2f7 100%);
border-radius: 15px;
border: 1px solid #e2e8f0;
}
.stat-number {
font-size: 1.8rem;
font-weight: 700;
color: #667eea;
margin-bottom: 5px;
}
.stat-label {
font-size: 0.9rem;
color: #4a5568;
font-weight: 500;
}
2019-2024
2014-2018
📊 Download Chart
// Color palette
const colors = {
primary: [
'#667eea', '#764ba2', '#f093fb', '#f5576c',
'#4facfe', '#00f2fe', '#43e97b', '#38f9d7',
'#ffecd2', '#fcb69f', '#a8edea', '#fed6e3'
]
};
// Chart.js default options
const defaultOptions = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
labels: {
font: { size: 12, weight: '500' },
color: '#4a5568',
padding: 15
}
},
tooltip: {
backgroundColor: 'rgba(0, 0, 0, 0.8)',
titleColor: 'white',
bodyColor: 'white',
borderColor: 'rgba(255, 255, 255, 0.2)',
borderWidth: 1,
cornerRadius: 8,
padding: 12
}
}
};
// Data definitions
const ipv4NetworksData = {
'Universities': 574,
'INFN': 510,
'GARR': 1082,
'Other research institutions': 42,
'IRCCS': 36,
'AFAM': 6
};
const networksData = {
period1: {
labels: ['2019', '2020', '2021', '2022', '2023', '2024'],
data: [18, 41, 27, 12, 12, 25]
},
period2: {
labels: ['2014', '2015', '2016', '2017', '2018'],
data: [79, 225, 37, 11, 14]
}
};
// Chart instances
let ipv4NetworksChart, networksChart;
// Initialize IPv4 Networks Chart
function createIPv4NetworksChart() {
const ctx = document.getElementById('ipv4NetworksChart').getContext('2d');
ipv4NetworksChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: Object.keys(ipv4NetworksData),
datasets: [{
data: Object.values(ipv4NetworksData),
backgroundColor: colors.primary,
borderWidth: 3,
borderColor: '#ffffff',
hoverBorderWidth: 4,
hoverOffset: 10
}]
},
options: {
...defaultOptions,
cutout: '50%',
plugins: {
...defaultOptions.plugins,
tooltip: {
...defaultOptions.plugins.tooltip,
callbacks: {
label: function(context) {
const total = context.dataset.data.reduce((a, b) => a + b, 0);
const percentage = ((context.parsed * 100) / total).toFixed(1);
return `${context.label}: ${context.parsed.toLocaleString()} (${percentage}%)`;
}
}
}
}
}
});
}
// Initialize Networks Timeline Chart
function createNetworksChart(period = 'period1') {
const ctx = document.getElementById('networksChart').getContext('2d');
const data = networksData[period];
if (networksChart) {
networksChart.destroy();
}
networksChart = new Chart(ctx, {
type: 'bar',
data: {
labels: data.labels,
datasets: [{
label: 'IPv4 and IPv6 Networks',
data: data.data,
backgroundColor: colors.primary[0],
borderColor: colors.primary[0],
borderWidth: 1,
borderRadius: 8,
borderSkipped: false
}]
},
options: {
...defaultOptions,
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: 'Number of networks assigned',
font: { size: 12, weight: '500' },
color: '#4a5568'
},
grid: {
color: 'rgba(0, 0, 0, 0.1)'
},
ticks: {
color: '#4a5568',
font: { size: 11 }
}
},
x: {
title: {
display: true,
text: 'Year',
font: { size: 12, weight: '500' },
color: '#4a5568'
},
grid: {
display: false
},
ticks: {
color: '#4a5568',
font: { size: 11 }
}
}
}
}
});
// Update button states
document.querySelectorAll('.period-btn').forEach(btn => btn.classList.remove('active'));
document.getElementById(`networksPeriod${period === 'period1' ? '1' : '2'}`).classList.add('active');
}
// Event Listeners
document.getElementById('networksPeriod1').addEventListener('click', () => {
createNetworksChart('period1');
updateStats();
});
document.getElementById('networksPeriod2').addEventListener('click', () => {
createNetworksChart('period2');
updateStats();
});
// Download handlers
document.getElementById('downloadIPv4Networks').addEventListener('click', () => {
const link = document.createElement('a');
link.download = 'ipv4-networks-by-organization-2024.png';
link.href = ipv4NetworksChart.toBase64Image();
link.click();
});
document.getElementById('downloadNetworks').addEventListener('click', () => {
const period = document.querySelector('.period-btn.active').textContent;
const link = document.createElement('a');
link.download = `networks-ipv4-ipv6-${period}.png`;
link.href = networksChart.toBase64Image();
link.click();
});
// Update stats
function updateStats() {
const currentPeriod = document.querySelector('.period-btn.active').textContent;
const periodData = currentPeriod === '2019-2024' ? networksData.period1 : networksData.period2;
const totalNetworks = Object.values(ipv4NetworksData).reduce((a, b) => a + b, 0);
const lastYearNetworks = periodData.data[periodData.data.length - 1];
const totalPeriodNetworks = periodData.data.reduce((a, b) => a + b, 0);
const avgPerYear = (totalPeriodNetworks / periodData.data.length).toFixed(1);
const stats = [
{ label: 'Total IPv4 addresses (2024)', value: totalNetworks.toLocaleString() },
{ label: `Networks assigned (${periodData.labels[periodData.labels.length - 1]})`, value: lastYearNetworks.toString() },
{ label: `Annual average networks assigned (${currentPeriod})`, value: avgPerYear },
{ label: `Total networks assigned (${currentPeriod})`, value: totalPeriodNetworks.toString() }
];
document.getElementById('statsGrid').innerHTML = stats.map(stat =>
`
${stat.value}
${stat.label}
`
).join('');
}
// Initialize charts
createIPv4NetworksChart();
createNetworksChart();
updateStats();
// Add hover effects
document.querySelectorAll('.chart-card').forEach(card => {
card.addEventListener('mouseenter', function() {
this.style.transform = 'translateY(-8px)';
});
card.addEventListener('mouseleave', function() {
this.style.transform = 'translateY(0)';
});
});