fix popup infos

This commit is contained in:
Tykayn 2025-06-06 15:48:03 +02:00 committed by tykayn
parent ef42dba9dd
commit abdd59e8c8
3 changed files with 192 additions and 118 deletions

View file

@ -165,6 +165,10 @@ document.addEventListener('DOMContentLoaded', () => {
/**
* mettre à jour la barre de progression
* pour le formulaire de modification
*/
function updateCompletionProgress() { function updateCompletionProgress() {
const inputs = document.querySelectorAll('input[type="text"]'); const inputs = document.querySelectorAll('input[type="text"]');
let filledInputs = 0; let filledInputs = 0;

View file

@ -21,6 +21,9 @@
function sortTable(Table, col, dir) { function sortTable(Table, col, dir) {
var sortClass, i; var sortClass, i;
if (!Table) {
return;
}
// get previous sort column // get previous sort column
sortTable.sortCol = -1; sortTable.sortCol = -1;
sortClass = Table.className.match(/js-sort-\d+/); sortClass = Table.className.match(/js-sort-\d+/);
@ -94,7 +97,7 @@ function sortTable(Table, col, dir) {
* @param RowB A TR DOM object * @param RowB A TR DOM object
* @returns {number} 1 if RowA is greater, -1 if RowB, 0 if equal * @returns {number} 1 if RowA is greater, -1 if RowB, 0 if equal
*/ */
sortTable.compareRow = function(RowA, RowB) { sortTable.compareRow = function (RowA, RowB) {
var valA, valB; var valA, valB;
if ('function' != typeof sortTable[sortTable.sortFunc]) { if ('function' != typeof sortTable[sortTable.sortFunc]) {
sortTable.sortFunc = 'string'; sortTable.sortFunc = 'string';
@ -110,7 +113,7 @@ sortTable.compareRow = function(RowA, RowB) {
* @param html * @param html
* @returns {string} * @returns {string}
*/ */
sortTable.stripTags = function(html) { sortTable.stripTags = function (html) {
return html.replace(/<\/?[a-z][a-z0-9]*\b[^>]*>/gi, ''); return html.replace(/<\/?[a-z][a-z0-9]*\b[^>]*>/gi, '');
}; };
@ -121,7 +124,7 @@ sortTable.stripTags = function(html) {
* @param Cell A TD DOM object * @param Cell A TD DOM object
* @returns {Date} * @returns {Date}
*/ */
sortTable.date = function(Cell) { sortTable.date = function (Cell) {
return new Date(sortTable.stripTags(Cell.innerHTML)); return new Date(sortTable.stripTags(Cell.innerHTML));
}; };
@ -132,7 +135,7 @@ sortTable.date = function(Cell) {
* @param Cell A TD DOM object * @param Cell A TD DOM object
* @returns {Number} * @returns {Number}
*/ */
sortTable.number = function(Cell) { sortTable.number = function (Cell) {
return Number(sortTable.stripTags(Cell.innerHTML).replace(/[^-\d.]/g, '')); return Number(sortTable.stripTags(Cell.innerHTML).replace(/[^-\d.]/g, ''));
}; };
@ -143,7 +146,7 @@ sortTable.number = function(Cell) {
* @param Cell A TD DOM object * @param Cell A TD DOM object
* @returns {String} * @returns {String}
*/ */
sortTable.string = function(Cell) { sortTable.string = function (Cell) {
return sortTable.stripTags(Cell.innerHTML).toLowerCase(); return sortTable.stripTags(Cell.innerHTML).toLowerCase();
}; };
@ -154,7 +157,7 @@ sortTable.string = function(Cell) {
* @param Cell A TD DOM object * @param Cell A TD DOM object
* @returns {String} * @returns {String}
*/ */
sortTable.last = function(Cell) { sortTable.last = function (Cell) {
return sortTable.stripTags(Cell.innerHTML).split(' ').pop().toLowerCase(); return sortTable.stripTags(Cell.innerHTML).split(' ').pop().toLowerCase();
}; };
@ -165,7 +168,7 @@ sortTable.last = function(Cell) {
* @param Cell A TD DOM object * @param Cell A TD DOM object
* @returns {String} * @returns {String}
*/ */
sortTable.input = function(Cell) { sortTable.input = function (Cell) {
for (var i = 0; i < Cell.children.length; i++) { for (var i = 0; i < Cell.children.length; i++) {
if ('object' == typeof Cell.children[i] if ('object' == typeof Cell.children[i]
&& 'undefined' != typeof Cell.children[i].value && 'undefined' != typeof Cell.children[i].value
@ -184,8 +187,8 @@ sortTable.input = function(Cell) {
* @param col Column to sort by * @param col Column to sort by
* @returns {Function} Click Handler * @returns {Function} Click Handler
*/ */
sortTable.getClickHandler = function(Table, col) { sortTable.getClickHandler = function (Table, col) {
return function() { return function () {
sortTable(Table, col); sortTable(Table, col);
}; };
}; };
@ -195,7 +198,7 @@ sortTable.getClickHandler = function(Table, col) {
* If the table(s) do not have a THead node, one will be created around the * If the table(s) do not have a THead node, one will be created around the
* first row * first row
*/ */
sortTable.init = function() { sortTable.init = function () {
var THead, Tables, Handler; var THead, Tables, Handler;
if (document.querySelectorAll) { if (document.querySelectorAll) {
Tables = document.querySelectorAll('table.js-sort-table'); Tables = document.querySelectorAll('table.js-sort-table');

View file

@ -118,7 +118,8 @@
let features = []; let features = [];
let maplibre; let maplibre;
let map; let map;
let overpassData = {}; // Stockage des données Overpass
function getCompletionColor(completion) { function getCompletionColor(completion) {
if (completion === undefined || completion === null) { if (completion === undefined || completion === null) {
return '#808080'; // Gris pour pas d'information return '#808080'; // Gris pour pas d'information
@ -129,30 +130,27 @@
} }
function calculateCompletion(element) { function calculateCompletion(element) {
let completed = 0; let completionCount = 0;
let total = 0; let totalFields = 0;
// Critères à vérifier const fieldsToCheck = [
const criteria = [
'name', 'name',
'addr:street', 'contact:street',
'addr:housenumber', 'contact:housenumber',
'addr:postcode',
'addr:city',
'opening_hours', 'opening_hours',
'website', 'contact:website',
'wheelchair', 'contact:phone',
'phone' 'wheelchair'
]; ];
criteria.forEach(criterion => { fieldsToCheck.forEach(field => {
if (element.tags && element.tags[criterion]) { totalFields++;
completed++; if (element.tags && element.tags[field]) {
completionCount++;
} }
total++;
}); });
return total > 0 ? (completed / total) * 100 : 0; return (completionCount / totalFields) * 100;
} }
function createPopupContent(element) { function createPopupContent(element) {
@ -254,8 +252,8 @@
let josm_elements = []; let josm_elements = [];
async function loadPlaces(map) { async function loadPlaces(map) {
map_is_loaded = false;
try { try {
const request = `{{query_places |raw}}`;
const response = await fetch('https://overpass-api.de/api/interpreter', { const response = await fetch('https://overpass-api.de/api/interpreter', {
method: 'POST', method: 'POST',
body: request body: request
@ -264,46 +262,113 @@
throw new Error(`HTTP error! status: ${response.status}`); throw new Error(`HTTP error! status: ${response.status}`);
} }
const data = await response.json(); const data = await response.json();
console.log('Lieux chargés:', data.elements); console.log('Données reçues:', data);
mapElements = data.elements;
map_is_loaded = true;
// Créer le graphique de distribution // Stocker les données Overpass
createCompletionChart(data.elements); data.elements.forEach(element => {
overpassData[element.id] = element;
});
// Mettre à jour les cercles // Mettre à jour les cercles
features = []; features = [];
josm_elements = []; josm_elements = [];
data.elements.forEach(element => { data.elements.forEach(element => {
const lat = element.lat || (element.center && element.center.lat); const lat = element.lat || (element.center && element.center.lat);
const lon = element.lon || (element.center && element.center.lon); const lon = element.lon || (element.center && element.center.lon);
if (lat && lon) { if (lat && lon) {
const completion = calculateCompletion(element); const completion = calculateCompletion(element);
const color = getCompletionColor(completion); console.log('Completion pour', element.tags?.name, ':', completion, '%');
// Créer un cercle de 20 mètres de rayon (plus petit) const circle = {
const circle = turf.circle([lon, lat], 0.04, { steps: 64, units: 'kilometers' }); id: `circle-${element.id}`,
circle.properties = { type: 'Feature',
color: color, properties: {
completion: completion, id: element.id,
name: element.tags?.name || 'Sans nom', name: element.tags?.name || 'Sans nom',
popupContent: createPopupContent(element), completion: completion,
center: [lon, lat] // Stocker le centre comme un tableau [lon, lat] center: [lon, lat]
},
geometry: {
type: 'Point',
coordinates: [lon, lat]
}
}; };
features.push(circle); features.push(circle);
josm_elements.push(element); josm_elements.push(element);
} }
}); });
// Mettre à jour la source des cercles // Créer les cercles sur la carte
map.getSource('completion-circles').setData({ features.forEach(feature => {
'type': 'FeatureCollection', const layerId = `circle-${feature.properties.id}`;
'features': features if (map.getSource(layerId)) {
map.removeSource(layerId);
}
if (map.getLayer(layerId)) {
map.removeLayer(layerId);
}
const circle = turf.circle(
feature.properties.center,
0.02, // Rayon initial en kilomètres
{ steps: 64, units: 'kilometers' }
);
map.addSource(layerId, {
'type': 'geojson',
'data': circle
});
map.addLayer({
'id': layerId,
'type': 'fill',
'source': layerId,
'paint': {
'fill-color': getCompletionColor(feature.properties.completion),
'fill-opacity': 0.7
}
});
}); });
// Calculer les bounds pour tous les points // Ajouter les popups sur les cercles
map.on('click', function(e) {
const clickedFeatures = map.queryRenderedFeatures(e.point, {
layers: features.map(f => `circle-${f.properties.id}`)
});
console.log('Clicked features:', clickedFeatures);
if (clickedFeatures.length > 0) {
const feature = clickedFeatures[0];
const elementId = feature.layer.id.replace('circle-', '');
const element = overpassData[elementId];
if (element) {
const completion = calculateCompletion(element);
// Créer le contenu de la popup
const popupContent = `
<div class="popup-content">
<h5>${element.tags?.name || 'Sans nom'}</h5>
<p>Taux de complétion: ${Math.round(completion)}%</p>
<ul>
${Object.entries(element.tags || {})
.filter(([key]) => !['name'].includes(key))
.map(([key, value]) => `<li><strong>${key}:</strong> ${value}</li>`)
.join('')}
</ul>
</div>
`;
new maplibregl.Popup()
.setLngLat(e.lngLat)
.setHTML(popupContent)
.addTo(map);
}
}
});
// Ajuster la vue pour inclure tous les points
const points = features.map(f => f.properties.center); const points = features.map(f => f.properties.center);
if (points.length > 0) { if (points.length > 0) {
const bounds = new maplibregl.LngLatBounds(points[0], points[0]); const bounds = new maplibregl.LngLatBounds(points[0], points[0]);
@ -319,33 +384,68 @@
console.warn('Bounds invalides, utilisation des coordonnées par défaut'); console.warn('Bounds invalides, utilisation des coordonnées par défaut');
} }
} }
createCompletionChart(data.elements);
// Cacher le spinner une fois le chargement terminé
document.getElementById('maploader').style.display = 'none';
document.getElementById('maploader').classList.add('d-none');
} catch (error) { } catch (error) {
console.error('Erreur lors du chargement des lieux:', error); console.error('Erreur lors du chargement des lieux:', error);
document.getElementById('maploader').classList.add('d-none');
} }
} }
function updateCircles(map) {
if (!map) return;
function openJOSMQuery(map, query) { const zoom = map.getZoom();
const bounds = map.getBounds(); // Ajuster la taille de base en fonction du zoom
// Plus le zoom est faible (loin), plus le rayon est grand
const baseRadius = Math.min(100, 200 / Math.pow(1.2, zoom));
const josmUrl = `http://localhost:8111/load_object?` + features.forEach(feature => {
const source = map.getSource(feature.id);
if (!source) return;
const completion = feature.properties.completion;
const radius = baseRadius * (1 + (completion / 100));
// Mettre à jour le rayon du cercle
const circle = turf.circle(
feature.properties.center,
0.5* radius / 1000, // Convertir en kilomètres
{ steps: 64, units: 'kilometers' }
);
// Mettre à jour la source avec le nouveau cercle
source.setData(circle);
// Mettre à jour la couleur du cercle
const layer = map.getLayer(feature.id);
if (layer) {
map.setPaintProperty(feature.id, 'fill-color', getCompletionColor(completion));
}
});
}
function openJOSMQuery(map, query) {
const bounds = map.getBounds();
const josmUrl = `http://localhost:8111/load_object?` +
`objects=${query}`; `objects=${query}`;
// Créer un élément <a> temporaire // Créer un élément <a> temporaire
const tempLink = document.createElement('a'); const tempLink = document.createElement('a');
tempLink.style.display = 'none'; tempLink.style.display = 'none';
document.body.appendChild(tempLink); document.body.appendChild(tempLink);
console.log('josmUrl', josmUrl); console.log('josmUrl', josmUrl);
tempLink.href = josmUrl; tempLink.href = josmUrl;
tempLink.click(); tempLink.click();
document.body.removeChild(tempLink); document.body.removeChild(tempLink);
} }
function openInJOSM() { function openInJOSM() {
if (josm_elements.length === 0) { if (josm_elements.length === 0) {
@ -355,8 +455,6 @@ function openJOSMQuery(map, query) {
const query = createJOSMQuery(josm_elements); const query = createJOSMQuery(josm_elements);
console.log('map', map); console.log('map', map);
openJOSMQuery(map, query); openJOSMQuery(map, query);
} }
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
@ -372,65 +470,34 @@ function openJOSMQuery(map, query) {
document.getElementById('openInJOSM').addEventListener('click', openInJOSM); document.getElementById('openInJOSM').addEventListener('click', openInJOSM);
map.on('load', () => { // Attendre que la carte soit chargée avant d'ajouter les écouteurs d'événements
// Créer une source pour les cercles map.on('load', function() {
map.addSource('completion-circles', { console.log('Map loaded');
'type': 'geojson', map_is_loaded = true;
'data': {
'type': 'FeatureCollection',
'features': []
}
});
// Ajouter une couche pour les cercles
map.addLayer({
'id': 'completion-circles',
'type': 'fill',
'source': 'completion-circles',
'paint': {
'fill-color': ['get', 'color'],
'fill-opacity': 0.6,
'fill-outline-color': '#fff'
}
});
// Ajouter une couche pour la bordure
map.addLayer({
'id': 'completion-circles-outline',
'type': 'line',
'source': 'completion-circles',
'paint': {
'line-color': 'rgba(100,100,100,0.5)',
'line-width': 2
}
});
// Ajouter les popups sur les cercles
map.on('click', 'completion-circles', (e) => {
const properties = e.features[0].properties;
new maplibregl.Popup()
.setLngLat(e.lngLat)
.setHTML(properties.popupContent)
.addTo(map);
});
// Changer le curseur au survol des cercles // Changer le curseur au survol des cercles
map.on('mouseenter', 'completion-circles', () => { map.on('mouseenter', function(e) {
map.getCanvas().style.cursor = 'pointer'; const hoveredFeatures = map.queryRenderedFeatures(e.point, {
layers: features.map(f => f.id)
});
if (hoveredFeatures.length > 0) {
map.getCanvas().style.cursor = 'pointer';
}
}); });
map.on('mouseleave', 'completion-circles', () => { map.on('mouseleave', function(e) {
map.getCanvas().style.cursor = ''; const hoveredFeatures = map.queryRenderedFeatures(e.point, {
layers: features.map(f => f.id)
});
if (hoveredFeatures.length === 0) {
map.getCanvas().style.cursor = '';
}
}); });
// Charger les lieux // Charger les lieux
loadPlaces(map); loadPlaces(map);
}); });
sortTable(); sortTable();
colorHeadingTable();
}); });
</script> </script>
{% endblock %} {% endblock %}