mirror of
https://forge.chapril.org/tykayn/osm-commerces
synced 2025-06-20 01:44:42 +02:00
fix popup infos
This commit is contained in:
parent
ef42dba9dd
commit
abdd59e8c8
3 changed files with 192 additions and 118 deletions
|
@ -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;
|
||||||
|
|
|
@ -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');
|
||||||
|
|
|
@ -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 %}
|
Loading…
Add table
Add a link
Reference in a new issue