panel latéral sur graphe avancé

This commit is contained in:
Tykayn 2025-07-16 17:34:13 +02:00 committed by tykayn
parent 2e459122b5
commit 0aa050b38b
3 changed files with 74 additions and 36 deletions

View file

@ -28,6 +28,10 @@
width: 75%; width: 75%;
z-index: 1001; z-index: 1001;
} }
.main-footer {
margin-left: 25%;
width: 75%;
}
} }
/* Mobile styles */ /* Mobile styles */
@ -45,6 +49,10 @@
margin-left: 0; margin-left: 0;
width: 100%; width: 100%;
} }
.main-footer {
margin-left: 0;
width: 100%;
}
} }
.city-sidebar .nav-link { .city-sidebar .nav-link {

View file

@ -2,9 +2,23 @@
{% block title %}Suivi des objets OSM - {{ stats.name }}{% endblock %} {% block title %}Suivi des objets OSM - {{ stats.name }}{% endblock %}
{% block stylesheets %}
{{ parent() }}
<link href='{{ asset('css/city-sidebar.css') }}' rel='stylesheet' />
{% endblock %}
{% block body %} {% block body %}
<div class="container mt-4"> <div class="container-fluid">
<h1>Suivi des objets OSM pour {{ stats.name }} ({{ stats.zone }})</h1> <div class="row">
<!-- Sidebar de navigation -->
<div class="col-12">
{% include 'admin/_city_sidebar.html.twig' with {'stats': stats, 'active_menu': 'followup_graph'} %}
</div>
<!-- Contenu principal -->
<div class="col-md-9 col-lg-10 main-content">
<div class="p-4">
<h1>Suivi des objets OSM pour {{ stats.name }} ({{ stats.zone }})</h1>
<div class="mb-3 d-flex flex-wrap gap-2"> <div class="mb-3 d-flex flex-wrap gap-2">
<a href="{{ path('admin_followup', {'insee_code': stats.zone}) }}" class="btn btn-warning"> <a href="{{ path('admin_followup', {'insee_code': stats.zone}) }}" class="btn btn-warning">
<i class="bi bi-arrow-repeat"></i> Mettre à jour les suivis (followup) <i class="bi bi-arrow-repeat"></i> Mettre à jour les suivis (followup)
@ -114,7 +128,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{% for type, label in followup_labels %} {% for type, label in followup_labels %}
<h2 id="title-{{ type }}"><i class="bi {{ followup_icons[type]|default('bi-question-circle') }} fs-2"></i> {{ label }}</h2> <h2 id="title-{{ type }}"><i class="bi {{ followup_icons[type]|default('bi-question-circle') }} fs-2"></i> {{ label }}</h2>
<canvas id="{{ type }}Chart" width="600" height="400"></canvas> <canvas id="{{ type }}Chart" width="600" height="400"></canvas>
@ -136,10 +150,10 @@
'all_types': [type] 'all_types': [type]
} %} } %}
{% endfor %} {% endfor %}
<h2 class="mt-4">Évolution du taux de complétion (CTC - Complète tes commerces)</h2> <h2 class="mt-4">Évolution du taux de complétion (CTC - Complète tes commerces)</h2>
<canvas id="ctcCompletionChart" width="900" height="400"></canvas> <canvas id="ctcCompletionChart" width="900" height="400"></canvas>
<h2 class="mt-4">Données brutes</h2> <h2 class="mt-4">Données brutes</h2>
<table class="table table-bordered table-striped"> <table class="table table-bordered table-striped">
<thead> <thead>
@ -162,6 +176,9 @@
</tbody> </tbody>
</table> </table>
<a href="{{ path('app_admin_stats', {'insee_code': stats.zone}) }}" class="btn btn-secondary mt-3"><i class="bi bi-arrow-left"></i> Retour à la fiche ville</a> <a href="{{ path('app_admin_stats', {'insee_code': stats.zone}) }}" class="btn btn-secondary mt-3"><i class="bi bi-arrow-left"></i> Retour à la fiche ville</a>
</div>
</div>
</div>
</div> </div>
{% endblock %} {% endblock %}
@ -270,7 +287,7 @@
canvas.parentNode.insertBefore(dateDiv, canvas.nextSibling); canvas.parentNode.insertBefore(dateDiv, canvas.nextSibling);
} }
}); });
// --- Graphique séparé pour les données CTC --- // --- Graphique séparé pour les données CTC ---
if (Object.keys(ctcCompletionSeries).length > 0) { if (Object.keys(ctcCompletionSeries).length > 0) {
const ctcDatasets = Object.keys(ctcCompletionSeries).map(function(type) { const ctcDatasets = Object.keys(ctcCompletionSeries).map(function(type) {
@ -320,4 +337,4 @@
} }
}); });
</script> </script>
{% endblock %} {% endblock %}

View file

@ -5,20 +5,21 @@
{% block stylesheets %} {% block stylesheets %}
{{ parent() }} {{ parent() }}
<link href='{{ asset('js/maplibre/maplibre-gl.css') }}' rel='stylesheet'/> <link href='{{ asset('js/maplibre/maplibre-gl.css') }}' rel='stylesheet'/>
<link href='{{ asset('css/city-sidebar.css') }}' rel='stylesheet' />
<style> <style>
.chart-container { .chart-container {
width: 100%; width: 100%;
height: 400px; height: 400px;
margin: 20px 0; margin: 20px 0;
} }
.stats-header { .stats-header {
background: #f8f9fa; background: #f8f9fa;
padding: 15px; padding: 15px;
border-radius: 8px; border-radius: 8px;
margin-bottom: 20px; margin-bottom: 20px;
} }
.action-bar { .action-bar {
background: white; background: white;
padding: 15px; padding: 15px;
@ -30,18 +31,18 @@
gap: 10px; gap: 10px;
align-items: center; align-items: center;
} }
.action-bar .btn { .action-bar .btn {
white-space: nowrap; white-space: nowrap;
} }
.stats-grid { .stats-grid {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px; gap: 15px;
margin-bottom: 20px; margin-bottom: 20px;
} }
.stat-card { .stat-card {
background: white; background: white;
padding: 15px; padding: 15px;
@ -49,25 +50,25 @@
border: 1px solid #dee2e6; border: 1px solid #dee2e6;
text-align: center; text-align: center;
} }
.stat-value { .stat-value {
font-size: 24px; font-size: 24px;
font-weight: bold; font-weight: bold;
color: #0d6efd; color: #0d6efd;
} }
.stat-label { .stat-label {
font-size: 14px; font-size: 14px;
color: #6c757d; color: #6c757d;
margin-top: 5px; margin-top: 5px;
} }
.chart-tabs { .chart-tabs {
display: flex; display: flex;
margin-bottom: 20px; margin-bottom: 20px;
border-bottom: 1px solid #dee2e6; border-bottom: 1px solid #dee2e6;
} }
.chart-tab { .chart-tab {
padding: 10px 20px; padding: 10px 20px;
background: none; background: none;
@ -75,20 +76,20 @@
cursor: pointer; cursor: pointer;
border-bottom: 3px solid transparent; border-bottom: 3px solid transparent;
} }
.chart-tab.active { .chart-tab.active {
border-bottom-color: #0d6efd; border-bottom-color: #0d6efd;
color: #0d6efd; color: #0d6efd;
} }
.chart-content { .chart-content {
display: none; display: none;
} }
.chart-content.active { .chart-content.active {
display: block; display: block;
} }
#themeMap { #themeMap {
height: 400px; height: 400px;
width: 100%; width: 100%;
@ -123,10 +124,18 @@
{% block body %} {% block body %}
<div class="container-fluid"> <div class="container-fluid">
<div class="row">
<!-- Sidebar de navigation -->
<div class="col-12">
{% include 'admin/_city_sidebar.html.twig' with {'stats': stats, 'active_menu': 'followup_graph'} %}
</div>
{# DEBUG : Affichage des objets Place trouvés pour cette ville #} <!-- Contenu principal -->
{% if places is defined %} <div class="col-md-9 col-lg-10 main-content">
<div class="alert alert-warning" style="font-size:0.95em;"> <div class="p-4">
{# DEBUG : Affichage des objets Place trouvés pour cette ville #}
{% if places is defined %}
<div class="alert alert-warning" style="font-size:0.95em;">
<b>DEBUG : Objets Place trouvés pour cette ville (avant filtrage)</b><br> <b>DEBUG : Objets Place trouvés pour cette ville (avant filtrage)</b><br>
<table class="table table-sm table-bordered mt-2 mb-0"> <table class="table table-sm table-bordered mt-2 mb-0">
<thead><tr> <thead><tr>
@ -185,7 +194,7 @@
<a href="{{ path('admin_street_completion', {'insee_code': stats.zone}) }}" class="btn btn-outline-success"> <a href="{{ path('admin_street_completion', {'insee_code': stats.zone}) }}" class="btn btn-outline-success">
<i class="bi bi-signpost"></i> Complétion des rues <i class="bi bi-signpost"></i> Complétion des rues
</a> </a>
</div> </div>
{% if theme == 'bicycle_parking' %} {% if theme == 'bicycle_parking' %}
@ -230,7 +239,7 @@
<div class="stat-label">Dernière mise à jour</div> <div class="stat-label">Dernière mise à jour</div>
</div> </div>
</div> </div>
<div class="chart-container"> <div class="chart-container">
<canvas id="themeChart"></canvas> <canvas id="themeChart"></canvas>
@ -294,6 +303,10 @@
<a href="https://forum.openstreetmap.fr/t/osm-mon-commerce/34403/11" class="btn btn-info suggestion-footer-btn mt-4 mb-2" target="_blank" rel="noopener"> <a href="https://forum.openstreetmap.fr/t/osm-mon-commerce/34403/11" class="btn btn-info suggestion-footer-btn mt-4 mb-2" target="_blank" rel="noopener">
<i class="bi bi-chat-dots"></i> Faire une suggestion <i class="bi bi-chat-dots"></i> Faire une suggestion
</a> </a>
</div>
</div>
</div>
</div>
{% endblock %} {% endblock %}
@ -439,7 +452,7 @@
<b>Complétion :</b> ${completion !== null ? completion + '%' : ''} <b>Complétion :</b> ${completion !== null ? completion + '%' : ''}
${missingHtml} ${missingHtml}
<br> <br>
<a class="btn btn-info" href='https://www.openstreetmap.org/${e.type}/${e.id}' target='_blank'> <a class="btn btn-info" href='https://www.openstreetmap.org/${e.type}/${e.id}' target='_blank'>
<i class="bi bi-planet" ></i> <i class="bi bi-planet" ></i>
Voir sur OSM</a> Voir sur OSM</a>
@ -447,9 +460,9 @@
<a class="btn btn-info" href='${josmUrl}' target='_blank'> <i class="bi bi-map" ></i> JOSM</a> <a class="btn btn-info" href='${josmUrl}' target='_blank'> <i class="bi bi-map" ></i> JOSM</a>
<a class="btn btn-info" href='${idUrl}' target='_blank'><i class="bi bi-pencil" ></i>iD</a> <a class="btn btn-info" href='${idUrl}' target='_blank'><i class="bi bi-pencil" ></i>iD</a>
<span style='font-size:0.95em;'>${e.tags ? Object.entries(e.tags).map(([k,v]) => `<span><b>${k}</b>: ${v}</span>`).join('<br>') : ''}</span><br> <span style='font-size:0.95em;'>${e.tags ? Object.entries(e.tags).map(([k,v]) => `<span><b>${k}</b>: ${v}</span>`).join('<br>') : ''}</span><br>
</div>`; </div>`;
new maplibregl.Marker({ color: color }) new maplibregl.Marker({ color: color })
.setLngLat([lon, lat]) .setLngLat([lon, lat])
@ -483,7 +496,7 @@
</script> </script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
<script> <script>
@ -492,7 +505,7 @@
const completionData = {{ completion_data|json_encode|raw }}; const completionData = {{ completion_data|json_encode|raw }};
// Mettre à jour les statistiques // Mettre à jour les statistiques
function updateStats() { function updateStats() {
if (countData.length > 0) { if (countData.length > 0) {
@ -500,15 +513,15 @@
document.getElementById('currentCount').textContent = latestCount.value; document.getElementById('currentCount').textContent = latestCount.value;
document.getElementById('lastUpdate').textContent = new Date(latestCount.date).toLocaleDateString('fr-FR'); document.getElementById('lastUpdate').textContent = new Date(latestCount.date).toLocaleDateString('fr-FR');
} }
if (completionData.length > 0) { if (completionData.length > 0) {
const latestCompletion = completionData[completionData.length - 1]; const latestCompletion = completionData[completionData.length - 1];
document.getElementById('currentCompletion').textContent = latestCompletion.value + '%'; document.getElementById('currentCompletion').textContent = latestCompletion.value + '%';
} }
document.getElementById('dataPoints').textContent = Math.max(countData.length, completionData.length); document.getElementById('dataPoints').textContent = Math.max(countData.length, completionData.length);
} }
// Configuration commune pour les graphiques // Configuration commune pour les graphiques
const commonOptions = { const commonOptions = {
responsive: true, responsive: true,
@ -549,7 +562,7 @@
intersect: false intersect: false
} }
}; };
// Graphique fusionné // Graphique fusionné
const ctx = document.getElementById('themeChart').getContext('2d'); const ctx = document.getElementById('themeChart').getContext('2d');
new Chart(ctx, { new Chart(ctx, {
@ -609,7 +622,7 @@
} }
} }
}); });
// Initialiser les statistiques // Initialiser les statistiques
updateStats(); updateStats();
@ -620,4 +633,4 @@
console.log('[DEBUG][Overpass] Aucune requête Overpass transmise à la page.'); console.log('[DEBUG][Overpass] Aucune requête Overpass transmise à la page.');
{% endif %} {% endif %}
</script> </script>
{% endblock %} {% endblock %}