up pages rues et évolutions dans le temps
This commit is contained in:
parent
7355600e6b
commit
c8e3cf2ada
10 changed files with 329 additions and 14 deletions
152
templates/admin/street_completion.html.twig
Normal file
152
templates/admin/street_completion.html.twig
Normal file
|
@ -0,0 +1,152 @@
|
|||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Complétion des rues - {{ stats.name }}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container my-5">
|
||||
<h1>Complétion des rues à {{ stats.name }} ({{ stats.zone }})</h1>
|
||||
<a href="{{ path('app_admin_stats', {'insee_code': stats.zone}) }}" class="btn btn-secondary mb-3"><i class="bi bi-arrow-left"></i> Retour aux stats</a>
|
||||
<table class="table table-bordered table-striped table-hover table-responsive">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Rue</th>
|
||||
<th class="text-end">Nombre de lieux</th>
|
||||
<th class="text-end">Complétion moyenne (%)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for rue in rues %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ path('app_public_street', {'cityId': insee_code, 'streetName': rue.name|url_encode }) }}">
|
||||
{{ rue.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td class="text-end">{{ rue.count }}</td>
|
||||
<td class="text-end">{{ rue.avg_completion }}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="3" class="text-muted">Aucune rue trouvée.</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="missing-streets-block" class="mt-5">
|
||||
<h2>Rues sans lieu associé (données OSM)</h2>
|
||||
<div id="missing-streets-loading">Chargement des rues OSM…</div>
|
||||
<ul id="missing-streets-list" class="list-group"></ul>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function buildOverpassAroundUrl(street, bbox) {
|
||||
// Requête Overpass autour de la rue (10m)
|
||||
// Utilise la requête de base de la motocultrice, mais avec around:10
|
||||
// Ici on cherche les commerces autour de la géométrie de la rue
|
||||
const query = `[out:json][timeout:25];
|
||||
way["name"="${street}"]["highway"](${bbox.join(",")});
|
||||
out body;
|
||||
>;
|
||||
out skel qt;
|
||||
node(around:10)[shop](if:t["name"])(if:t["addr:street"]=="${street}");
|
||||
out;`;
|
||||
return `https://overpass-turbo.eu/map.html?Q=${encodeURIComponent(query)}`;
|
||||
}
|
||||
function buildOsmUrl(street, bbox) {
|
||||
// Lien OSM pour la rue (zoom sur la bbox)
|
||||
const [s, w, n, e] = bbox;
|
||||
const lat = (parseFloat(s) + parseFloat(n)) / 2;
|
||||
const lon = (parseFloat(w) + parseFloat(e)) / 2;
|
||||
return `https://www.openstreetmap.org/#map=18/${lat}/${lon}`;
|
||||
}
|
||||
function fetchStreetBbox(street, insee, cb) {
|
||||
// Requête Overpass pour trouver la bbox de la rue
|
||||
const query = `[out:json][timeout:25];area["ref:INSEE"="${insee}"][admin_level=8];way["name"="${street}"]["highway"](area);out bb;`;
|
||||
fetch('https://overpass-api.de/api/interpreter', {
|
||||
method: 'POST',
|
||||
body: query
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.elements && data.elements.length > 0 && data.elements[0].bounds) {
|
||||
const b = data.elements[0].bounds;
|
||||
cb([b.south, b.west, b.north, b.east]);
|
||||
}
|
||||
});
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Récupérer la liste des rues déjà présentes dans le tableau
|
||||
const ruesConnues = new Set([
|
||||
{% for rue in rues %}'{{ rue.name|e('js') }}',{% endfor %}
|
||||
]);
|
||||
// Construire la requête Overpass pour toutes les rues de la ville
|
||||
const insee = '{{ insee_code }}';
|
||||
const overpassQuery = `
|
||||
[out:json][timeout:25];
|
||||
area["ref:INSEE"="${insee}"]->.searchArea;
|
||||
way["highway"]["name"](area.searchArea);
|
||||
out tags;
|
||||
`;
|
||||
fetch('https://overpass-api.de/api/interpreter', {
|
||||
method: 'POST',
|
||||
body: overpassQuery,
|
||||
headers: { 'Content-Type': 'text/plain' }
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
const allStreets = new Set();
|
||||
(data.elements || []).forEach(el => {
|
||||
if (el.tags && el.tags.name) {
|
||||
allStreets.add(el.tags.name);
|
||||
}
|
||||
});
|
||||
// Filtrer les rues qui n'ont pas de lieu associé
|
||||
const missing = Array.from(allStreets).filter(nom => !ruesConnues.has(nom));
|
||||
const ul = document.getElementById('missing-streets-list');
|
||||
ul.innerHTML = '';
|
||||
if (missing.length === 0) {
|
||||
ul.innerHTML = '<li class="list-group-item text-success">Toutes les rues OSM ont au moins un lieu associé.</li>';
|
||||
} else {
|
||||
missing.sort((a, b) => a.localeCompare(b, 'fr'));
|
||||
missing.forEach(nom => {
|
||||
const li = document.createElement('li');
|
||||
li.className = 'list-group-item d-flex justify-content-between align-items-center';
|
||||
li.setAttribute('data-street-name', nom);
|
||||
li.textContent = nom;
|
||||
const buttons = document.createElement('span');
|
||||
buttons.innerHTML = `
|
||||
<a href="#" class="btn btn-outline-secondary btn-sm osm-link" title="Voir la rue sur OpenStreetMap" target="_blank" data-street="${nom}">
|
||||
<i class="bi bi-globe"></i>
|
||||
</a>
|
||||
<a href="#" class="btn btn-outline-primary btn-sm overpass-link ms-1" title="Lieux possibles sur Overpass" target="_blank" data-street="${nom}">
|
||||
<i class="bi bi-ev-station"></i>
|
||||
</a>
|
||||
`;
|
||||
li.appendChild(buttons);
|
||||
ul.appendChild(li);
|
||||
});
|
||||
}
|
||||
document.getElementById('missing-streets-loading').style.display = 'none';
|
||||
})
|
||||
.catch(e => {
|
||||
document.getElementById('missing-streets-loading').textContent = 'Erreur lors de la récupération des rues OSM.';
|
||||
});
|
||||
document.querySelectorAll('#missing-streets-list li').forEach(function(li) {
|
||||
const street = li.getAttribute('data-street-name');
|
||||
const insee = '{{ insee_code }}';
|
||||
li.querySelector('.osm-link').addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
fetchStreetBbox(street, insee, function(bbox) {
|
||||
window.open(buildOsmUrl(street, bbox), '_blank');
|
||||
});
|
||||
});
|
||||
li.querySelector('.overpass-link').addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
fetchStreetBbox(street, insee, function(bbox) {
|
||||
window.open(buildOverpassAroundUrl(street, bbox), '_blank');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
Loading…
Add table
Add a link
Reference in a new issue