mirror of
https://forge.chapril.org/tykayn/libre-charge-map
synced 2025-06-20 01:34:43 +02:00
ajout des suggestions osmose
This commit is contained in:
parent
522f48f887
commit
e0a042c28b
8 changed files with 429 additions and 769 deletions
346
js/lcm_main.js
346
js/lcm_main.js
|
@ -7,7 +7,7 @@
|
|||
import lcm_config from './lcm_config.js'
|
||||
import lcm_utils from './lcm_utils.js'
|
||||
import lcm_color_utils from './lcm_color_utils.js'
|
||||
import {sendToJOSM, createJOSMEditLink} from './lcm_editor.js'
|
||||
import { sendToJOSM, createJOSMEditLink } from './lcm_editor.js'
|
||||
|
||||
let geojsondata;
|
||||
let lastLatLng;
|
||||
|
@ -115,7 +115,7 @@ let overlays = {
|
|||
stations: all_stations_markers
|
||||
}
|
||||
|
||||
const layerControl = L.control.layers(baseLayers, overlays, {collapsed: true}).addTo(map)
|
||||
const layerControl = L.control.layers(baseLayers, overlays, { collapsed: true }).addTo(map)
|
||||
tileGrey.addTo(map)
|
||||
|
||||
|
||||
|
@ -286,17 +286,35 @@ function displayStatsFromGeoJson(resultAsGeojson) {
|
|||
$('#bars_power').html(bar_powers);
|
||||
}
|
||||
|
||||
function bindEventsOnJosmRemote() {
|
||||
let josm_remote_buttons = $(`#sendToJOSM`)
|
||||
$(josm_remote_buttons[0]).on('click', () => {
|
||||
let josm_link = $(josm_remote_buttons[0]).attr('data-href')
|
||||
$.get(josm_link, (res) => {
|
||||
console.log('res', res)
|
||||
})
|
||||
})
|
||||
// Modifier bindEventsOnJosmRemote pour cibler les boutons dans un contexte (la popup)
|
||||
function bindEventsOnJosmRemote(popupElement) {
|
||||
// Cible tous les liens JOSM à l'intérieur de l'élément popup fourni
|
||||
$(popupElement).find('.edit-button.josm').each(function () {
|
||||
// Utiliser .off().on() pour éviter les liaisons multiples si la popup est rouverte
|
||||
$(this).off('click').on('click', (event) => {
|
||||
event.preventDefault(); // Empêcher le comportement par défaut du lien
|
||||
let josm_link = $(this).attr('data-href');
|
||||
console.log('Sending command to JOSM:', josm_link);
|
||||
// Utiliser fetch pour la requête GET vers JOSM (plus moderne que $.get)
|
||||
fetch(josm_link)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
// Gérer les erreurs de communication avec JOSM
|
||||
console.error('JOSM remote control error:', response.status, response.statusText);
|
||||
alert('Erreur de communication avec JOSM. Assurez-vous que JOSM est lancé et que le contrôle à distance est activé.');
|
||||
} else {
|
||||
console.log('JOSM command sent successfully.');
|
||||
// Optionnel: Afficher une notification de succès
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Failed to send command to JOSM:', error);
|
||||
alert('Impossible d\'envoyer la commande à JOSM. Est-il lancé et le contrôle à distance activé ?');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function displayPointsFromApi(points, convert_to_osm_json) {
|
||||
if (points && convert_to_osm_json) {
|
||||
geojsondata = osmtogeojson(points);
|
||||
|
@ -306,7 +324,7 @@ function displayPointsFromApi(points, convert_to_osm_json) {
|
|||
|
||||
let resultLayer = L.geoJson(geojsondata, {
|
||||
style: function (feature) {
|
||||
return {color: '#f00'};
|
||||
return { color: '#f00' };
|
||||
},
|
||||
filter: function (feature, layer) {
|
||||
let isPolygon = (feature.geometry) && (feature.geometry.type !== undefined) && (feature.geometry.type === 'Polygon');
|
||||
|
@ -475,8 +493,7 @@ function eachFeature(feature, layer) {
|
|||
circle_alert.on({
|
||||
mouseover: function () {
|
||||
this.openPopup();
|
||||
bindEventsOnJosmRemote();
|
||||
updateExternalEditorsLinks();
|
||||
bindEventsOnJosmRemote(this.getPopup().getElement());
|
||||
bindFullDetails(feature);
|
||||
},
|
||||
mouseout: function () {
|
||||
|
@ -484,8 +501,7 @@ function eachFeature(feature, layer) {
|
|||
},
|
||||
click: function () {
|
||||
this.openPopup();
|
||||
bindEventsOnJosmRemote();
|
||||
updateExternalEditorsLinks();
|
||||
bindEventsOnJosmRemote(this.getPopup().getElement());
|
||||
bindFullDetails(feature);
|
||||
|
||||
},
|
||||
|
@ -519,7 +535,7 @@ function eachFeature(feature, layer) {
|
|||
circle.on({
|
||||
mouseover: function () {
|
||||
this.openPopup();
|
||||
bindEventsOnJosmRemote();
|
||||
bindEventsOnJosmRemote(this.getPopup().getElement());
|
||||
bindFullDetails(feature);
|
||||
},
|
||||
mouseout: function () {
|
||||
|
@ -527,7 +543,7 @@ function eachFeature(feature, layer) {
|
|||
},
|
||||
click: function () {
|
||||
this.openPopup();
|
||||
bindEventsOnJosmRemote();
|
||||
bindEventsOnJosmRemote(this.getPopup().getElement());
|
||||
bindFullDetails(feature);
|
||||
},
|
||||
});
|
||||
|
@ -543,12 +559,12 @@ function bindFullDetails(feature) {
|
|||
let content = '<table>' +
|
||||
'<tbody>' + ''
|
||||
|
||||
let ii=0
|
||||
let ii = 0
|
||||
let keys = Object.keys(feature.properties.tags)
|
||||
keys.forEach( (elem, val) => {
|
||||
console.log('elem, val', elem, val)
|
||||
content += '<tr><td>'+elem+'</td><td>'+feature.properties.tags[elem]+'</td></tr>';
|
||||
ii++;
|
||||
keys.forEach((elem, val) => {
|
||||
console.log('elem, val', elem, val)
|
||||
content += '<tr><td>' + elem + '</td><td>' + feature.properties.tags[elem] + '</td></tr>';
|
||||
ii++;
|
||||
})
|
||||
content += '</tbody>' +
|
||||
'</table>'
|
||||
|
@ -660,6 +676,16 @@ function onMapMoveEnd() {
|
|||
}
|
||||
}
|
||||
|
||||
// Ajout d'un log pour déboguer
|
||||
console.log("Zoom actuel:", map.getZoom());
|
||||
|
||||
if (map.getZoom() > 12) {
|
||||
console.log("Recherche des issues Osmose...");
|
||||
searchOsmoseIssues(map);
|
||||
} else {
|
||||
console.log("Zoom trop faible pour les issues Osmose");
|
||||
osmose_markers.clearLayers();
|
||||
}
|
||||
}
|
||||
|
||||
setCoordinatesOfLeafletMapFromQueryParameters()
|
||||
|
@ -784,12 +810,10 @@ function searchFoodPlaces(map) {
|
|||
const query = `
|
||||
[out:json][timeout:25];
|
||||
(
|
||||
node["amenity"="restaurant"](${bbox});
|
||||
node["amenity"="cafe"](${bbox});
|
||||
nwr["amenity"="restaurant"](${bbox});
|
||||
nwr["amenity"="cafe"](${bbox});
|
||||
);
|
||||
out body;
|
||||
>;
|
||||
out skel qt;`;
|
||||
out center;`;
|
||||
|
||||
const url = `https://overpass-api.de/api/interpreter?data=${encodeURIComponent(query)}`;
|
||||
|
||||
|
@ -798,21 +822,21 @@ function searchFoodPlaces(map) {
|
|||
fetch(url)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const geojson = osmtogeojson(data);
|
||||
geojson.features.forEach(feature => {
|
||||
const coords = feature.geometry.coordinates;
|
||||
const properties = feature.properties;
|
||||
const name = properties.tags.name || 'Sans nom';
|
||||
const type = properties.tags.amenity;
|
||||
data.elements.forEach(element => {
|
||||
// Utiliser les coordonnées du centre pour les ways et relations
|
||||
const lat = element.lat || element.center.lat;
|
||||
const lon = element.lon || element.center.lon;
|
||||
const name = element.tags.name || 'Sans nom';
|
||||
const type = element.tags.amenity;
|
||||
|
||||
const marker = L.marker([coords[1], coords[0]], {
|
||||
const marker = L.marker([lat, lon], {
|
||||
icon: foodIcon
|
||||
});
|
||||
|
||||
marker.bindPopup(`
|
||||
<strong>${name}</strong><br>
|
||||
Type: ${type}<br>
|
||||
${properties.tags.cuisine ? 'Cuisine: ' + properties.tags.cuisine : ''}
|
||||
${element.tags.cuisine ? 'Cuisine: ' + element.tags.cuisine : ''}
|
||||
`);
|
||||
|
||||
food_places_markers.addLayer(marker);
|
||||
|
@ -821,16 +845,150 @@ function searchFoodPlaces(map) {
|
|||
.catch(error => console.error('Erreur lors de la recherche des restaurants:', error));
|
||||
}
|
||||
|
||||
// Modifier la fonction init pour ajouter le contrôle des couches
|
||||
// Ajouter après la déclaration des autres variables globales
|
||||
let osmose_markers = L.layerGroup();
|
||||
const osmoseIcon = L.divIcon({
|
||||
className: 'osmose-marker-drop',
|
||||
html: '<div class="osmose-marker-inner">⚡</div>',
|
||||
iconSize: [30, 40],
|
||||
iconAnchor: [15, 40]
|
||||
});
|
||||
|
||||
// Ajouter cette nouvelle fonction
|
||||
function searchOsmoseIssues(map) {
|
||||
const bounds = map.getBounds();
|
||||
const zoom = map.getZoom();
|
||||
// Construction de la bbox avec l'ordre correct : ouest,sud,est,nord
|
||||
const bbox = `${bounds.getWest()}%2C${bounds.getSouth()}%2C${bounds.getEast()}%2C${bounds.getNorth()}`;
|
||||
|
||||
// URL formatée selon l'exemple fourni
|
||||
const url = `https://osmose.openstreetmap.fr/api/0.3/issues?zoom=${zoom}&item=8410%2C8411&level=1%2C2%2C3&limit=500&bbox=${bbox}`;
|
||||
|
||||
console.log("Recherche des issues Osmose (liste) avec l'URL :", url);
|
||||
osmose_markers.clearLayers();
|
||||
|
||||
fetch(url)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
return response.text().then(text => { throw new Error(`Erreur HTTP ${response.status}: ${response.statusText}. Réponse : ${text}`); });
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
if (!data || !Array.isArray(data.issues)) {
|
||||
console.warn("Réponse Osmose (liste) inattendue ou pas d'issues:", data);
|
||||
return;
|
||||
}
|
||||
const issuesList = data.issues;
|
||||
console.log(`Nombre d'issues Osmose (liste) trouvées: ${issuesList.length}`);
|
||||
|
||||
issuesList.forEach(issueInfo => {
|
||||
// Vérifier si les coordonnées sont valides
|
||||
if (issueInfo.lat == null || issueInfo.lon == null) {
|
||||
console.warn("Issue Osmose sans coordonnées ignorée:", issueInfo);
|
||||
return; // Ignorer cette issue
|
||||
}
|
||||
|
||||
const lat = parseFloat(issueInfo.lat);
|
||||
const lon = parseFloat(issueInfo.lon);
|
||||
const issueId = issueInfo.id; // C'est l'UUID
|
||||
|
||||
// Vérifier si l'UUID est valide
|
||||
if (!issueId) {
|
||||
console.warn("Issue Osmose sans ID (UUID) ignorée:", issueInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
const osmoseMarker = L.circle([lat, lon], {
|
||||
color: "purple",
|
||||
fillColor: "purple",
|
||||
fillOpacity: 0.8,
|
||||
radius: 10,
|
||||
className: 'leaflet-osmose-layer',
|
||||
pane: 'markerPane',
|
||||
issueId: issueId
|
||||
});
|
||||
|
||||
// Préparer une popup de chargement simple
|
||||
osmoseMarker.bindPopup("Chargement des détails...");
|
||||
|
||||
osmoseMarker.on('click', function (e) {
|
||||
const clickedMarker = e.target;
|
||||
const storedIssueId = clickedMarker.options.issueId;
|
||||
|
||||
// Afficher immédiatement la popup de chargement
|
||||
clickedMarker.openPopup();
|
||||
|
||||
const detailUrl = `https://osmose.openstreetmap.fr/api/0.3/issue/${storedIssueId}?langs=auto`;
|
||||
console.log("Récupération des détails pour l'issue:", detailUrl);
|
||||
|
||||
fetch(detailUrl)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
return response.text().then(text => { throw new Error(`Erreur HTTP ${response.status}: ${response.statusText}. Réponse : ${text}`); });
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(issueDetails => {
|
||||
// Construire le contenu de la popup avec les détails
|
||||
let popupContent = `<strong>${issueDetails.title?.auto || 'Titre non disponible'}</strong><br>`;
|
||||
if (issueDetails.subtitle?.auto) {
|
||||
popupContent += `<p>${issueDetails.subtitle.auto}</p>`;
|
||||
}
|
||||
|
||||
let proposedTags = '';
|
||||
if (issueDetails.new_elems && issueDetails.new_elems[0] && issueDetails.new_elems[0].add) {
|
||||
proposedTags = '<table class="proposed-tags">';
|
||||
issueDetails.new_elems[0].add.forEach(tag => {
|
||||
proposedTags += `<tr><td>${tag.k}</td><td>${tag.v}</td></tr>`;
|
||||
});
|
||||
proposedTags += '</table>';
|
||||
popupContent += `<div class="proposed-tags-container"><h4>Tags proposés :</h4>${proposedTags}</div>`;
|
||||
}
|
||||
|
||||
// Construire le lien JOSM /import
|
||||
const josmFixUrl = `http://localhost:8111/import?url=https://osmose.openstreetmap.fr/api/0.3/issue/${storedIssueId}/fix/0`;
|
||||
|
||||
popupContent += `
|
||||
<div class="action-buttons">
|
||||
<a class="edit-button josm" data-href="${josmFixUrl}" href="#" title="Ouvre JOSM et charge la correction proposée">⚡ Réparer dans JOSM</a>
|
||||
<a href="https://osmose.openstreetmap.fr/fr/issue/${storedIssueId}" target="_blank" title="Voir les détails de l'alerte sur le site Osmose">Voir sur Osmose</a>
|
||||
</div>`;
|
||||
|
||||
// Mettre à jour le contenu de la popup et s'assurer qu'elle est ouverte
|
||||
clickedMarker.setPopupContent(popupContent);
|
||||
clickedMarker.openPopup(); // Rouvrir pour ajuster la taille si nécessaire
|
||||
|
||||
// Lier l'événement au bouton JOSM DANS la popup
|
||||
bindEventsOnJosmRemote(clickedMarker.getPopup().getElement());
|
||||
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Erreur lors de la récupération des détails de l'issue Osmose:", error);
|
||||
clickedMarker.setPopupContent(`Erreur lors du chargement des détails.<br><a href="https://osmose.openstreetmap.fr/fr/issue/${storedIssueId}" target="_blank">Voir sur Osmose</a>`);
|
||||
clickedMarker.openPopup();
|
||||
});
|
||||
});
|
||||
|
||||
osmose_markers.addLayer(osmoseMarker);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Erreur détaillée lors de la recherche de la liste des issues Osmose:', error);
|
||||
});
|
||||
}
|
||||
|
||||
// Modifier la fonction init pour ajouter le nouveau calque
|
||||
function init() {
|
||||
|
||||
food_places_markers.addTo(map);
|
||||
$('#found_charging_stations').hide();
|
||||
|
||||
// Ajouter le contrôle des couches
|
||||
// Mettre à jour le contrôle des calques
|
||||
const overlayMaps = {
|
||||
"Stations de recharge": all_stations_markers,
|
||||
"Restaurants et cafés": food_places_markers
|
||||
"Restaurants et cafés": food_places_markers,
|
||||
"Bornes potentielles (Osmose)": osmose_markers
|
||||
};
|
||||
|
||||
L.control.layers(null, overlayMaps).addTo(map);
|
||||
|
@ -851,23 +1009,25 @@ function init() {
|
|||
console.log('Données envoyées à JOSM avec succès !');
|
||||
})
|
||||
.catch(() => {
|
||||
alert('Erreur : JOSM doit être ouvert avec l\'option "Contrôle à distance" activée');
|
||||
alert('Erreur : JOSM doit être ouvert avec l\'option de télécommande "Contrôle à distance" activée dans ses paramètres (accédez-y avec F12)');
|
||||
});
|
||||
});
|
||||
|
||||
$('#searchButton').on('click', searchLocation);
|
||||
$('#shareUrl').on('click', copyCurrentUrl);
|
||||
|
||||
|
||||
$('#searchResults').on('change', function() {
|
||||
|
||||
|
||||
$('#searchResults').on('change', function () {
|
||||
const selectedIndex = $(this).val();
|
||||
if (selectedIndex !== null) {
|
||||
const selectedPlace = $(this).find('option:selected').data('place');
|
||||
moveToLocation(selectedPlace);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
document.getElementById('searchButton').addEventListener('click', searchLocation);
|
||||
|
||||
osmose_markers.addTo(map);
|
||||
}
|
||||
|
||||
|
||||
|
@ -882,52 +1042,56 @@ function copyCurrentUrl() {
|
|||
document.execCommand('copy');
|
||||
document.body.removeChild(dummy);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function searchLocation() {
|
||||
const location = $('#searchLocation').val();
|
||||
if (!location) {
|
||||
alert('Veuillez entrer un lieu à rechercher.');
|
||||
return;
|
||||
}
|
||||
|
||||
const url = `https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(location)}`;
|
||||
|
||||
fetch(url)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const resultsDropdown = $('#searchResults');
|
||||
resultsDropdown.empty(); // Clear previous results
|
||||
|
||||
if (data.length === 0) {
|
||||
alert('Lieu non trouvé. Veuillez essayer un autre terme de recherche.');
|
||||
resultsDropdown.hide();
|
||||
} else if (data.length === 1) {
|
||||
const place = data[0];
|
||||
moveToLocation(place);
|
||||
resultsDropdown.hide();
|
||||
} else {
|
||||
data.forEach((place, index) => {
|
||||
const option = $('<option></option>')
|
||||
.val(index)
|
||||
.text(`${place.display_name} (${place.lat}, ${place.lon})`);
|
||||
resultsDropdown.append(option);
|
||||
});
|
||||
resultsDropdown.show();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Erreur lors de la recherche du lieu :', error);
|
||||
alert('Erreur lors de la recherche du lieu.');
|
||||
});
|
||||
}
|
||||
|
||||
function moveToLocation(place) {
|
||||
const lat = parseFloat(place.lat);
|
||||
const lon = parseFloat(place.lon);
|
||||
map.setView([lat, lon], 13); // Ajustez le niveau de zoom selon vos besoins
|
||||
}
|
||||
|
||||
|
||||
init()
|
||||
|
||||
function searchLocation() {
|
||||
const location = $('#searchLocation').val();
|
||||
if (!location) {
|
||||
alert('Veuillez entrer un lieu à rechercher.');
|
||||
return;
|
||||
}
|
||||
|
||||
const url = `https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(location)}`;
|
||||
|
||||
fetch(url)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const resultsDropdown = $('#searchResults');
|
||||
resultsDropdown.empty(); // Clear previous results
|
||||
|
||||
if (data.length === 0) {
|
||||
alert('Lieu non trouvé. Veuillez essayer un autre terme de recherche.');
|
||||
resultsDropdown.hide();
|
||||
} else if (data.length === 1) {
|
||||
const place = data[0];
|
||||
moveToLocation(place);
|
||||
resultsDropdown.hide();
|
||||
} else {
|
||||
data.forEach((place, index) => {
|
||||
const option = $('<option></option>')
|
||||
.val(index)
|
||||
.text(`${place.display_name} (${place.lat}, ${place.lon})`);
|
||||
resultsDropdown.append(option);
|
||||
});
|
||||
resultsDropdown.show();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Erreur lors de la recherche du lieu :', error);
|
||||
alert('Erreur lors de la recherche du lieu.');
|
||||
});
|
||||
}
|
||||
|
||||
function moveToLocation(place) {
|
||||
const lat = parseFloat(place.lat);
|
||||
const lon = parseFloat(place.lon);
|
||||
map.setView([lat, lon], 13); // Ajustez le niveau de zoom selon vos besoins
|
||||
}
|
||||
|
||||
|
||||
init()
|
||||
|
||||
// Créer un nouveau pane pour les marqueurs Osmose avec un zIndex plus élevé
|
||||
map.createPane('osmosePane');
|
||||
map.getPane('osmosePane').style.zIndex = 1000;
|
Loading…
Add table
Add a link
Reference in a new issue