diff --git a/templates/admin/stats.html.twig b/templates/admin/stats.html.twig index 31533d3e..ca7ef263 100644 --- a/templates/admin/stats.html.twig +++ b/templates/admin/stats.html.twig @@ -152,7 +152,7 @@ } #stats-table thead th { - background: #f8f9fa; + background:rgb(255, 255, 255); border-bottom: 2px solid #dee2e6; box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.1); padding: 0.75rem; @@ -706,16 +706,16 @@
Comment est calculé le score de complétion ?
-Le score de complétion est calculé en fonction de plusieurs critères :
Chaque critère rempli augmente le score de complétion d'une part égale. Un commerce parfaitement renseigné aura un score de 100%.
@@ -1220,15 +1220,19 @@ console.log('pas de completionCtx'); } else { new Chart(completionCtx, { - type: 'bar', + type: 'line', data: { labels: completionLabels, datasets: [{ - label: 'Évolution du taux de complétion', + label: 'Décompte des objets par tranches de complétion', data: completionValues, - backgroundColor: 'rgba(75, 192, 192, 0.5)', + backgroundColor: 'rgba(75, 192, 192, 0.1)', borderColor: 'rgba(75, 192, 192, 1)', - borderWidth: 1 + borderWidth: 2, + tension: 0.3, + fill: false, + pointRadius: 4, + pointHoverRadius: 6 }] }, options: { @@ -1241,7 +1245,7 @@ plugins: { title: { display: true, - text: 'Évolution du taux de complétion', + text: 'Décompte des objets par tranches de complétion', font: { size: 16 } diff --git a/templates/admin/stats_history.html.twig b/templates/admin/stats_history.html.twig index 39584145..f2721054 100644 --- a/templates/admin/stats_history.html.twig +++ b/templates/admin/stats_history.html.twig @@ -75,82 +75,85 @@ document.addEventListener('DOMContentLoaded', function() { ]; const completionStat = {{stat.getCompletionPercent()}} - new Chart(ctx, { + // Fonction pour créer les données avec labels uniquement sur le dernier point + function createDatasetWithLastLabel(label, data, borderColor, backgroundColor, borderWidth, hidden) { + const lastIndex = data.length - 1; + return { + label: label, + data: data, + borderColor: borderColor, + backgroundColor: backgroundColor, + tension: 0.3, + fill: false, + borderWidth: borderWidth, + hidden: hidden, + pointRadius: function(context) { + // Afficher un point plus grand uniquement sur le dernier point + return context.dataIndex === lastIndex ? 5 : 3; + }, + pointHoverRadius: function(context) { + return context.dataIndex === lastIndex ? 7 : 5; + } + }; + } + + const chart = new Chart(ctx, { type: 'line', data: { labels: labels, datasets: [ - { - label: 'Taux de complétion global (%)', - data: completionData, - borderColor: 'rgb(75, 192, 192)', - backgroundColor: 'rgba(75, 192, 192, 0.1)', - tension: 0.3, - fill: false, - borderWidth: 3 - }, - { - label: 'Horaires d\'ouverture (%)', - data: openingHoursData, - borderColor: 'rgb(255, 99, 132)', - backgroundColor: 'rgba(255, 99, 132, 0.1)', - tension: 0.3, - fill: false, - borderWidth: 2 - }, - { - label: 'Adresses (%)', - data: addressData, - borderColor: 'rgb(54, 162, 235)', - backgroundColor: 'rgba(54, 162, 235, 0.1)', - tension: 0.3, - fill: false, - borderWidth: 2 - }, - { - label: 'Sites web (%)', - data: websiteData, - borderColor: 'rgb(255, 205, 86)', - backgroundColor: 'rgba(255, 205, 86, 0.1)', - tension: 0.3, - fill: false, - borderWidth: 2 - }, - { - label: 'SIRET (%)', - data: siretData, - borderColor: 'rgb(153, 102, 255)', - backgroundColor: 'rgba(153, 102, 255, 0.1)', - tension: 0.3, - fill: false, - borderWidth: 2 - }, - { - label: 'Emails (%)', - data: emailData, - borderColor: 'rgb(199, 199, 199)', - backgroundColor: 'rgba(199, 199, 199, 0.1)', - tension: 0.3, - fill: false, - borderWidth: 2 - } + createDatasetWithLastLabel( + 'Taux de complétion global (%)', + completionData, + 'rgb(75, 192, 192)', + 'rgba(75, 192, 192, 0.1)', + 3, + false + ), + createDatasetWithLastLabel( + 'Horaires d\'ouverture (%)', + openingHoursData, + 'rgb(255, 99, 132)', + 'rgba(255, 99, 132, 0.1)', + 2, + false + ), + createDatasetWithLastLabel( + 'Adresses (%)', + addressData, + 'rgb(54, 162, 235)', + 'rgba(54, 162, 235, 0.1)', + 2, + false + ), + createDatasetWithLastLabel( + 'Sites web (%)', + websiteData, + 'rgb(255, 205, 86)', + 'rgba(255, 205, 86, 0.1)', + 2, + false + ), + createDatasetWithLastLabel( + 'SIRET (%)', + siretData, + 'rgb(153, 102, 255)', + 'rgba(153, 102, 255, 0.1)', + 2, + false + ), + createDatasetWithLastLabel( + 'Emails (%)', + emailData, + 'rgb(199, 199, 199)', + 'rgba(199, 199, 199, 0.1)', + 2, + false + ) ] }, options: { responsive: true, - plugins: { - title: { - display: true, - text: 'Évolution des taux de complétion dans le temps => '+completionStat - }, - legend: { - position: 'top', - labels: { - usePointStyle: true, - padding: 20 - } - } - }, scales: { y: { beginAtZero: true, @@ -170,6 +173,78 @@ document.addEventListener('DOMContentLoaded', function() { interaction: { intersect: false, mode: 'index' + }, + plugins: { + title: { + display: true, + text: 'Évolution des taux de complétion dans le temps => '+completionStat + }, + legend: { + position: 'top', + labels: { + usePointStyle: true, + padding: 20 + }, + onClick: function(e, legendItem, legend) { + const index = legendItem.datasetIndex; + const chart = legend.chart; + const meta = chart.getDatasetMeta(index); + + // Basculer la visibilité + meta.hidden = meta.hidden === null ? !chart.data.datasets[index].hidden : null; + + // Mettre à jour le graphique + chart.update(); + } + }, + tooltip: { + enabled: true + } + }, + animation: { + onComplete: function() { + const chart = this.chart; + const ctx = chart.ctx; + const lastIndex = labels.length - 1; + + chart.data.datasets.forEach((dataset, datasetIndex) => { + const meta = chart.getDatasetMeta(datasetIndex); + if (meta.hidden) return; + + const lastPoint = meta.data[lastIndex]; + if (!lastPoint) return; + + const value = dataset.data[lastIndex]; + const x = lastPoint.x; + const y = lastPoint.y; + + // Style du texte avec fond pour meilleure lisibilité + ctx.save(); + ctx.font = 'bold 11px Arial'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'bottom'; + + const text = value.toFixed(1) + '%'; + const textMetrics = ctx.measureText(text); + const textWidth = textMetrics.width; + const textHeight = 14; + const padding = 4; + + // Dessiner un rectangle de fond avec la couleur de la courbe + ctx.fillStyle = dataset.borderColor; + ctx.fillRect( + x - textWidth / 2 - padding, + y - textHeight - padding - 8, + textWidth + padding * 2, + textHeight + padding * 2 + ); + + // Dessiner le texte en blanc + ctx.fillStyle = '#ffffff'; + ctx.fillText(text, x, y - 8); + ctx.restore(); + }); + } } } });