|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
|
|
const softwareData = [ |
|
|
{ id: 1, software: "CSI [Etabs, SAFE, SAP2000]", date: "July 9, 2020", cost: 12176.60, year: "2020" }, |
|
|
{ id: 2, software: "Plaxis", date: "September 1, 2020", cost: 5361.00, year: "2020" }, |
|
|
{ id: 3, software: "Tekla", date: "December 1, 2020", cost: 13503.40, year: "2020" }, |
|
|
{ id: 4, software: "CSI [Etabs, SAFE, SAP2000]", date: "July 9, 2021", cost: 11877.00, year: "2021" }, |
|
|
{ id: 5, software: "Plaxis", date: "September 1, 2021", cost: 5391.00, year: "2021" }, |
|
|
{ id: 6, software: "Tekla", date: "December 1, 2021", cost: 6868.60, year: "2021" }, |
|
|
{ id: 7, software: "CSI [Etabs, SAFE, SAP2000]", date: "August 10, 2022", cost: 13482.00, year: "2022" }, |
|
|
{ id: 8, software: "Plaxis", date: "September 5, 2022", cost: 5796.00, year: "2022" }, |
|
|
{ id: 9, software: "Tekla", date: "October 18, 2022", cost: 7130.37, year: "2022" }, |
|
|
{ id: 10, software: "CSI [Etabs, SAFE, SAP2000]", date: "July 4, 2023", cost: 11664.00, year: "2023" }, |
|
|
{ id: 11, software: "Plaxis", date: "September 21, 2023", cost: 6201.00, year: "2023" }, |
|
|
{ id: 12, software: "Tekla", date: "October 18, 2023", cost: 7792.20, year: "2023" }, |
|
|
{ id: 13, software: "CSI [Etabs, SAFE, SAP2000]", date: "July 4, 2024", cost: 11336.00, year: "2024" }, |
|
|
{ id: 14, software: "Plaxis", date: "September 18, 2024", cost: 7003.40, year: "2024" }, |
|
|
{ id: 15, software: "Tekla", date: "October 10, 2024", cost: 14963.91, year: "2024" }, |
|
|
{ id: 16, software: "CSI [Etabs, SAFE, SAP2000]", date: "May 22, 2025", cost: 11336.00, year: "2025" }, |
|
|
{ id: 17, software: "Unreal Engine", date: "September 6, 2024", cost: 2727.18, year: "2024" }, |
|
|
{ id: 18, software: "Plaxis", date: "September 18, 2025", cost: 7752.84, year: "2025" }, |
|
|
{ id: 19, software: "Tekla", date: "November 26, 2025", cost: 15467.10, year: "2025" }, |
|
|
{ id: 20, software: "Unreal Engine", date: "September 6, 2025", cost: 2744.62, year: "2025" } |
|
|
]; |
|
|
|
|
|
const currentYear = new Date().getFullYear().toString(); |
|
|
const currentYearSpend = softwareData |
|
|
.filter(item => item.year === currentYear) |
|
|
.reduce((sum, item) => sum + item.cost, 0); |
|
|
|
|
|
|
|
|
const options = { year: 'numeric', month: 'long', day: 'numeric' }; |
|
|
document.getElementById('current-date').textContent = new Date().toLocaleDateString('en-SG', options); |
|
|
document.getElementById('current-year').textContent = `SGD ${currentYearSpend.toLocaleString('en-SG', {minimumFractionDigits: 2, maximumFractionDigits: 2})}`; |
|
|
|
|
|
const totalSpend = softwareData.reduce((sum, item) => sum + item.cost, 0); |
|
|
const years = [...new Set(softwareData.map(item => item.year))]; |
|
|
const avgAnnual = totalSpend / years.length; |
|
|
|
|
|
|
|
|
const softwareGroups = {}; |
|
|
softwareData.forEach(item => { |
|
|
if (!softwareGroups[item.software]) { |
|
|
softwareGroups[item.software] = 0; |
|
|
} |
|
|
softwareGroups[item.software] += item.cost; |
|
|
}); |
|
|
const mostExpensive = Object.entries(softwareGroups).reduce((a, b) => a[1] > b[1] ? a : b); |
|
|
|
|
|
|
|
|
document.getElementById('total-spend').textContent = `SGD ${totalSpend.toLocaleString('en-SG', {minimumFractionDigits: 2, maximumFractionDigits: 2})}`; |
|
|
document.getElementById('avg-annual').textContent = `SGD ${avgAnnual.toLocaleString('en-SG', {minimumFractionDigits: 2, maximumFractionDigits: 2})}`; |
|
|
document.getElementById('most-expensive').textContent = `${mostExpensive[0]} (SGD ${mostExpensive[1].toLocaleString('en-SG', {minimumFractionDigits: 2, maximumFractionDigits: 2})})`; |
|
|
|
|
|
|
|
|
const yearlyData = {}; |
|
|
softwareData.forEach(item => { |
|
|
if (!yearlyData[item.year]) { |
|
|
yearlyData[item.year] = 0; |
|
|
} |
|
|
yearlyData[item.year] += item.cost; |
|
|
}); |
|
|
|
|
|
const yearlyLabels = Object.keys(yearlyData).sort(); |
|
|
const yearlyValues = yearlyLabels.map(year => yearlyData[year]); |
|
|
|
|
|
const ctx = document.getElementById('yearly-chart').getContext('2d'); |
|
|
new Chart(ctx, { |
|
|
type: 'bar', |
|
|
data: { |
|
|
labels: yearlyLabels, |
|
|
datasets: [{ |
|
|
label: 'Yearly Software Spend (SGD)', |
|
|
data: yearlyValues, |
|
|
backgroundColor: '#3B82F6', |
|
|
borderColor: '#2563EB', |
|
|
borderWidth: 1 |
|
|
}] |
|
|
}, |
|
|
options: { |
|
|
responsive: true, |
|
|
maintainAspectRatio: false, |
|
|
scales: { |
|
|
y: { |
|
|
beginAtZero: true, |
|
|
ticks: { |
|
|
callback: function(value) { |
|
|
return 'SGD ' + value.toLocaleString('en-SG'); |
|
|
} |
|
|
} |
|
|
} |
|
|
}, |
|
|
plugins: { |
|
|
tooltip: { |
|
|
callbacks: { |
|
|
label: function(context) { |
|
|
return 'SGD ' + context.raw.toLocaleString('en-SG'); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
const currentYearTable = document.getElementById('current-year-table'); |
|
|
const currentYearItems = softwareData.filter(item => item.year === currentYear); |
|
|
|
|
|
currentYearItems.forEach(item => { |
|
|
const row = document.createElement('tr'); |
|
|
row.innerHTML = ` |
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${item.software}</td> |
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${item.date}</td> |
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${item.cost.toLocaleString('en-SG', {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td> |
|
|
`; |
|
|
currentYearTable.appendChild(row); |
|
|
}); |
|
|
|
|
|
|
|
|
document.getElementById('yearly-view').addEventListener('click', function() { |
|
|
|
|
|
alert('Yearly view would show aggregated data by year'); |
|
|
}); |
|
|
|
|
|
document.getElementById('software-view').addEventListener('click', function() { |
|
|
|
|
|
alert('Software view would show data grouped by software'); |
|
|
}); |
|
|
}); |