06/05 Optimize app
This commit is contained in:
@@ -58,6 +58,17 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Budget vs Actual chart -->
|
||||
{% set chart_cats = summary | selectattr('has_budget') | list %}
|
||||
{% if chart_cats %}
|
||||
<div class="pcard mb-4">
|
||||
<div style="font-size:13px;font-weight:600;margin-bottom:12px;">Budget vs Actual</div>
|
||||
<div style="position:relative;height:{{ [[chart_cats|length * 42, 180]|max, 380]|min }}px;">
|
||||
<canvas id="budgetChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Budget Items -->
|
||||
{% if summary %}
|
||||
<div class="pcard p-0">
|
||||
@@ -148,3 +159,74 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
{% set chart_cats = summary | selectattr('has_budget') | list %}
|
||||
{% if chart_cats %}
|
||||
<script>
|
||||
(function() {
|
||||
const labels = {{ chart_cats | map(attribute='category') | map(attribute='name') | list | tojson }};
|
||||
const spent = {{ chart_cats | map(attribute='spent') | list | tojson }};
|
||||
const limits = {{ chart_cats | map(attribute='limit') | list | tojson }};
|
||||
const colors = {{ chart_cats | map(attribute='category') | map(attribute='color') | list | tojson }};
|
||||
|
||||
const ctx = document.getElementById('budgetChart');
|
||||
if (!ctx) return;
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [
|
||||
{
|
||||
label: 'Spent',
|
||||
data: spent,
|
||||
backgroundColor: colors.map((c, i) => {
|
||||
const pct = limits[i] > 0 ? spent[i] / limits[i] : 0;
|
||||
return pct >= 1 ? '#ef4444cc' : pct >= 0.8 ? '#f59e0bcc' : '#10b981cc';
|
||||
}),
|
||||
borderRadius: 4,
|
||||
barPercentage: 0.55,
|
||||
categoryPercentage: 0.9,
|
||||
},
|
||||
{
|
||||
label: 'Budget',
|
||||
data: limits,
|
||||
backgroundColor: '#e2e8f0cc',
|
||||
borderRadius: 4,
|
||||
barPercentage: 0.55,
|
||||
categoryPercentage: 0.9,
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: { position: 'top', labels: { boxWidth: 10, font: { size: 11 } } },
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: ctx => {
|
||||
const sym = '{{ current_user.currency_symbol }}';
|
||||
return ` ${ctx.dataset.label}: ${sym}${ctx.parsed.x.toLocaleString('en-US', {minimumFractionDigits:2, maximumFractionDigits:2})}`;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
beginAtZero: true,
|
||||
grid: { color: '#f1f5f9' },
|
||||
ticks: {
|
||||
font: { size: 10 },
|
||||
callback: v => '{{ current_user.currency_symbol }}' + v.toLocaleString(),
|
||||
},
|
||||
},
|
||||
y: { ticks: { font: { size: 11 } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user