v1.6 - Camembert sur Dashboard
This commit is contained in:
@@ -53,7 +53,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h2>📈 Graphique</h2>
|
<h2>📈 Graphiques</h2>
|
||||||
|
<div class="filter-bar" id="chart-filters" style="margin-bottom:15px; font-size:0.85em">
|
||||||
|
<div class="filter-chip active" onclick="setChartMode('bar')">Bar chart</div>
|
||||||
|
<div class="filter-chip" onclick="setChartMode('pie')">Camembert</div>
|
||||||
|
</div>
|
||||||
<div class="chart-container">
|
<div class="chart-container">
|
||||||
<canvas id="mainChart"></canvas>
|
<canvas id="mainChart"></canvas>
|
||||||
</div>
|
</div>
|
||||||
@@ -62,6 +66,7 @@
|
|||||||
<script>
|
<script>
|
||||||
var depenses = [];
|
var depenses = [];
|
||||||
var currentFilter = { type: 'all', value: null };
|
var currentFilter = { type: 'all', value: null };
|
||||||
|
var chartMode = 'bar';
|
||||||
var chart = null;
|
var chart = null;
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
@@ -72,6 +77,12 @@
|
|||||||
updateChart();
|
updateChart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setChartMode(mode) {
|
||||||
|
chartMode = mode;
|
||||||
|
document.getElementById('chart-filters').innerHTML = '<div class="filter-chip' + (mode === 'bar' ? ' active' : '') + '" onclick="setChartMode('\''+mode+'\'')">Bar chart</div><div class="filter-chip' + (mode === 'pie' ? ' active' : '') + '" onclick="setChartMode('\''+mode+'\'')">Camembert</div>';
|
||||||
|
updateChart();
|
||||||
|
}
|
||||||
|
|
||||||
function renderFilters() {
|
function renderFilters() {
|
||||||
var bars = [
|
var bars = [
|
||||||
{ id: 'byMonth', label: 'Mois', type: 'month' },
|
{ id: 'byMonth', label: 'Mois', type: 'month' },
|
||||||
@@ -88,7 +99,7 @@
|
|||||||
function setFilter(type) {
|
function setFilter(type) {
|
||||||
currentFilter.type = type;
|
currentFilter.type = type;
|
||||||
renderFilters();
|
renderFilters();
|
||||||
|
setChartMode('bar');
|
||||||
var values = [];
|
var values = [];
|
||||||
if (type === 'month') {
|
if (type === 'month') {
|
||||||
values = [...new Set(depenses.map(d => d.date.split('-')[0] + '-' + d.date.split('-')[1]))].sort().reverse();
|
values = [...new Set(depenses.map(d => d.date.split('-')[0] + '-' + d.date.split('-')[1]))].sort().reverse();
|
||||||
@@ -97,7 +108,6 @@
|
|||||||
} else if (type === 'category') {
|
} else if (type === 'category') {
|
||||||
values = [...new Set(depenses.map(d => d.category || 'Autre'))].sort();
|
values = [...new Set(depenses.map(d => d.category || 'Autre'))].sort();
|
||||||
}
|
}
|
||||||
|
|
||||||
currentFilter.value = values[0] || null;
|
currentFilter.value = values[0] || null;
|
||||||
renderValues();
|
renderValues();
|
||||||
renderExpenses();
|
renderExpenses();
|
||||||
@@ -162,7 +172,48 @@
|
|||||||
var labels = [];
|
var labels = [];
|
||||||
var data = [];
|
var data = [];
|
||||||
var backgroundColors = [];
|
var backgroundColors = [];
|
||||||
|
var borderColors = [];
|
||||||
|
|
||||||
|
if (chartMode === 'pie') {
|
||||||
|
if (currentFilter.type === 'person') {
|
||||||
|
var persons = {};
|
||||||
|
for (var i = 0; i < filtered.length; i++) {
|
||||||
|
var d = filtered[i];
|
||||||
|
var p = d.prenom || 'Inconnu';
|
||||||
|
if (!persons[p]) persons[p] = 0;
|
||||||
|
persons[p] += parseFloat(d.montant) || 0;
|
||||||
|
}
|
||||||
|
Object.keys(persons).sort().forEach(function(p) {
|
||||||
|
labels.push(p);
|
||||||
|
data.push(persons[p]);
|
||||||
|
backgroundColors.push('rgba(233, 69, 96, 0.7)');
|
||||||
|
borderColors.push('rgba(233, 69, 96, 1)');
|
||||||
|
});
|
||||||
|
} else if (currentFilter.type === 'category') {
|
||||||
|
var categories = {};
|
||||||
|
for (var i = 0; i < filtered.length; i++) {
|
||||||
|
var d = filtered[i];
|
||||||
|
var c = d.category || 'Autre';
|
||||||
|
if (!categories[c]) categories[c] = 0;
|
||||||
|
categories[c] += parseFloat(d.montant) || 0;
|
||||||
|
}
|
||||||
|
var colors = [
|
||||||
|
'rgba(0, 217, 255, 0.7)', 'rgba(233, 69, 96, 0.7)', 'rgba(123, 44, 191, 0.7)',
|
||||||
|
'rgba(0, 255, 136, 0.7)', 'rgba(255, 200, 0, 0.7)', 'rgba(255, 71, 87, 0.7)', 'rgba(153, 68, 204, 0.7)'
|
||||||
|
];
|
||||||
|
Object.keys(categories).sort().forEach(function(c, idx) {
|
||||||
|
labels.push(c);
|
||||||
|
data.push(categories[c]);
|
||||||
|
backgroundColors.push(colors[idx % colors.length]);
|
||||||
|
borderColors.push(colors[idx % colors.length].replace('0.7', '1'));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
labels.push('Mois actuel');
|
||||||
|
data.push(filtered.reduce(function(s, d) { return s + (parseFloat(d.montant) || 0); }, 0));
|
||||||
|
backgroundColors.push('rgba(0, 217, 255, 0.7)');
|
||||||
|
borderColors.push('rgba(0, 217, 255, 1)');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (currentFilter.type === 'month') {
|
if (currentFilter.type === 'month') {
|
||||||
var months = {};
|
var months = {};
|
||||||
for (var i = 0; i < filtered.length; i++) {
|
for (var i = 0; i < filtered.length; i++) {
|
||||||
@@ -175,6 +226,7 @@
|
|||||||
labels.push(m);
|
labels.push(m);
|
||||||
data.push(months[m]);
|
data.push(months[m]);
|
||||||
backgroundColors.push('rgba(0, 217, 255, 0.7)');
|
backgroundColors.push('rgba(0, 217, 255, 0.7)');
|
||||||
|
borderColors.push('rgba(0, 217, 255, 1)');
|
||||||
});
|
});
|
||||||
} else if (currentFilter.type === 'person') {
|
} else if (currentFilter.type === 'person') {
|
||||||
var persons = {};
|
var persons = {};
|
||||||
@@ -188,6 +240,7 @@
|
|||||||
labels.push(p);
|
labels.push(p);
|
||||||
data.push(persons[p]);
|
data.push(persons[p]);
|
||||||
backgroundColors.push('rgba(233, 69, 96, 0.7)');
|
backgroundColors.push('rgba(233, 69, 96, 0.7)');
|
||||||
|
borderColors.push('rgba(233, 69, 96, 1)');
|
||||||
});
|
});
|
||||||
} else if (currentFilter.type === 'category') {
|
} else if (currentFilter.type === 'category') {
|
||||||
var categories = {};
|
var categories = {};
|
||||||
@@ -197,23 +250,29 @@
|
|||||||
if (!categories[c]) categories[c] = 0;
|
if (!categories[c]) categories[c] = 0;
|
||||||
categories[c] += parseFloat(d.montant) || 0;
|
categories[c] += parseFloat(d.montant) || 0;
|
||||||
}
|
}
|
||||||
Object.keys(categories).sort().forEach(function(c) {
|
var colors = [
|
||||||
|
'rgba(0, 217, 255, 0.7)', 'rgba(233, 69, 96, 0.7)', 'rgba(123, 44, 191, 0.7)',
|
||||||
|
'rgba(0, 255, 136, 0.7)', 'rgba(255, 200, 0, 0.7)', 'rgba(255, 71, 87, 0.7)', 'rgba(153, 68, 204, 0.7)'
|
||||||
|
];
|
||||||
|
Object.keys(categories).sort().forEach(function(c, idx) {
|
||||||
labels.push(c);
|
labels.push(c);
|
||||||
data.push(categories[c]);
|
data.push(categories[c]);
|
||||||
backgroundColors.push('rgba(123, 44, 191, 0.7)');
|
backgroundColors.push(colors[idx % colors.length]);
|
||||||
|
borderColors.push(colors[idx % colors.length].replace('0.7', '1'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (chart) chart.destroy();
|
if (chart) chart.destroy();
|
||||||
chart = new Chart(ctx, {
|
chart = new Chart(ctx, {
|
||||||
type: 'bar',
|
type: chartMode,
|
||||||
data: {
|
data: {
|
||||||
labels: labels,
|
labels: labels,
|
||||||
datasets: [{
|
datasets: [{
|
||||||
label: 'Montant (€)',
|
label: 'Montant (€)',
|
||||||
data: data,
|
data: data,
|
||||||
backgroundColor: backgroundColors,
|
backgroundColor: backgroundColors,
|
||||||
borderColor: backgroundColors.map(c => c.replace('0.7', '1')),
|
borderColor: borderColors,
|
||||||
borderWidth: 1
|
borderWidth: 1
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
@@ -221,14 +280,16 @@
|
|||||||
responsive: true,
|
responsive: true,
|
||||||
maintainAspectRatio: false,
|
maintainAspectRatio: false,
|
||||||
plugins: {
|
plugins: {
|
||||||
legend: { display: false },
|
legend: {
|
||||||
|
position: 'right',
|
||||||
|
labels: { color: '#fff', padding: 15, font: { size: 12 } }
|
||||||
|
},
|
||||||
title: {
|
title: {
|
||||||
display: true,
|
display: true,
|
||||||
text: currentFilter.type === 'month' ? 'Dépenses par mois' :
|
text: chartMode === 'pie' ? 'Répartition par ' + (currentFilter.type === 'month' ? 'Mois' : currentFilter.type === 'person' ? 'Personne' : 'Catégorie') : ''
|
||||||
currentFilter.type === 'person' ? 'Dépenses par personne' : 'Dépenses par catégorie'
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
scales: {
|
scales: chartMode === 'pie' ? {} : {
|
||||||
y: { beginAtZero: true, grid: { color: 'rgba(255,255,255,0.1)' }, ticks: { color: '#888' } },
|
y: { beginAtZero: true, grid: { color: 'rgba(255,255,255,0.1)' }, ticks: { color: '#888' } },
|
||||||
x: { grid: { display: false }, ticks: { color: '#888' } }
|
x: { grid: { display: false }, ticks: { color: '#888' } }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user