2025-07-12 12:03:40 +02:00
{% extends 'base.html.twig' %}
{# {% block title %}Suivi de la rue {{ street }} à {{ city }}{% endblock %} #}
{% block stylesheets %}
{{ parent ( ) }}
<link href=' {{ asset ( 'js/maplibre/maplibre-gl.css' ) }} ' rel='stylesheet'/>
<style>
#streetMap { height: 400px; width: 100%; border-radius: 8px; margin-bottom: 2rem; }
</style>
{% endblock %}
{% block body %}
<div class="container my-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h1>Rue <span class="text-primary"> {{ street | e ( 'html' ) }} </span> à <span class="text-success"> {{ city }} </span></h1>
<a href=" {{ stats_url }} " class="btn btn-outline-info my-2"><i class="bi bi-bar-chart"></i> Voir les statistiques de la ville</a>
</div>
<a href=" {{ path ( 'app_public_index' ) }} " class="btn btn-secondary"><i class="bi bi-arrow-left"></i> Retour à l'accueil</a>
</div>
<div class="row mb-4">
<div class="col-md-6 col-12">
<h3>Répartition de la complétion</h3>
<canvas id="completionChart" height="200"></canvas>
</div>
<div class="col-md-6 col-12">
<h3>Carte des lieux</h3>
<div id="streetMap" style="height: 300px; width: 100%; border-radius: 8px;"></div>
2025-07-12 13:04:39 +02:00
<span class="is-info"> Si il manque des lieux dans cette rue c'est parce que les objets n'ont pas d'attribut "contact:street" et "contact:housenumber". Les addresses des commerces et autres lieux doivent toujours être sur des noeuds distincts dans OpenStreetMap.</span>
2025-07-12 12:03:40 +02:00
</div>
</div>
<h2 class="mt-4">Lieux de la rue</h2>
<div class="table-responsive">
<table class="table table-bordered table-striped table-hover table-responsive table-sort">
{% include 'admin/stats/table-head.html.twig' with { stats : { places : places , getAvecAdresse : 0 , getAvecSite : 0 , getAvecAccessibilite : 0 , getAvecNote : 0 } } %}
<tbody>
{% for commerce in places %}
{% include 'admin/stats/row.html.twig' with { commerce : commerce , stats : { population : 0 , places : places } } %}
{% else %}
<tr><td colspan="18" class="text-muted">Aucun lieu trouvé pour cette rue.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
{% block javascripts %}
{{ parent ( ) }}
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src=" {{ asset ( 'js/maplibre/maplibre-gl.js' ) }} "></script>
<script>
// Graphe de complétion
const completionData = {
labels: {{ completion_buckets | keys | json_encode | raw }} ,
datasets: [ {
label: 'Nombre de lieux',
data: {{ completion_buckets_values | json_encode | raw }} ,
backgroundColor: [
'#e57373', '#ffb74d', '#fff176', '#81c784', '#64b5f6'
]
}]
};
new Chart(document.getElementById('completionChart'), {
type: 'bar',
data: completionData,
options: {
responsive: true,
plugins: { legend: { display: false } },
scales: { y: { beginAtZero: true, precision: 0 } }
}
});
// Carte MapLibre
const mapToken = ' {{ maptiler_token }} ';
const places = {{ places_js | json_encode | raw }} ;
let center = [2.35, 48.85];
if (places.length > 0) {
const avgLat = places.reduce((sum, p) => sum + (p.lat || 0), 0) / places.length;
const avgLon = places.reduce((sum, p) => sum + (p.lon || 0), 0) / places.length;
center = [avgLon, avgLat];
}
const map = new maplibregl.Map( {
container: 'streetMap',
style: `https://api.maptiler.com/maps/streets/style.json?key=$ { mapToken}`,
center: center,
zoom: 16
});
// Couleurs selon la complétion
function getColor(percentage) {
if (percentage < 20) return '#e57373';
if (percentage < 40) return '#ffb74d';
if (percentage < 60) return '#fff176';
if (percentage < 80) return '#81c784';
return '#64b5f6';
}
places.forEach(place => {
if (place.lat && place.lon) {
new maplibregl.Marker( { color: getColor(place.completionPercentage)})
.setLngLat([place.lon, place.lat])
.setPopup(new maplibregl.Popup().setHTML(`<strong>$ { place.name || '(sans nom)'}</strong><br>Complétion : $ { place.completionPercentage}%`))
.addTo(map);
}
});
</script>
{% endblock %}