Files
finance-dashboard/app/static/js/dashboard.js
T

40 lines
2.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
(() => {
const status = document.getElementById('chart-status');
if (typeof Chart === 'undefined') {
status.textContent = 'Chart.js konnte nicht vom CDN geladen werden. Alle Werte bleiben in den Tabellen verfügbar.';
return;
}
const data = JSON.parse(document.getElementById('chart-data').textContent);
const euro = cents => new Intl.NumberFormat('de-DE', {style: 'currency', currency: 'EUR'}).format(cents / 100);
const palette = ['#72e2b0','#79b6ff','#f4c272','#bc9cfa','#f691aa','#67cbd0','#e5db89','#9ec28b','#b2bdec','#daaa81'];
Chart.defaults.color = '#a4b3c7';
Chart.defaults.borderColor = '#293548';
Chart.defaults.font.family = 'system-ui, sans-serif';
new Chart(document.getElementById('monthly-chart'), {
type: 'line',
data: {labels: data.months, datasets: data.years.map((year, i) => ({...year, borderColor: palette[i % palette.length], backgroundColor: palette[i % palette.length], tension: 0.2, pointRadius: 3}))},
options: {responsive:true, maintainAspectRatio:false, animation:false, interaction:{mode:'index',intersect:false},
scales:{y:{ticks:{callback:euro},title:{display:true,text:'Euro'}}}, plugins:{tooltip:{callbacks:{label:ctx => `${ctx.dataset.label}: ${euro(ctx.raw)}`}}}}
});
function shares(id, rows) {
// Signed corrections cannot be represented truthfully as pie slices.
const negative = rows.some(row => row.amount < 0);
const total = rows.reduce((sum,row) => sum + row.amount, 0);
new Chart(document.getElementById(id), {
type: negative ? 'bar' : 'doughnut',
data:{labels:rows.map(row => row.name),datasets:[{data:rows.map(row => row.amount),backgroundColor:rows.map((_,i) => palette[i % palette.length]),borderWidth:0}]},
options:{responsive:true,maintainAspectRatio:false,animation:false,
...(negative ? {scales:{y:{ticks:{callback:euro}}}} : {cutout:'68%'}),
plugins:{legend:{display:!negative,position:'bottom',labels:{boxWidth:10,font:{size:11}}},tooltip:{callbacks:{label:ctx => {
const amount = rows[ctx.dataIndex].amount;
const share = total === 0 ? '' : new Intl.NumberFormat('de-DE',{minimumFractionDigits:2,maximumFractionDigits:2}).format(amount / total * 100) + ' %';
return `${ctx.label}: ${euro(amount)} (${share})`;
}}}}}
});
}
shares('shares-chart', data.shares);
shares('kinds-chart', data.kinds);
status.textContent = data.years.some(year => year.data.some(value => value !== 0)) ? 'Diagramme zeigen tatsächlich erhaltene Einnahmen. Negative Positionssummen werden als Balken dargestellt.' : 'Noch keine tatsächlichen Einnahmen vorhanden.';
})();