Annual report
Annual report 2024
Le informazioni contenute in questo documento sono tratte dal Bilancio Consuntivo 2024 e dalla Relazione sull'attività svolta e risultati conseguiti 2024 approvati dall'Assemblea dei soci GARR a aprile 2025.
Leggi il pdf
Infrastruttura di rete
vedi statistiche
Servizi
vedi statistiche
Personale e organizzazione
Vedi statistiche
Comunicazione e formazione
Vedi statistiche
INFRASTRUTTURA DI RETE
Statistiche infrastruttura di rete
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
min-height: 100vh;
}
.container {
max-width: 1400px;
margin: 0 auto;
}
.header {
text-align: center;
margin-bottom: 3rem;
color: white;
}
.header h1 {
font-size: 2.5rem;
font-weight: 300;
margin-bottom: 0.5rem;
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: repeat(auto-fit, minmax(600px, 1fr));
gap: 2rem;
margin-bottom: 2rem;
}
.chart-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 2rem;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.chart-card:hover {
transform: translateY(-5px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
}
.chart-header {
text-align: center;
margin-bottom: 1.5rem;
}
.chart-title {
font-size: 1.3rem;
font-weight: 600;
color: #2d3748;
margin-bottom: 0.3rem;
}
.chart-title-en {
font-size: 1rem;
font-style: italic;
color: #414853;
margin-bottom: 0.5rem;
}
.chart-subtitle {
font-size: 0.85rem;
color: #383b40;
line-height: 1.4;
}
.chart-container {
position: relative;
height: 400px;
margin-bottom: 1rem;
}
.chart-container.pie-chart {
height: 350px;
}
.controls {
display: flex;
justify-content: center;
align-items: center;
gap: 1rem;
flex-wrap: wrap;
margin-top: 1rem;
}
.period-btn {
padding: 0.5rem 1rem;
border: 2px solid #e2e8f0;
border-radius: 8px;
background: white;
color: #2d3748;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.3s ease;
}
.period-btn:hover {
border-color: #1e3c72;
box-shadow: 0 0 0 3px rgba(30, 60, 114, 0.1);
}
.year-selector {
padding: 0.5rem 1rem;
border: 2px solid #e2e8f0;
border-radius: 8px;
background: white;
color: #2d3748;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.3s ease;
}
.year-selector:hover, .year-selector:focus {
border-color: #1e3c72;
box-shadow: 0 0 0 3px rgba(30, 60, 114, 0.1);
outline: none;
}
.download-btn {
background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
color: white;
border: none;
padding: 0.6rem 1.2rem;
border-radius: 8px;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(30, 60, 114, 0.3);
}
.download-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(30, 60, 114, 0.4);
}
.stats-summary {
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10px);
border-radius: 15px;
padding: 1.5rem;
margin-top: 2rem;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
.stat-item {
text-align: center;
padding: 1rem;
border-radius: 10px;
background: linear-gradient(135deg, #f7fafc 0%, #edf2f7 100%);
}
.stat-number {
font-size: 1.8rem;
font-weight: 700;
color: #2d3748;
}
.stat-label {
font-size: 0.9rem;
color: #718096;
margin-top: 0.25rem;
}
@media (max-width: 768px) {
.charts-grid {
grid-template-columns: 1fr;
}
.header h1 {
font-size: 2rem;
}
.chart-container {
height: 300px;
}
body {
padding: 1rem;
}
}
2019-2024
2012-2018
📊 Download Chart
2020-2024
2014-2019
📊 Download Chart
2024
2023
2022
2021
2020
2019
2018
2017
2016
📊 Download Chart
2024
2023
2022
2021
2020
2019
2018
2017
2016
📊 Download Chart
2020-2024
2014-2019
📊 Download Chart
// Modern color palette
const colors = {
primary: ['#1e3c72', '#2a5298', '#3b82f6', '#06b6d4', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6'],
gradients: [
'linear-gradient(135deg, #1e3c72 0%, #2a5298 100%)',
'linear-gradient(135deg, #3b82f6 0%, #06b6d4 100%)',
'linear-gradient(135deg, #10b981 0%, #34d399 100%)',
'linear-gradient(135deg, #f59e0b 0%, #fbbf24 100%)',
'linear-gradient(135deg, #ef4444 0%, #f87171 100%)',
'linear-gradient(135deg, #8b5cf6 0%, #a78bfa 100%)',
'linear-gradient(135deg, #ec4899 0%, #f472b6 100%)',
'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)'
]
};
// Chart configurations
// Default options (come richiesto, deve continuare a funzionare)
const defaultOptions = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom',
labels: {
padding: 20,
usePointStyle: true,
font: {
size: 11,
family: "'Segoe UI', sans-serif"
}
}
},
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,
displayColors: true
}
},
animation: {
duration: 1500,
easing: 'easeOutQuart'
}
};
// Options estese con percentuali per i grafici a torta cloud
const pieOptionsWithPercentages = {
...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}%)`;
}
}
}
}
};
// Data definitions
const backboneData = {
period1: {
labels: ['2019', '2020', '2021', '2022', '2023', '2024'],
data: [3.020, 3.130, 3.130, 15.000, 22.060, 23.96]
},
period2: {
labels: ['2012', '2013', '2014', '2015', '2016', '2017', '2018'],
data: [0.548, 0.833, 0.860, 1.890, 2.040, 2.550, 2.950]
}
};
const accessData = {
period1: {
labels: ['2020', '2021', '2022', '2023', '2024'],
data: [2.3, 2.5, 2.7, 3.1, 4.0]
},
period2: {
labels: ['2014', '2015', '2016', '2017', '2018', '2019'],
data: [0.7, 0.9, 1.2, 1.4, 1.8, 2.0]
}
};
const backboneLinksLabels = ['> 100 Gbps', '100 Gbps', '< 100 Gbps', '≤ 10 Gbps', '≤ 1 Gbps'];
const accessLinksLabels = ['< 0.1 Gbps', '≥ 0.1 Gbps', '≥ 1 Gbps', '≥ 10 Gbps', '≥ 100 Gbps'];
const totalTrafficData = {
period1: {
labels: ['2020', '2021', '2022', '2023', '2024'],
datasets: [
{ label: 'IP (IP+GARR)', data: [204, 253, 437, 500, 510] },
{ label: 'L2/L3 VPN', data: [170, 200, 256, 326, 287] },
{ label: 'OPN', data: [72, 56, 61, 104, 135] }
]
},
period2: {
labels: ['2014', '2015', '2016', '2017', '2018', '2019'],
datasets: [
{ label: 'IP connectivity GARR', data: [126, 172, 306, 301, 384, 492] }
]
}
};
const researchTrafficData = {
labels: ['2020', '2021', '2022', '2023', '2024'],
datasets: [
{ label: 'IP Connectivity & L2/L3 VPN', data: [197, 234, 400, 423, 393] },
{ label: 'OPN', data: [72, 56, 61, 104, 135] },
{ label: 'Totale', data: [269, 290, 461, 527, 528] }
]
};
// Chart instances
let backboneCapacityChart, accessCapacityChart, backboneLinksChart, accessLinksChart, totalTrafficChart, researchTrafficChart;
// Initialize Backbone Capacity Chart
function createBackboneCapacityChart(period = 'period1') {
const ctx = document.getElementById('backboneCapacityChart').getContext('2d');
const data = backboneData[period];
if (backboneCapacityChart) {
backboneCapacityChart.destroy();
}
backboneCapacityChart = new Chart(ctx, {
type: 'bar',
data: {
labels: data.labels,
datasets: [{
label: 'Capacità in Tbps',
data: data.data,
backgroundColor: colors.primary[0],
borderColor: colors.primary[0],
borderWidth: 1,
borderRadius: 6,
borderSkipped: false
}]
},
options: {
...defaultOptions,
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: 'Capacità aggregata in Tbps'
}
},
x: {
title: {
display: true,
text: 'Anno'
}
}
}
}
});
}
// Initialize Access Capacity Chart
function createAccessCapacityChart(period = 'period1') {
const ctx = document.getElementById('accessCapacityChart').getContext('2d');
const data = accessData[period];
if (accessCapacityChart) {
accessCapacityChart.destroy();
}
accessCapacityChart = new Chart(ctx, {
type: 'bar',
data: {
labels: data.labels,
datasets: [{
label: 'Capacità in Tbps',
data: data.data,
backgroundColor: colors.primary[1],
borderColor: colors.primary[1],
borderWidth: 1,
borderRadius: 6,
borderSkipped: false
}]
},
options: {
...defaultOptions,
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: 'Capacità aggregata in Tbps'
}
},
x: {
title: {
display: true,
text: 'Anno'
}
}
}
}
});
}
// Initialize Backbone Links Chart
function createBackboneLinksChart(year = '2024') {
const ctx = document.getElementById('backboneLinksChart').getContext('2d');
const selector = document.getElementById('backboneYear');
const data = selector.value.split(',').map(Number);
if (backboneLinksChart) {
backboneLinksChart.destroy();
}
backboneLinksChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: backboneLinksLabels,
datasets: [{
data: data,
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} links (${percentage}%)`;
}
}
}
}
}
});
}
// Initialize Access Links Chart
function createAccessLinksChart(year = '2024') {
const ctx = document.getElementById('accessLinksChart').getContext('2d');
const selector = document.getElementById('accessYear');
const data = selector.value.split(',').map(Number);
if (accessLinksChart) {
accessLinksChart.destroy();
}
accessLinksChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: accessLinksLabels,
datasets: [{
data: data,
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} links (${percentage}%)`;
}
}
}
}
}
});
}
// Initialize Total Traffic Chart
function createTotalTrafficChart(period = 'period1') {
const ctx = document.getElementById('totalTrafficChart').getContext('2d');
const data = totalTrafficData[period];
if (totalTrafficChart) {
totalTrafficChart.destroy();
}
const datasets = data.datasets.map((dataset, index) => ({
label: dataset.label,
data: dataset.data,
borderColor: colors.primary[index],
backgroundColor: colors.primary[index] + '20',
borderWidth: 3,
fill: true,
tension: 0.4,
pointRadius: 6,
pointHoverRadius: 8
}));
totalTrafficChart = new Chart(ctx, {
type: 'line',
data: {
labels: data.labels,
datasets: datasets
},
options: {
...defaultOptions,
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: 'Petabyte (1PB = 1.000.000 GB)'
}
},
x: {
title: {
display: true,
text: 'Anno'
}
}
}
}
});
}
// Initialize Research Traffic Chart
function createResearchTrafficChart() {
const ctx = document.getElementById('researchTrafficChart').getContext('2d');
const datasets = researchTrafficData.datasets.map((dataset, index) => ({
label: dataset.label,
data: dataset.data,
borderColor: colors.primary[index],
backgroundColor: colors.primary[index] + '20',
borderWidth: index === 2 ? 4 : 3, // Totale line is thicker
fill: index !== 2, // Totale line is not filled
tension: 0.4,
pointRadius: 6,
pointHoverRadius: 8,
borderDash: index === 2 ? [8, 4] : []
}));
researchTrafficChart = new Chart(ctx, {
type: 'line',
data: {
labels: researchTrafficData.labels,
datasets: datasets
},
options: {
...defaultOptions,
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: 'Petabyte (1PB = 1.000.000 GB)'
}
},
x: {
title: {
display: true,
text: 'Anno'
}
}
}
}
});
}
// Event Listeners
document.getElementById('backbonePeriod1').addEventListener('click', () => {
createBackboneCapacityChart('period1');
updateStats();
});
document.getElementById('backbonePeriod2').addEventListener('click', () => {
createBackboneCapacityChart('period2');
updateStats();
});
document.getElementById('accessPeriod1').addEventListener('click', () => {
createAccessCapacityChart('period1');
updateStats();
});
document.getElementById('accessPeriod2').addEventListener('click', () => {
createAccessCapacityChart('period2');
updateStats();
});
document.getElementById('trafficPeriod1').addEventListener('click', () => {
createTotalTrafficChart('period1');
updateStats();
});
document.getElementById('trafficPeriod2').addEventListener('click', () => {
createTotalTrafficChart('period2');
updateStats();
});
document.getElementById('backboneYear').addEventListener('change', () => {
createBackboneLinksChart();
updateStats();
});
document.getElementById('accessYear').addEventListener('change', () => {
createAccessLinksChart();
updateStats();
});
// Download handlers
document.getElementById('downloadBackbone').addEventListener('click', () => {
const link = document.createElement('a');
link.download = 'backbone-capacity-GARR.png';
link.href = backboneCapacityChart.toBase64Image();
link.click();
});
document.getElementById('downloadAccess').addEventListener('click', () => {
const link = document.createElement('a');
link.download = 'access-capacity-GARR.png';
link.href = accessCapacityChart.toBase64Image();
link.click();
});
document.getElementById('downloadBackboneLinks').addEventListener('click', () => {
const year = document.getElementById('backboneYear').options[document.getElementById('backboneYear').selectedIndex].text;
const link = document.createElement('a');
link.download = `backbone-links-${year}-GARR.png`;
link.href = backboneLinksChart.toBase64Image();
link.click();
});
document.getElementById('downloadAccessLinks').addEventListener('click', () => {
const year = document.getElementById('accessYear').options[document.getElementById('accessYear').selectedIndex].text;
const link = document.createElement('a');
link.download = `access-links-${year}-GARR.png`;
link.href = accessLinksChart.toBase64Image();
link.click();
});
document.getElementById('downloadTotalTraffic').addEventListener('click', () => {
const link = document.createElement('a');
link.download = 'total-traffic-GARR.png';
link.href = totalTrafficChart.toBase64Image();
link.click();
});
document.getElementById('downloadResearchTraffic').addEventListener('click', () => {
const link = document.createElement('a');
link.download = 'research-traffic-GARR.png';
link.href = researchTrafficChart.toBase64Image();
link.click();
});
// Update stats
function updateStats() {
const currentBackboneCapacity = 23.96; // 2024 value
const currentAccessCapacity = 4.0; // 2024 value
const currentTotalLinks = 253; // 2024 backbone links
const currentAccessLinks = 896; // 2024 access links
const stats = [
{ label: 'Backbone Capacity (2024)', value: `${currentBackboneCapacity} Tbps` },
{ label: 'Access Capacity (2024)', value: `${currentAccessCapacity} Tbps` },
{ label: 'Backbone Links (2024)', value: currentTotalLinks.toLocaleString() },
{ label: 'Access Links (2024)', value: currentAccessLinks.toLocaleString() }
];
document.getElementById('statsGrid').innerHTML = stats.map(stat =>
`
${stat.value}
${stat.label}
`
).join('');
}
// Initialize all charts
createBackboneCapacityChart();
createAccessCapacityChart();
createBackboneLinksChart();
createAccessLinksChart();
createTotalTrafficChart();
createResearchTrafficChart();
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)';
});
});
SERVIZI
Statistiche rete e accesso
2019-2024
2012-2018
📊 Download Chart
2024
2023
📊 Download Chart
2019-2024
2014-2018
📊 Download Chart
2019-2024
2014-2018
📊 Download Chart
2024
2023
📊 Download Chart
2024
2023
2022
2021
2020
2019
2018
2017
📊 Download Chart
2019-2024
2014-2018
📊 Download Chart
// Color palette
const colorsServ = {
primary: [
'#667eea', '#764ba2', '#f093fb', '#f5576c',
'#4facfe', '#00f2fe', '#43e97b', '#38f9d7',
'#ffecd2', '#fcb69f', '#a8edea', '#fed6e3'
]
};
// Chart.js default options
const defaultOptionsServ = {
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 nocData = {
period1: {
labels: ['2019', '2020', '2021', '2022', '2023', '2024'],
datasets: [
{ label: 'Guasti', data: [1062, 1027, 999, 1144, 1151, 1170] },
{ label: 'Manutenzioni', data: [390, 363, 432, 498, 538, 677] }
]
},
period2: {
labels: ['2012', '2013', '2014', '2015', '2016', '2017', '2018'],
datasets: [
{ label: 'Guasti', data: [687, 734, 770, 754, 906, 820, 956] },
{ label: 'Manutenzioni', data: [386, 432, 346, 416, 593, 393, 310] }
]
}
};
const scarrData = {
labels: ['2019', '2020', '2021', '2022', '2023', '2024'],
data: [450, 760, 2400, 4500, 4717, 4700]
};
const certData = {
labels: ['2019', '2020', '2021', '2022', '2023', '2024'],
datasets: [
{ label: 'Ticket manuali', data: [3689, 2493, 2243, 1951, 2016, 1967] },
{ label: 'Ticket automatici', data: [12471, 7392, 7677, 5110, 8126, 5061] }
]
};
// Separated domains data (only .it and .eu)
const domainsData = {
period1: {
labels: ['2019', '2020', '2021', '2022', '2023', '2024'],
datasets: [
{ label: '.it', data: [117, 92, 122, 105, 98, 127] },
{ label: '.eu', data: [119, 87, 110, 95, 107, 91] }
]
},
period2: {
labels: ['2014', '2015', '2016', '2017', '2018'],
datasets: [
{ label: '.it', data: [96, 98, 103, 136, 164] },
{ label: '.eu', data: [70, 81, 79, 118, 90] }
]
}
};
// New networks data (only IPv4 and IPv6)
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]
}
};
const idemData = {
period1: {
labels: ['2019', '2020', '2021', '2022', '2023', '2024'],
datasets: [
{ label: 'Membri', data: [104, 113, 139, 140, 149, 156] },
{ label: 'Partner', data: [29, 30, 34, 33, 35, 34] },
{ label: 'IDP', data: [106, 113, 126, 145, 151, 159] },
{ label: 'SP', data: [116, 115, 121, 122, 131, 134] }
]
},
period2: {
labels: ['2014', '2015', '2016', '2017', '2018'],
datasets: [
{ label: 'Membri', data: [60, 70, 72, 77, 94] },
{ label: 'Partner', data: [24, 26, 27, 29, 29] },
{ label: 'IDP', data: [67, 74, 76, 79, 97] },
{ label: 'SP', data: [105, 114, 118, 125, 120] }
]
}
};
const eduroamData = {
labels: ['2014', '2015', '2016', '2017', '2018', '2019', '2020', '2021', '2022', '2023', '2024'],
data: [23000000, 43000000, 60000000, 79000000, 98000000, 133000000, 61000000, 74300000, 150000000, 192000000, 258000000]
};
const certificatesData = {
labels: ['2019', '2020', '2021', '2022', '2023', '2024'],
data: [7288, 6664, 58182, 37753, 35307, 107252]
};
const attacksData = {
2024: { UDP: 430, TCP: 4312 },
2023: { UDP: 392, TCP: 739 }
};
const incidentsData = {
'Piracy': 899,
'Vulnerability': 552,
'Data Breach': 185,
'Spam/Phishing': 138,
'Scan/Probe': 69,
'Altro': 60,
'Connection Attempt': 31,
'DoS': 27
};
// UPDATED: Domains by Organization Data with 2024 and 2023
const domainsByOrgData = {
2024: {
'Università': 120,
'CNR': 64,
'Altri enti': 21,
'INFN': 7,
'Altro': 6
},
2023: {
'Università': 102,
'CNR': 69,
'Altri enti': 24,
'INFN': 6,
'Altro': 6
}
};
const ipv4NetworksData = {
'Università': 574,
'INFN': 510,
'GARR': 1082,
'Altri enti di ricerca': 42,
'IRCCS': 36,
'AFAM': 6
};
const eduIdData = {
labels: ['2023', '2024'],
datasets: [
{ label: 'Istituti', data: [101, 106] },
{ label: 'Studenti', data: [686, 1307] }
]
};
// Chart instances
let nocChart, scarrChart, certChart, domainsChart, networksChart, idemChart, eduroamChart, devicesChart, certificatesChart, attacksChart, incidentsChart, domainsByOrgChart, ipv4NetworksChart, eduIdChart;
// Initialize NOC Chart
function createNocChart(period = 'period1') {
const ctx = document.getElementById('nocChart').getContext('2d');
const data = nocData[period];
if (nocChart) {
nocChart.destroy();
}
const datasets = data.datasets.map((dataset, index) => ({
label: dataset.label,
data: dataset.data,
backgroundColor: colorsServ.primary[index + 3],
borderColor: colorsServ.primary[index + 3],
borderWidth: 1,
borderRadius: 6,
borderSkipped: false
}));
nocChart = new Chart(ctx, {
type: 'bar',
data: {
labels: data.labels,
datasets: datasets
},
options: {
...defaultOptionsServ,
scales: {
x: { stacked: true, title: { display: true, text: 'Anno' } },
y: { stacked: true, beginAtZero: true, title: { display: true, text: 'Interventi effettuati' } }
}
}
});
}
// Initialize SCARR Chart
function createScarrChart() {
const ctx = document.getElementById('scarrChart').getContext('2d');
scarrChart = new Chart(ctx, {
type: 'bar',
data: {
labels: scarrData.labels,
datasets: [{
label: 'Scansioni di vulnerabilità',
data: scarrData.data,
backgroundColor: colorsServ.primary[1],
borderColor: colorsServ.primary[1],
borderWidth: 1,
borderRadius: 6,
borderSkipped: false
}]
},
options: {
...defaultOptionsServ,
scales: {
y: { beginAtZero: true, title: { display: true, text: 'Scansioni' } },
x: { title: { display: true, text: 'Anno' } }
}
}
});
}
// Initialize CERT Chart
function createCertChart() {
const ctx = document.getElementById('certChart').getContext('2d');
const datasets = certData.datasets.map((dataset, index) => ({
label: dataset.label,
data: dataset.data,
backgroundColor: colorsServ.primary[index + 3],
borderColor: colorsServ.primary[index + 3],
borderWidth: 1,
borderRadius: 6,
borderSkipped: false
}));
certChart = new Chart(ctx, {
type: 'bar',
data: {
labels: certData.labels,
datasets: datasets
},
options: {
...defaultOptionsServ,
scales: {
x: { stacked: true, title: { display: true, text: 'Anno' } },
y: { stacked: true, beginAtZero: true, title: { display: true, text: 'Segnalazioni' } }
}
}
});
}
// Initialize Domains Chart (only domains now)
function createDomainsChart(period = 'period1') {
const ctx = document.getElementById('domainsChart').getContext('2d');
const data = domainsData[period];
if (domainsChart) {
domainsChart.destroy();
}
const datasets = data.datasets.map((dataset, index) => ({
label: dataset.label,
data: dataset.data,
backgroundColor: colorsServ.primary[index],
borderColor: colorsServ.primary[index],
borderWidth: 1,
borderRadius: 6,
borderSkipped: false
}));
domainsChart = new Chart(ctx, {
type: 'bar',
data: {
labels: data.labels,
datasets: datasets
},
options: {
...defaultOptionsServ,
scales: {
y: { beginAtZero: true, title: { display: true, text: 'Interventi' } },
x: { title: { display: true, text: 'Anno' } }
}
}
});
}
// NEW: Initialize Networks Chart (only networks)
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: 'Reti IPv4 e IPv6',
data: data.data,
backgroundColor: colorsServ.primary[2],
borderColor: colorsServ.primary[2],
borderWidth: 1,
borderRadius: 6,
borderSkipped: false
}]
},
options: {
...defaultOptionsServ,
scales: {
y: { beginAtZero: true, title: { display: true, text: 'Reti assegnate' } },
x: { title: { display: true, text: 'Anno' } }
}
}
});
}
// Initialize IDEM Chart
function createIdemChart(period = 'period1') {
const ctx = document.getElementById('idemChart').getContext('2d');
const data = idemData[period];
if (idemChart) {
idemChart.destroy();
}
const datasets = data.datasets.map((dataset, index) => ({
label: dataset.label,
data: dataset.data,
backgroundColor: colorsServ.primary[index],
borderColor: colorsServ.primary[index],
borderWidth: 1,
borderRadius: 6,
borderSkipped: false,
stack: index < 2 ? 'Mep' : 'IeS' // Members/Partners stack, IDP/SP stack
}));
idemChart = new Chart(ctx, {
type: 'bar',
data: {
labels: data.labels,
datasets: datasets
},
options: {
...defaultOptionsServ,
scales: {
x: { stacked: true, title: { display: true, text: 'Anno' } },
y: { stacked: true, beginAtZero: true, title: { display: true, text: 'Adesioni' } }
}
}
});
}
// Initialize eduroam Chart
function createEduroamChart() {
const ctx = document.getElementById('eduroamChart').getContext('2d');
eduroamChart = new Chart(ctx, {
type: 'line',
data: {
labels: eduroamData.labels,
datasets: [{
label: 'Accessi Wi-Fi in roaming tramite eduroam',
data: eduroamData.data,
borderColor: colorsServ.primary[5],
backgroundColor: colorsServ.primary[5] + '20',
borderWidth: 3,
fill: true,
tension: 0.4,
pointRadius: 6,
pointHoverRadius: 8
}]
},
options: {
...defaultOptionsServ,
scales: {
y: {
beginAtZero: true,
title: { display: true, text: 'Accessi' },
ticks: {
callback: function(value) {
if (value >= 1000000) {
return (value / 1000000) + 'M';
}
return value.toLocaleString();
}
}
},
x: { title: { display: true, text: 'Anno' } }
}
}
});
}
// Initialize Devices Chart
function createDevicesChart(year = '2024') {
const ctx = document.getElementById('devicesChart').getContext('2d');
const selector = document.getElementById('devicesYear');
const data = selector.value.split(',').map(Number);
if (devicesChart) {
devicesChart.destroy();
}
devicesChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ['Italiani', 'Esteri'],
datasets: [{
data: data,
backgroundColor: [colorsServ.primary[0], colorsServ.primary[3]],
borderWidth: 3,
borderColor: '#ffffff',
hoverBorderWidth: 4,
hoverOffset: 10
}]
},
options: {
...defaultOptionsServ,
cutout: '50%',
plugins: {
...defaultOptionsServ.plugins,
tooltip: {
...defaultOptionsServ.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 Certificates Chart
function createCertificatesChart() {
const ctx = document.getElementById('certificatesChart').getContext('2d');
certificatesChart = new Chart(ctx, {
type: 'line',
data: {
labels: certificatesData.labels,
datasets: [{
label: 'Certificati digitali rilasciati',
data: certificatesData.data,
borderColor: colorsServ.primary[3],
backgroundColor: colorsServ.primary[3] + '20',
borderWidth: 3,
fill: true,
tension: 0.4,
pointRadius: 6,
pointHoverRadius: 8
}]
},
options: {
...defaultOptionsServ,
scales: {
y: { beginAtZero: true, title: { display: true, text: 'Certificati' } },
x: { title: { display: true, text: 'Anno' } }
}
}
});
}
// Initialize Attacks Chart
function createAttacksChart(year = '2024') {
const ctx = document.getElementById('attacksChart').getContext('2d');
const data = attacksData[year];
if (attacksChart) {
attacksChart.destroy();
}
attacksChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: Object.keys(data),
datasets: [{
data: Object.values(data),
backgroundColor: [colorsServ.primary[0], colorsServ.primary[3]],
borderWidth: 3,
borderColor: '#ffffff',
hoverBorderWidth: 4,
hoverOffset: 10
}]
},
options: {
...defaultOptionsServ,
cutout: '60%',
plugins: {
...defaultOptionsServ.plugins,
tooltip: {
...defaultOptionsServ.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 Incidents Chart
function createIncidentsChart() {
const ctx = document.getElementById('incidentsChart').getContext('2d');
incidentsChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: Object.keys(incidentsData),
datasets: [{
data: Object.values(incidentsData),
backgroundColor: colorsServ.primary,
borderWidth: 3,
borderColor: '#ffffff',
hoverBorderWidth: 4,
hoverOffset: 10
}]
},
options: {
...defaultOptionsServ,
cutout: '50%',
plugins: {
...defaultOptionsServ.plugins,
tooltip: {
...defaultOptionsServ.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}%)`;
}
}
}
}
}
});
}
// UPDATED: Initialize Domains by Organization Chart with year selection
function createDomainsByOrgChart(year = '2024') {
const ctx = document.getElementById('domainsByOrgChart').getContext('2d');
const data = domainsByOrgData[year];
if (domainsByOrgChart) {
domainsByOrgChart.destroy();
}
domainsByOrgChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: Object.keys(data),
datasets: [{
data: Object.values(data),
backgroundColor: colorsServ.primary,
borderWidth: 3,
borderColor: '#ffffff',
hoverBorderWidth: 4,
hoverOffset: 10
}]
},
options: {
...defaultOptionsServ,
cutout: '50%',
plugins: {
...defaultOptionsServ.plugins,
tooltip: {
...defaultOptionsServ.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 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: colorsServ.primary,
borderWidth: 3,
borderColor: '#ffffff',
hoverBorderWidth: 4,
hoverOffset: 10
}]
},
options: {
...defaultOptionsServ,
cutout: '50%',
plugins: {
...defaultOptionsServ.plugins,
tooltip: {
...defaultOptionsServ.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 edu.id Chart
function createEduIdChart() {
const ctx = document.getElementById('eduIdChart').getContext('2d');
const datasets = eduIdData.datasets.map((dataset, index) => ({
label: dataset.label,
data: dataset.data,
backgroundColor: colorsServ.primary[index],
borderColor: colorsServ.primary[index],
borderWidth: 1,
borderRadius: 6,
borderSkipped: false
}));
eduIdChart = new Chart(ctx, {
type: 'bar',
data: {
labels: eduIdData.labels,
datasets: datasets
},
options: {
...defaultOptionsServ,
scales: {
y: { beginAtZero: true, title: { display: true, text: 'Numero' } },
x: { title: { display: true, text: 'Anno' } }
}
}
});
}
// Event Listeners
document.getElementById('nocPeriod1').addEventListener('click', () => {
createNocChart('period1');
updateStats();
});
document.getElementById('nocPeriod2').addEventListener('click', () => {
createNocChart('period2');
updateStats();
});
document.getElementById('domainsPeriod1').addEventListener('click', () => {
createDomainsChart('period1');
updateStats();
});
document.getElementById('domainsPeriod2').addEventListener('click', () => {
createDomainsChart('period2');
updateStats();
});
// NEW: Networks chart event listeners
document.getElementById('networksPeriod1').addEventListener('click', () => {
createNetworksChart('period1');
updateStats();
});
document.getElementById('networksPeriod2').addEventListener('click', () => {
createNetworksChart('period2');
updateStats();
});
document.getElementById('idemPeriod1').addEventListener('click', () => {
createIdemChart('period1');
updateStats();
});
document.getElementById('idemPeriod2').addEventListener('click', () => {
createIdemChart('period2');
updateStats();
});
document.getElementById('devicesYear').addEventListener('change', () => {
createDevicesChart();
updateStats();
});
document.getElementById('attacksYear').addEventListener('change', () => {
const year = document.getElementById('attacksYear').options[document.getElementById('attacksYear').selectedIndex].text;
createAttacksChart(year);
updateStats();
});
// NEW: Domains by Organization year change listener
document.getElementById('domainsOrgYear').addEventListener('change', () => {
const year = document.getElementById('domainsOrgYear').value;
createDomainsByOrgChart(year);
updateStats();
});
// Download handlers
document.getElementById('downloadNoc').addEventListener('click', () => {
const link = document.createElement('a');
link.download = 'noc-guasti-manutenzioni.png';
link.href = nocChart.toBase64Image();
link.click();
});
document.getElementById('downloadScarr').addEventListener('click', () => {
const link = document.createElement('a');
link.download = 'scarr-vulnerability-scans.png';
link.href = scarrChart.toBase64Image();
link.click();
});
document.getElementById('downloadCert').addEventListener('click', () => {
const link = document.createElement('a');
link.download = 'cert-security-reports.png';
link.href = certChart.toBase64Image();
link.click();
});
document.getElementById('downloadDomains').addEventListener('click', () => {
const link = document.createElement('a');
link.download = 'domains-only.png';
link.href = domainsChart.toBase64Image();
link.click();
});
// NEW: Networks download handler
document.getElementById('downloadNetworks').addEventListener('click', () => {
const link = document.createElement('a');
link.download = 'networks-ipv4-ipv6.png';
link.href = networksChart.toBase64Image();
link.click();
});
document.getElementById('downloadIdem').addEventListener('click', () => {
const link = document.createElement('a');
link.download = 'idem-federation.png';
link.href = idemChart.toBase64Image();
link.click();
});
document.getElementById('downloadEduroam').addEventListener('click', () => {
const link = document.createElement('a');
link.download = 'eduroam-access.png';
link.href = eduroamChart.toBase64Image();
link.click();
});
document.getElementById('downloadDevices').addEventListener('click', () => {
const year = document.getElementById('devicesYear').options[document.getElementById('devicesYear').selectedIndex].text;
const link = document.createElement('a');
link.download = `eduroam-devices-${year}.png`;
link.href = devicesChart.toBase64Image();
link.click();
});
document.getElementById('downloadCertificates').addEventListener('click', () => {
const link = document.createElement('a');
link.download = 'digital-certificates.png';
link.href = certificatesChart.toBase64Image();
link.click();
});
document.getElementById('downloadAttacks').addEventListener('click', () => {
const year = document.getElementById('attacksYear').options[document.getElementById('attacksYear').selectedIndex].text;
const link = document.createElement('a');
link.download = `ddos-attacks-${year}.png`;
link.href = attacksChart.toBase64Image();
link.click();
});
document.getElementById('downloadIncidents').addEventListener('click', () => {
const link = document.createElement('a');
link.download = 'security-incidents-2024.png';
link.href = incidentsChart.toBase64Image();
link.click();
});
// UPDATED: Domains by Organization download handler with year
document.getElementById('downloadDomainsByOrg').addEventListener('click', () => {
const year = document.getElementById('domainsOrgYear').value;
const link = document.createElement('a');
link.download = `domains-by-organization-${year}.png`;
link.href = domainsByOrgChart.toBase64Image();
link.click();
});
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('downloadEduId').addEventListener('click', () => {
const link = document.createElement('a');
link.download = 'edu-id-registrations.png';
link.href = eduIdChart.toBase64Image();
link.click();
});
// UPDATED: Update stats to include domains by org year
function updateStats() {
const selectedOrgYear = document.getElementById('domainsOrgYear').value;
const orgData = domainsByOrgData[selectedOrgYear];
const totalOrgDomains = Object.values(orgData).reduce((a, b) => a + b, 0);
const stats = [
{ label: 'NOC Tickets (2024)', value: '1,847' },
{ label: 'Vulnerability Scans (2024)', value: '4,700' },
{ label: 'CERT Reports (2024)', value: '7,028' },
{ label: 'Digital Certificates (2024)', value: '107,252' },
{ label: 'eduroam Access (2024)', value: '258M' },
{ label: 'IDEM Members (2024)', value: '190' },
{ label: `Total Domains per ente (${selectedOrgYear})`, value: totalOrgDomains.toString() },
{ label: 'Networks (2024)', value: '25' },
{ label: 'edu.id Students (2024)', value: '1,307' }
];
document.getElementById('statsGridServ').innerHTML = stats.map(stat =>
`
${stat.value}
${stat.label}
`
).join('');
}
// Initialize all charts
createNocChart();
createScarrChart();
createCertChart();
createDomainsChart();
createNetworksChart(); // NEW
createIdemChart();
createEduroamChart();
createDevicesChart();
createCertificatesChart();
createAttacksChart();
createIncidentsChart();
createDomainsByOrgChart(); // Updated with year selection
createIPv4NetworksChart();
createEduIdChart();
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)';
});
});
Statistiche cloud
2024
2023
📊 download chart
2024
2023
📊 download chart
// Color palette
const colorsCloud = {
primary: ['#667eea', '#764ba2', '#3b82f6', '#06b6d4', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#ec4899', '#6366f1']
};
// Default options
const defaultOptionsCloud = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom',
labels: {
padding: 20,
usePointStyle: true,
font: {
size: 11,
family: "'Segoe UI', sans-serif"
}
}
},
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,
displaycolorsCloud: true
}
},
animation: {
duration: 1500,
easing: 'easeOutQuart'
}
};
// Options estese con percentuali per i grafici a torta cloud
const pieOptionsWithPercentagesCloud = {
...defaultOptionsCloud,
cutout: '50%',
plugins: {
...defaultOptionsCloud.plugins,
tooltip: {
...defaultOptionsCloud.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}%)`;
}
}
}
}
};
// Data
const dataTipologia = {
2024: {
"Disaster Recovery, Business Continuity": 1064,
"Servizi GARR": 1076,
"Sperimentazione ICT": 1208,
"Formazione/Didattica": 568,
"AI/ML Data Storage": 200,
"Calcolo": 4968,
"Servizi web": 307,
"Altro": 732
},
2023: {
"Disaster Recovery, Business Continuity": 524,
"Servizi GARR": 1304,
"Sperimentazione ICT": 459,
"Formazione/Didattica": 77,
"AI/ML Data Storage": 714,
"Calcolo": 3328,
"Servizi web": 235,
"Altro": 455
}
};
const dataComunita = {
2024: {
"GARR Sperimentazione": 1444,
"GARR Servizi": 1062,
"Ricerca scientifica": 2472,
"Ricerca biomedica": 2370,
"Università": 2356,
"Beni culturali": 195,
"Arti performative": 0,
"Scuola": 0,
"Altro": 72
},
2023: {
"GARR Sperimentazione": 1468,
"GARR Servizi": 565,
"Ricerca scientifica": 2211,
"Ricerca biomedica": 1307,
"Università": 1413,
"Beni culturali": 101,
"Arti performative": 6,
"Scuola": 8,
"Altro": 17
}
};
const dataObjectStorage = {
"GARR Sperimentazione": 800,
"GARR Servizi": 1600,
"Ricerca scientifica": 52200,
"Ricerca biomedica": 420000,
"Università": 209400,
"Beni culturali": 800,
"Arti performative": 0,
"Scuola": 0,
"Altro": 1200
};
let chartTipologia, chartComunita, chartObjectStorage;
function createChart(id, data, colorsCloud) {
const ctx = document.getElementById(id).getContext('2d');
const dataset = {
labels: Object.keys(data),
datasets: [{
data: Object.values(data),
backgroundColor: colorsCloud,
borderColor: '#fff',
borderWidth: 3,
hoverBorderWidth: 4,
hoverOffset: 10
}]
};
return new Chart(ctx, {
type: 'doughnut',
data: dataset,
options: pieOptionsWithPercentagesCloud
});
}
function updateChart(chart, data) {
chart.data.labels = Object.keys(data);
chart.data.datasets[0].data = Object.values(data);
chart.update();
}
function updateStats() {
// Totali 2024 per ogni dataset
const totalTipologia = Object.values(dataTipologia["2024"]).reduce((a,b) => a+b, 0);
const totalComunita = Object.values(dataComunita["2024"]).reduce((a,b) => a+b, 0);
const totalObjectStorage = Object.values(dataObjectStorage).reduce((a,b) => a+b, 0);
const stats = [
{ label: 'Totale vCPU per Tipologia (2024)', value: totalTipologia.toLocaleString() },
{ label: 'Totale vCPU per Comunità (2024)', value: totalComunita.toLocaleString() },
{ label: 'Totale Object Storage (GB)', value: (totalObjectStorage/1000).toFixed(1) + ' TB' },
{ label: 'Tipo con più vCPU (2024)', value: 'Calcolo' }
];
const container = document.getElementById('statsGridCloud');
container.innerHTML = stats.map(stat => `
${stat.value}
${stat.label}
`).join('');
}
document.addEventListener("DOMContentLoaded", () => {
// Initialize charts
chartTipologia = createChart("chartTipologia", dataTipologia["2024"], colorsCloud.primary);
chartComunita = createChart("chartComunita", dataComunita["2024"], colorsCloud.primary);
chartObjectStorage = createChart("chartObjectStorage", dataObjectStorage, colorsCloud.primary);
// Event listeners for year selectors
document.getElementById("yearTipologia").addEventListener("change", (e) => {
updateChart(chartTipologia, dataTipologia[e.target.value]);
updateStats();
});
document.getElementById("yearComunita").addEventListener("change", (e) => {
updateChart(chartComunita, dataComunita[e.target.value]);
updateStats();
});
// Download handlers
document.getElementById("downloadTipologia").addEventListener("click", () => {
const year = document.getElementById("yearTipologia").value;
const link = document.createElement('a');
link.download = `cloud-tipologia-${year}.png`;
link.href = chartTipologia.toBase64Image();
link.click();
});
document.getElementById("downloadComunita").addEventListener("click", () => {
const year = document.getElementById("yearComunita").value;
const link = document.createElement('a');
link.download = `cloud-comunita-${year}.png`;
link.href = chartComunita.toBase64Image();
link.click();
});
document.getElementById("downloadObjectStorage").addEventListener("click", () => {
const link = document.createElement('a');
link.download = 'cloud-object-storage-2024.png';
link.href = chartObjectStorage.toBase64Image();
link.click();
});
// Initialize stats
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)';
});
});
});
Statistiche applicazioni
// Color palette
const colorsApp = {
primary: ['#667eea', '#764ba2', '#3b82f6', '#06b6d4', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#ec4899', '#6366f1']
};
// Default options
const defaultOptionsApp = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom',
labels: {
padding: 20,
usePointStyle: true,
font: {
size: 11,
family: "'Segoe UI', sans-serif"
}
}
},
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,
displaycolorsApp: true
}
},
animation: {
duration: 1500,
easing: 'easeOutQuart'
}
};
// Line chart options
const lineOptions = {
...defaultOptionsApp,
scales: {
x: {
grid: {
color: 'rgba(0, 0, 0, 0.1)'
},
ticks: {
font: {
size: 11
}
}
},
y: {
grid: {
color: 'rgba(0, 0, 0, 0.1)'
},
ticks: {
font: {
size: 11
}
}
}
}
};
// Bar chart options
const barOptionsApp = {
...defaultOptionsApp,
scales: {
x: {
grid: {
color: 'rgba(0, 0, 0, 0.1)'
},
ticks: {
font: {
size: 11
}
}
},
y: {
grid: {
color: 'rgba(0, 0, 0, 0.1)'
},
ticks: {
font: {
size: 11
}
}
}
}
};
// Data
const dataMirror = {
labels: ['2012', '2013', '2014', '2015', '2016', '2017', '2018', '2019', '2020', '2021', '2022', '2023', '2024'],
datasets: [{
label: 'Traffico (PB)',
data: [7.3, 8.1, 7.4, 6.9, 6.8, 6.0, 5.8, 6.0, 4.5, 5.7, 3.6, 4.2, 7.7],
borderColor: colorsApp.primary[0],
backgroundColor: colorsApp.primary[0] + '20',
borderWidth: 3,
fill: true,
tension: 0.4,
pointRadius: 5,
pointHoverRadius: 8
}]
};
const dataFilesender = {
labels: ['2014', '2015', '2016', '2017', '2018', '2019', '2020', '2021', '2022', '2023', '2024'],
datasets: [{
label: 'File inviati',
data: [35000, 59000, 88000, 90400, 100580, 73600, 132900, 138000, 126000, 142000, 148000],
borderColor: colorsApp.primary[0],
backgroundColor: colorsApp.primary[0] + '20',
borderWidth: 3,
fill: true,
tension: 0.4,
pointRadius: 5,
pointHoverRadius: 8,
yAxisID: 'y'
}, {
label: 'Volume dati (TB)',
data: [null, null, null, null, null, null, null, 52, 66.1, 57.3, 90.3],
borderColor: colorsApp.primary[1],
backgroundColor: colorsApp.primary[1] + '20',
borderWidth: 3,
fill: false,
tension: 0.4,
pointRadius: 5,
pointHoverRadius: 8,
yAxisID: 'y1'
}]
};
const dataSpeedtest = {
labels: ['2019', '2020', '2021', '2022', '2023', '2024'],
datasets: [{
label: 'Misure',
data: [3650, 28950, 33500, 30000, 29000, 23000],
borderColor: colorsApp.primary[0],
backgroundColor: colorsApp.primary[0] + '20',
borderWidth: 3,
fill: false,
tension: 0.4,
pointRadius: 5,
pointHoverRadius: 8,
yAxisID: 'y'
}, {
label: 'Indirizzi IP unici',
data: [830, 11522, 20000, 14000, 13000, 11900],
borderColor: colorsApp.primary[1],
backgroundColor: colorsApp.primary[1] + '20',
borderWidth: 3,
fill: false,
tension: 0.4,
pointRadius: 5,
pointHoverRadius: 8,
yAxisID: 'y1'
}]
};
const dataGARRbox = {
labels: ['2019', '2020', '2021', '2022', '2023', '2024'],
datasets: [{
label: 'Organizzazioni',
data: [51, 53, 53, 55, 57, 60],
borderColor: colorsApp.primary[0],
backgroundColor: colorsApp.primary[0] + '20',
borderWidth: 3,
fill: false,
tension: 0.4,
pointRadius: 5,
pointHoverRadius: 8,
yAxisID: 'y'
}, {
label: 'Spazio assegnato (TB)',
data: [25.5, 25.7, 24.8, 27.7, 17, 19.9],
borderColor: colorsApp.primary[1],
backgroundColor: colorsApp.primary[1] + '20',
borderWidth: 3,
fill: false,
tension: 0.4,
pointRadius: 5,
pointHoverRadius: 8,
yAxisID: 'y1'
}]
};
const dataURLGARR = {
labels: ['2022', '2023', '2024'],
datasets: [{
label: 'Link creati',
data: [950, 2000, 3800],
backgroundColor: colorsApp.primary[0],
borderColor: colorsApp.primary[0],
borderWidth: 2,
yAxisID: 'y'
}, {
label: 'Visualizzazioni',
data: [44000, 200000, 458000],
backgroundColor: colorsApp.primary[1],
borderColor: colorsApp.primary[1],
borderWidth: 2,
yAxisID: 'y1'
}]
};
let chartMirror, chartFilesender, chartSpeedtest, chartGARRbox, chartURLGARR;
// Chart creation functions
function createLineChart(id, data, options = lineOptions) {
const ctx = document.getElementById(id).getContext('2d');
return new Chart(ctx, {
type: 'line',
data: data,
options: options
});
}
function createBarChart(id, data, options = barOptionsApp) {
const ctx = document.getElementById(id).getContext('2d');
return new Chart(ctx, {
type: 'bar',
data: data,
options: options
});
}
// Dual axis options
const dualAxisOptions = {
...lineOptions,
scales: {
...lineOptions.scales,
y1: {
type: 'linear',
display: true,
position: 'right',
grid: {
drawOnChartArea: false,
},
ticks: {
font: {
size: 11
}
}
}
}
};
function updateStatsApp() {
const stats = [
{ label: 'Mirror - Picco Traffico (2013)', value: '8,1 PB' },
{ label: 'Filesender - File 2024', value: '148.000' },
{ label: 'Speedtest - Picco Misure (2021)', value: '33.500' },
{ label: 'GARRbox - Organizzazioni 2024', value: '60' },
{ label: 'URL GARR - Link 2024', value: '3.800' },
{ label: 'URL GARR - Visualizzazioni 2024', value: '458.000' }
];
const container = document.getElementById('statsGridApp');
container.innerHTML = stats.map(stat => `
${stat.value}
${stat.label}
`).join('');
}
document.addEventListener("DOMContentLoaded", () => {
// Initialize charts
chartMirror = createLineChart("chartMirror", dataMirror);
chartFilesender = createLineChart("chartFilesender", dataFilesender, dualAxisOptions);
chartSpeedtest = createLineChart("chartSpeedtest", dataSpeedtest, dualAxisOptions);
chartGARRbox = createLineChart("chartGARRbox", dataGARRbox, dualAxisOptions);
chartURLGARR = createBarChart("chartURLGARR", dataURLGARR, {
...barOptionsApp,
scales: {
...barOptionsApp.scales,
y1: {
type: 'linear',
display: true,
position: 'right',
grid: {
drawOnChartArea: false,
},
ticks: {
font: {
size: 11
}
}
}
}
});
// Download handlers
document.getElementById("downloadMirror").addEventListener("click", () => {
const link = document.createElement('a');
link.download = 'garr-mirror-traffico.png';
link.href = chartMirror.toBase64Image();
link.click();
});
document.getElementById("downloadFilesender").addEventListener("click", () => {
const link = document.createElement('a');
link.download = 'garr-filesender-files.png';
link.href = chartFilesender.toBase64Image();
link.click();
});
document.getElementById("downloadSpeedtest").addEventListener("click", () => {
const link = document.createElement('a');
link.download = 'garr-speedtest-measurements.png';
link.href = chartSpeedtest.toBase64Image();
link.click();
});
document.getElementById("downloadGARRbox").addEventListener("click", () => {
const link = document.createElement('a');
link.download = 'garr-garrbox-usage.png';
link.href = chartGARRbox.toBase64Image();
link.click();
});
document.getElementById("downloadURLGARR").addEventListener("click", () => {
const link = document.createElement('a');
link.download = 'garr-url-links.png';
link.href = chartURLGARR.toBase64Image();
link.click();
});
// Initialize stats
updateStatsApp();
// 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)';
});
});
});
Statistiche videoconferenza e streaming
// Color palette
const colorsMul = {
primary: ['#667eea', '#764ba2', '#3b82f6', '#06b6d4', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#ec4899', '#6366f1']
};
// Default options
const defaultOptionsMul = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom',
labels: {
padding: 20,
usePointStyle: true,
font: {
size: 11,
family: "'Segoe UI', sans-serif"
}
}
},
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
}
},
animation: {
duration: 1500,
easing: 'easeOutQuart'
}
};
// Line chart options
const lineOptionsMul = {
...defaultOptionsMul,
scales: {
x: {
grid: {
color: 'rgba(0, 0, 0, 0.1)'
},
ticks: {
font: {
size: 11
}
}
},
y: {
display: false
},
y1: {
display: false
},
y2: {
display: false
}
}
};
// Data GARR Meet
const dataGARRMeet = {
labels: ['2020', '2021', '2022', '2023', '2024'],
datasets: [{
label: 'eduMeet - Picco',
data: [473, 337, 237, 305, 119],
backgroundColor: colorsMul.primary[0],
borderColor: colorsMul.primary[0],
borderWidth: 2
}, {
label: 'eduMeet - Media',
data: [158, 69, 35, 50, 50],
backgroundColor: colorsMul.primary[0] + '80',
borderColor: colorsMul.primary[0],
borderWidth: 2
}, {
label: 'OpenMeet - Picco',
data: [90, 150, 137, 124, 66],
backgroundColor: colorsMul.primary[1],
borderColor: colorsMul.primary[1],
borderWidth: 2
}, {
label: 'OpenMeet - Media',
data: [null, 29, 33, 26, 21],
backgroundColor: colorsMul.primary[1] + '80',
borderColor: colorsMul.primary[1],
borderWidth: 2
}, {
label: 'BlueMeet - Picco',
data: [null, 182, 254, 195, 200],
backgroundColor: colorsMul.primary[2],
borderColor: colorsMul.primary[2],
borderWidth: 2
}, {
label: 'BlueMeet - Media',
data: [null, 26, 30, 22, 26],
backgroundColor: colorsMul.primary[2] + '80',
borderColor: colorsMul.primary[2],
borderWidth: 2
}]
};
// Data GARR.tv crescita temporale
const dataGarrTv = {
labels: [
'Ago 2023', 'Set 2023', 'Ott 2023', 'Nov 2023', 'Dic 2023',
'Gen 2024', 'Feb 2024', 'Mar 2024', 'Apr 2024', 'Mag 2024',
'Giu 2024', 'Lug 2024', 'Ago 2024', 'Set 2024', 'Ott 2024',
'Nov 2024', 'Dic 2024'
],
datasets: [{
label: 'Utenti iscritti',
data: [0, 15, 35, 68, 95, 125, 180, 245, 320, 410, 520, 630, 720, 780, 814, 814, 814],
borderColor: '#667eea',
backgroundColor: '#667eea20',
borderWidth: 3,
fill: true,
tension: 0.4,
pointRadius: 4,
pointHoverRadius: 8,
yAxisID: 'y'
}, {
label: 'Canali',
label: 'Channels',
data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 9, 9, 10, 10, 10],
borderColor: '#f5576c',
backgroundColor: '#f5576c20',
borderWidth: 3,
fill: false,
tension: 0.4,
pointRadius: 4,
pointHoverRadius: 8,
yAxisID: 'y1'
}, {
label: 'Filmati Live 24h',
data: [0, 0, 1, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 7, 7, 7, 7],
borderColor: '#00a8ff',
backgroundColor: '#00a8ff20',
borderWidth: 3,
fill: false,
tension: 0.4,
pointRadius: 4,
pointHoverRadius: 8,
yAxisID: 'y1'
}, {
label: 'Video in mirror dalla federazione',
data: [0, 8, 22, 45, 75, 110, 150, 195, 245, 285, 315, 335, 350, 360, 365, 367, 367],
borderColor: '#00d2d3',
backgroundColor: '#00d2d320',
borderWidth: 3,
fill: false,
tension: 0.4,
pointRadius: 4,
pointHoverRadius: 8,
yAxisID: 'y2'
}]
};
let chartGARRMeet, chartGarrTv;
function createBarChart(id, data, options = defaultOptionsMul) {
const ctx = document.getElementById(id).getContext('2d');
return new Chart(ctx, {
type: 'bar',
data: data,
options: {
...options,
scales: {
x: {
grid: {
color: 'rgba(0, 0, 0, 0.1)'
},
ticks: {
font: {
size: 11
}
}
},
y: {
grid: {
color: 'rgba(0, 0, 0, 0.1)'
},
ticks: {
font: {
size: 11
}
}
}
}
}
});
}
function createLineChart(id, data, options = lineOptionsMul) {
const ctx = document.getElementById(id).getContext('2d');
return new Chart(ctx, {
type: 'line',
data: data,
options: options
});
}
function updateStatsMul() {
const statsMultimedia = [
{ label: 'GARR Meet - Picco eduMeet', value: '473' },
{ label: 'GARR Meet - BlueMeet Picco', value: '200' },
{ label: 'GARR.tv - Utenti iscritti', value: '814' },
{ label: 'GARR.tv - Canali', value: '10' },
{ label: 'GARR.tv - Video in mirror dalla federazione', value: '367' },
{ label: 'GARR.tv - Filmati Live 24h', value: '7' }
];
const containerMultimedia = document.getElementById('statsGridMultimedia');
containerMultimedia.innerHTML = statsMultimedia.map(stat => `
${stat.value}
${stat.label}
`).join('');
}
document.addEventListener("DOMContentLoaded", () => {
// Initialize charts
chartGARRMeet = createBarChart("chartGARRMeet", dataGARRMeet);
chartGarrTv = createLineChart("chartGarrTv", dataGarrTv, lineOptionsMul);
// Download handlers
document.getElementById("downloadGARRMeet").addEventListener("click", () => {
const link = document.createElement('a');
link.download = 'garr-meet-daily-average.png';
link.href = chartGARRMeet.toBase64Image();
link.click();
});
document.getElementById("downloadGarrTv").addEventListener("click", () => {
const link = document.createElement('a');
link.download = 'garr-tv-growth.png';
link.href = chartGarrTv.toBase64Image();
link.click();
});
// Initialize stats
updateStatsMul();
// 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)';
});
});
});
PERSONALE E ORGANIZZAZIONE
Statistiche personale e organizzazione
2024
2023
2022
2021
2020
2019
2018
📊 download chart
2024
2023
📊 download chart
2024
2023
2022
2021
2020
2019
2018
📊 download chart
2024
2023
2022
2021
2020
2019
2018
📊 download chart
// Default options
const defaultOptionsPers = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom',
labels: {
padding: 20,
usePointStyle: true,
font: {
size: 11,
family: "'Segoe UI', sans-serif"
}
}
},
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,
displayColors: true
}
},
animation: {
duration: 1500,
easing: 'easeOutQuart'
}
};
// Pie chart options with percentages only (for gender chart)
const pieOptionsPercentageOnlyPers = {
...defaultOptionsPers,
cutout: '50%',
plugins: {
...defaultOptionsPers.plugins,
tooltip: {
...defaultOptionsPers.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}: ${percentage}%`;
}
}
}
}
};
// Pie chart options with percentages (for other charts)
const pieOptionsWithPercentagesPers = {
...defaultOptionsPers,
cutout: '50%',
plugins: {
...defaultOptionsPers.plugins,
tooltip: {
...defaultOptionsPers.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}%)`;
}
}
}
}
};
// Bar chart options
const barOptionsPers = {
...defaultOptionsPers,
scales: {
x: {
grid: {
color: 'rgba(0, 0, 0, 0.1)'
},
ticks: {
font: {
size: 11
}
}
},
y: {
grid: {
color: 'rgba(0, 0, 0, 0.1)'
},
ticks: {
font: {
size: 11
}
}
}
}
};
// Data
const dataGenere = {
2024: { "Uomini": 70, "Donne": 30 },
2023: { "Uomini": 69.5, "Donne": 30.5 },
2022: { "Uomini": 66.2, "Donne": 33.8 },
2021: { "Uomini": 68, "Donne": 32 },
2020: { "Uomini": 68, "Donne": 32 },
2019: { "Uomini": 68, "Donne": 32 },
2018: { "Uomini": 69.2, "Donne": 30.8 }
};
const dataAnzianita = {
labels: ['