From da7292e74633d6f90c4df71e66c3e621cf5d8b68 Mon Sep 17 00:00:00 2001 From: Tykayn Date: Sun, 4 May 2025 23:22:35 +0200 Subject: [PATCH] =?UTF-8?q?add=20calcul=20itineraire=20et=20d=C3=A9charge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 38 ++++ js/lcm_main.js | 466 +++++++++++++++++++++++++++++++++++++---- js/lcm_routing.js | 8 + make_stats.js | 8 +- styles/_overrides.scss | 6 +- styles/main.scss | 10 + styles/style.css | 17 +- styles/style.css.map | 2 +- 8 files changed, 502 insertions(+), 53 deletions(-) create mode 100644 js/lcm_routing.js diff --git a/index.html b/index.html index 7a7b2d4..68e13fc 100644 --- a/index.html +++ b/index.html @@ -141,6 +141,44 @@ la nuit, ou bien où l'on séjourne plus longtemps.

+
+

Paramètres de la batterie

+

+ + +

+

+ + +

+

+ + +

+

+ + +

+

+ + +

+

Types de prises

diff --git a/js/lcm_main.js b/js/lcm_main.js index da05416..7df91a7 100644 --- a/js/lcm_main.js +++ b/js/lcm_main.js @@ -4,10 +4,18 @@ * lister les bornes trouvées dans la page * @type {boolean} */ + +import {lcm_i18n} from './lcm_i18n.js'; + + // Détecter la langue du navigateur + const currentLanguage = lcm_i18n.detectLanguage(); + console.log('Langue détectée:', currentLanguage); + import lcm_config from './lcm_config.js' import lcm_utils, { valid_qa_message } from './lcm_utils.js' import lcm_color_utils from './lcm_color_utils.js' import { sendToJOSM, createJOSMEditLink } from './lcm_editor.js' +import routing from './lcm_routing.js' let geojsondata; let lastLatLng; @@ -15,7 +23,16 @@ let searchLocationMarker = null; let count_hidden_by_filters = 0; let averageChargeKwh = 26; +let routePolyline = null; +let routeMarkers = []; +let startMarker = null; +let endMarker = null; +let startCoords = null; +let endCoords = null; +// Déclarer les variables d'itinéraire au début +let startItinerary = [0, 0]; +let endItinerary = [0, 0]; // serveurs de tuiles: https://wiki.openstreetmap.org/wiki/Tile_servers // https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png @@ -31,28 +48,22 @@ let averageChargeKwh = 26; let map = L.map('map') L.control.scale().addTo(map) +setCoordinatesOfLeafletMapFromQueryParameters() + /** * filtres à toggle par des boutons dans la page * à appliquer à chaque rafraîchissement des points geojson * TODO: make buttons and filter in refresh circles */ let filterStatesAvailable = ['hide', 'show', 'showOnly'] + -let filters_features = { - display_unknown_max_power_station: filterStatesAvailable[1] -} -let display_type2_sockets = 'show'; -let display_type2_combo_sockets = 'show'; let display_unknown_max_power_station = 'show'; let display_alert_cable_missing = 'show'; -let display_known_max_power_station = 'show'; -let display_type2_combo_sockets_with_cable = 'show'; -let display_lower_than_50kw = 'show'; -let display_higer_than_50kw = 'show'; -let display_lower_than_200kw = 'show'; -let display_higer_than_200kw = 'show'; -let display_chelou = 'show'; // les stations avec une valeur suspecte, plus de 400kW +const start = map.getCenter(); +const startLat = start.lat; +const startLon = start.lng; // Ajouter cette fonction avant searchLocation function moveToLocation(place) { @@ -198,7 +209,19 @@ function searchLocation() { .val(index) .text(displayText) .data('place', place); + + // Création du bouton itinéraire + const routeBtn = $('
`; - popupContent += josm_buttons - // Mettre à jour le contenu de la popup et s'assurer qu'elle est ouverte + popupContent += josm_buttons; clickedMarker.setPopupContent(popupContent); - // clickedMarker.openPopup(); // Rouvrir pour ajuster la taille si nécessaire $('#current_station_infos').html(`

Analyse Osmose

${josm_buttons} ${proposedTags}
`); - // 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.
Voir sur Osmose`); - // clickedMarker.openPopup(); }); }); osmose_markers.addLayer(osmoseMarker); }); - updateCounters(); // Mettre à jour l'affichage après le traitement + updateCounters(); }) .catch(error => { console.error('Erreur détaillée lors de la recherche de la liste des issues Osmose:', error); @@ -1355,11 +1419,19 @@ function searchOsmoseIssues(map) { // Ajouter un écouteur d'événements pour le changement de visibilité des calques function init() { + + bindEventsOnJosmRemote(); onMapMoveEnd(); map.on('moveend', onMapMoveEnd); $('#spinning_icon').hide(); + // ... dans la gestion du clic sur un résultat Addok ... + $('.route-to-place').on('click', function() { + const place = $(this).data('place'); + calculerEtAfficherItineraire(place, 'car'); + }); + /** * boutons de changement de filtres et de rechargement des bornes à l'affichage */ @@ -1547,4 +1619,310 @@ function updateFilteredStationsCount() { } else { $('#filter_max_output_display').after(filterStats); } +} +// au clic droit, proposer les points d'itinéraire +map.on('contextmenu', function(e) { + // Créer un menu contextuel simple + let popup = L.popup() + .setLatLng(e.latlng) + .setContent(` +
+ + `) + .openOn(map); +}); + + +// Fonctions globales pour le menu contextuel +window.setStartMarkerFromPopup = function(latlng) { + startItinerary = [latlng[0], latlng[1]] + + setStartMarker({lat: latlng[0], lng: latlng[1]}); + map.closePopup(); + if (endItinerary) calculerEtAfficherItineraire(); +}; +window.setEndMarkerFromPopup = function(latlng) { + setEndMarker({lat: latlng[0], lng: latlng[1]}); + endItinerary = [latlng[0], latlng[1]] + map.closePopup(); + if (startItinerary) calculerEtAfficherItineraire(); +}; + + +// Déclarer une variable globale pour le tracé +window.routePolyline = null; +window.lastRouteDestination = null; + +// Ajouter cette fonction avant calculerEtAfficherItineraire +async function searchChargingStationsAroundPoint(lat, lon, radius = 1500) { + const query = ` + [out:json][timeout:25]; + ( + node["amenity"="charging_station"](around:${radius},${lat},${lon}); + way["amenity"="charging_station"](around:${radius},${lat},${lon}); + relation["amenity"="charging_station"](around:${radius},${lat},${lon}); + ); + out body; + >; + out skel qt;`; + + const url = `https://overpass-api.de/api/interpreter?data=${encodeURIComponent(query)}`; + + try { + const response = await fetch(url); + const data = await response.json(); + return data.elements || []; + } catch (error) { + console.error('Erreur lors de la recherche des stations de recharge:', error); + return []; + } +} + +async function calculerEtAfficherItineraire(destination, mode = 'car') { + // Récupérer le point de départ (centre de la carte) + const startLat = startItinerary[0]; + const startLon = startItinerary[1]; + const endLat = endItinerary[0]; + const endLon = endItinerary[1]; + + // Récupérer les paramètres de la batterie + const batteryCapacity = parseFloat($('#battery_capacity').val()) || 40; + const batteryStartLevel = parseFloat($('#battery_start_level').val()) || 90; + const consumptionPerKm = parseFloat($('#consumption_per_km').val()) || 160; + const minBatteryLevel = parseFloat($('#min_battery_level').val()) || 15; + const chargeToLevel = parseFloat($('#charge_to_level').val()) || 80; + + // Construire l'URL OSRM + const url = `https://router.project-osrm.org/route/v1/${mode}/${startLon},${startLat};${endLon},${endLat}?overview=full&geometries=geojson&alternatives=false&steps=false`; + + $('#current_station_infos').html('Calcul de l\'itinéraire en cours…'); + + try { + const response = await fetch(url); + const data = await response.json(); + + if (!data.routes || !data.routes.length) { + $('#current_station_infos').html('Aucun itinéraire trouvé.'); + return; + } + + const route = data.routes[0]; + const coords = route.geometry.coordinates.map(c => [c[1], c[0]]); // [lat, lon] + + // Supprimer l'ancien tracé et les marqueurs + if (window.routePolyline) { + map.removeLayer(window.routePolyline); + } + if (window.pauseMarkers) { + window.pauseMarkers.forEach(marker => map.removeLayer(marker)); + } + if (window.batteryMarkers) { + window.batteryMarkers.forEach(marker => map.removeLayer(marker)); + } + + // Afficher le nouveau tracé sur la carte + window.routePolyline = L.polyline(coords, {color: '#0059ce', weight: 5}).addTo(map); + // Supprimer le fitBounds qui déplace la vue + // map.fitBounds(window.routePolyline.getBounds()); + + // Calculer la consommation totale + const totalDistanceKm = route.distance / 1000; + const totalConsumptionKwh = (totalDistanceKm * consumptionPerKm) / 1000; + const batteryStartKwh = (batteryCapacity * batteryStartLevel) / 100; + const batteryEndKwh = batteryStartKwh - totalConsumptionKwh; + const batteryEndLevel = (batteryEndKwh / batteryCapacity) * 100; + + // Ajouter les marqueurs de niveau de batterie + window.batteryMarkers = []; + const batteryLevels = [90, 80, 70, 60, 50, 40, 30, 20, 15]; + let accumulatedDistance = 0; + let currentBatteryLevel = batteryStartLevel; + + for (let i = 0; i < coords.length - 1; i++) { + const segmentDistance = L.latLng(coords[i]).distanceTo(coords[i + 1]) / 1000; // en km + const segmentConsumption = (segmentDistance * consumptionPerKm) / 1000; // en kWh + const nextBatteryLevel = ((batteryStartKwh - (accumulatedDistance * consumptionPerKm / 1000)) / batteryCapacity) * 100; + + // Vérifier si on atteint un niveau de batterie à marquer + for (const level of batteryLevels) { + if (currentBatteryLevel > level && nextBatteryLevel <= level) { + const ratio = (level - currentBatteryLevel) / (nextBatteryLevel - currentBatteryLevel); + const markerCoords = [ + coords[i][0] + (coords[i + 1][0] - coords[i][0]) * ratio, + coords[i][1] + (coords[i + 1][1] - coords[i][1]) * ratio + ]; + + const batteryMarker = L.marker(markerCoords, { + icon: L.divIcon({ + className: 'battery-marker', + html: `🔋 ${level}%`, + iconSize: [30, 30] + }) + }).addTo(map); + + let popupContent = `
+

Niveau de batterie : ${level}%

`; + + if (level <= minBatteryLevel) { + popupContent += `

⚠️ Recharge recommandée !

`; + } + + popupContent += `

Distance parcourue : ${(accumulatedDistance + segmentDistance * ratio).toFixed(1)} km

+

Consommation : ${((accumulatedDistance + segmentDistance * ratio) * consumptionPerKm / 1000).toFixed(1)} kWh

+
`; + + batteryMarker.bindPopup(popupContent); + window.batteryMarkers.push(batteryMarker); + } + } + + accumulatedDistance += segmentDistance; + currentBatteryLevel = nextBatteryLevel; + } + + // Calculer le nombre de pauses nécessaires (1 pause toutes les 2 heures) + const durationHours = route.duration / 3600; + const numberOfPauses = Math.floor(durationHours / 2); + const pauseDurationMinutes = 10; + const totalPauseTimeMinutes = numberOfPauses * pauseDurationMinutes; + + // Ajouter les marqueurs de pause + window.pauseMarkers = []; + if (numberOfPauses > 0) { + const totalDistance = route.distance; + const pauseInterval = totalDistance / (numberOfPauses + 1); + + for (let i = 1; i <= numberOfPauses; i++) { + const pauseDistance = pauseInterval * i; + let accumulatedDistance = 0; + let pauseCoords; + + // Trouver les coordonnées pour cette pause + for (let j = 0; j < coords.length - 1; j++) { + const segmentDistance = L.latLng(coords[j]).distanceTo(coords[j + 1]); + if (accumulatedDistance + segmentDistance >= pauseDistance) { + const ratio = (pauseDistance - accumulatedDistance) / segmentDistance; + pauseCoords = [ + coords[j][0] + (coords[j + 1][0] - coords[j][0]) * ratio, + coords[j][1] + (coords[j + 1][1] - coords[j][1]) * ratio + ]; + break; + } + accumulatedDistance += segmentDistance; + } + + if (pauseCoords) { + // Calculer la distance restante jusqu'à la prochaine pause ou la fin + const nextPauseDistance = (i < numberOfPauses) ? pauseInterval : (totalDistance - pauseDistance); + const consumptionToNextPause = (nextPauseDistance / 1000) * consumptionPerKm / 1000; // en kWh + const batteryLevelNeeded = (consumptionToNextPause / batteryCapacity) * 100 + minBatteryLevel; + + // Calculer le niveau de batterie actuel à ce point + const currentBatteryLevel = ((batteryStartKwh - (pauseDistance / 1000 * consumptionPerKm / 1000)) / batteryCapacity) * 100; + + // Rechercher les stations de recharge autour du point de pause + const chargingStations = await searchChargingStationsAroundPoint(pauseCoords[0], pauseCoords[1]); + + // Créer le contenu du popup avec les stations trouvées + let popupContent = `
+

Pause recommandée n°${i}

+

Durée : 10 minutes

+

Niveau de batterie actuel : ${currentBatteryLevel.toFixed(1)}%

+

Niveau de batterie nécessaire : ${batteryLevelNeeded.toFixed(1)}%

+

Distance jusqu'à la prochaine pause : ${(nextPauseDistance / 1000).toFixed(1)} km

`; + + if (chargingStations.length > 0) { + popupContent += `
+

Stations de recharge à proximité (${chargingStations.length}) :

+
    `; + + chargingStations.forEach(station => { + const name = station.tags?.name || 'Sans nom'; + const operator = station.tags?.operator || 'Opérateur inconnu'; + const distance = L.latLng(pauseCoords).distanceTo([station.lat, station.lon]).toFixed(0); + + popupContent += `
  • + ${name}
    + Opérateur : ${operator}
    + Distance : ${distance} m +
  • `; + }); + + popupContent += `
`; + } else { + popupContent += `

Aucune station de recharge trouvée dans un rayon de 1.5 km

`; + } + + popupContent += `
`; + + const pauseMarker = L.marker(pauseCoords, { + icon: L.divIcon({ + className: 'pause-marker', + html: '⏸️', + iconSize: [30, 30] + }) + }).addTo(map); + + pauseMarker.bindPopup(popupContent); + window.pauseMarkers.push(pauseMarker); + } + } + } + + // Afficher distance, durée, et boutons de mode de transport + const distanceKm = (route.distance / 1000).toFixed(1); + const durationMin = Math.round(route.duration / 60); + const totalDurationMin = durationMin + totalPauseTimeMinutes; + + // Convertir la durée totale en heures et minutes si nécessaire + let durationDisplay = ''; + if (totalDurationMin >= 60) { + const hours = Math.floor(totalDurationMin / 60); + const minutes = totalDurationMin % 60; + durationDisplay = `${hours}h${minutes > 0 ? ` ${minutes}min` : ''}`; + } else { + durationDisplay = `${totalDurationMin} min`; + } + + $('#current_station_infos').html(` +
+

Itinéraire

+
Distance : ${distanceKm} km
+
Durée estimée : ${durationDisplay} (dont ${totalPauseTimeMinutes} min de pause)
+
Nombre de pauses recommandées : ${numberOfPauses} (10 min toutes les 2h)
+
Niveau de batterie final estimé : ${batteryEndLevel.toFixed(1)}%
+
Consommation totale estimée : ${totalConsumptionKwh.toFixed(1)} kWh
+
+ + + +
+
+ `); + + // Stocker la destination pour recalculer facilement + window.lastRouteDestination = destination; + } catch (e) { + $('#current_station_infos').html('Erreur lors du calcul de l\'itinéraire.'); + } +} + +function setStartMarker(latlng) { + if (startMarker) map.removeLayer(startMarker); + startMarker = L.marker(latlng, { draggable: true, icon: L.divIcon({className: 'start-marker', html: '🟢', iconSize: [30, 30]}) }).addTo(map); + startCoords = [latlng.lat, latlng.lng]; + startMarker.on('dragend', function(e) { + startCoords = [e.target.getLatLng().lat, e.target.getLatLng().lng]; + if (endCoords) calculerEtAfficherItineraire(); + }); +} + +function setEndMarker(latlng) { + if (endMarker) map.removeLayer(endMarker); + endMarker = L.marker(latlng, { draggable: true, icon: L.divIcon({className: 'end-marker', html: '🔴', iconSize: [30, 30]}) }).addTo(map); + endCoords = [latlng.lat, latlng.lng]; + endMarker.on('dragend', function(e) { + endCoords = [e.target.getLatLng().lat, e.target.getLatLng().lng]; + if (startCoords) calculerEtAfficherItineraire(); + }); } \ No newline at end of file diff --git a/js/lcm_routing.js b/js/lcm_routing.js new file mode 100644 index 0000000..5562a43 --- /dev/null +++ b/js/lcm_routing.js @@ -0,0 +1,8 @@ +/** + * gestion des itinéraires pour libre charge map + */ +class routing{ + +} + +export default routing \ No newline at end of file diff --git a/make_stats.js b/make_stats.js index e1cce92..21c42f1 100644 --- a/make_stats.js +++ b/make_stats.js @@ -159,6 +159,7 @@ function compterFeaturesInOpenStreetMapFromFile() { const nombreFeaturesInOSM = data.elements.length; let countPointsDeChargeOSM = 0; + let validationErrors = {} // Initialiser le compteur pour chaque tag let tagsCountOSM = {}; @@ -176,11 +177,15 @@ function compterFeaturesInOpenStreetMapFromFile() { } // Compter les tags présents if (element.tags) { + + let tags = Object.keys(element.tags) + lcm_config.tags_to_display_in_popup.forEach(tag => { if (element.tags[tag] !== undefined && element.tags[tag] !== null && element.tags[tag] !== "") { tagsCountOSM[tag]++; } }); + } }); @@ -188,7 +193,8 @@ function compterFeaturesInOpenStreetMapFromFile() { ...stats, countStationsOSM: nombreFeaturesInOSM, countPointsDeChargeOSM: countPointsDeChargeOSM, - tagsCountOSM + tagsCountOSM, + validationErrors }; } catch (erreur) { console.error('Erreur lors du traitement du fichier OSM:', erreur.message); diff --git a/styles/_overrides.scss b/styles/_overrides.scss index 1ca8da1..af245b9 100644 --- a/styles/_overrides.scss +++ b/styles/_overrides.scss @@ -3,9 +3,9 @@ overrides leaflet */ -.leaflet-interactive { - border: solid 3px white; -} +// .leaflet-interactive { +// border: solid 3px white; +// } .leaflet-control-layers { &.leaflet-control-layers-toggle { diff --git a/styles/main.scss b/styles/main.scss index b0bd61e..6cdfe08 100644 --- a/styles/main.scss +++ b/styles/main.scss @@ -700,6 +700,16 @@ header { } } } +.routing{ + + .start-marker { font-size: 2em; } + .end-marker { font-size: 2em; } + .pause-marker { font-size: 2em; } + + .route-color{ + fill: #0059ce; + } +} @include meta.load-css('_osmose.scss'); @include meta.load-css('_recherche.scss'); diff --git a/styles/style.css b/styles/style.css index 1435a60..f829b3a 100644 --- a/styles/style.css +++ b/styles/style.css @@ -624,6 +624,19 @@ header img { height: 1rem; } +.routing .start-marker { + font-size: 2em; +} +.routing .end-marker { + font-size: 2em; +} +.routing .pause-marker { + font-size: 2em; +} +.routing .route-color { + fill: #0059ce; +} + .osmose-marker-drop:hover .osmose-marker-inner { animation: bounce 0.5s ease infinite; background-color: #9F2BFF; @@ -997,10 +1010,6 @@ label:hover .island .checkbox-custom { /** overrides leaflet */ -.leaflet-interactive { - border: solid 3px white; -} - .leaflet-control-layers.leaflet-control-layers-toggle { background: url("img/burger.png"); } diff --git a/styles/style.css.map b/styles/style.css.map index 8c598bc..17cc285 100644 --- a/styles/style.css.map +++ b/styles/style.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["main.scss","_osmose.scss","_recherche.scss","_filters.scss","_mobile.scss","_overrides.scss","_animations.scss","_stats.scss"],"names":[],"mappings":";AAIA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAKA;EACE;;AAGE;EACE;EACA;;AAKJ;EACE;;;AAMN;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;;AAIJ;EACE;;;AAGF;EACE;EACA;EACA;;;AAGF;AAAA;AAAA;AAAA;EAIE;EACA;EACA;EACA;EACA;;;AAKA;EACE;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;EACA;;AAGA;EACE;EACA;;;AAIJ;EACE;;;AAGF;EACE;EACA;EACA;;;AAGF;EAOE;;AANA;EACE;EACA;EACA;;;AAMJ;EACE;;;AAGF;EACE;IACE;;EAGF;IACE;;;AAIJ;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIF;EACE;EACA;EACA;;AAEA;EACE;;;AAIJ;AAAA;AAAA;AAIA;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;AAAA;EAEE;;;AAGF;AAAA;EAEE;;;AAGF;AAAA;EAEE;;;AAGF;AAAA;EAEE;;;AAGF;AAAA;EAEE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;AAEA;EACE;;;AAIJ;EACE;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAIF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAIA;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAIJ;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAGF;EACE;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;;AAIJ;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;;;AAOF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAIA;EACE;EACA;;;AAKN;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAMA;EACE;EACA;EACA;EACA;EACA;EACA;;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAIA;EACE;;;AAIJ;EACE;;AAUE;EACE;EACA;EACA;;AAcJ;EACE;;AAGF;EACE;;AAGF;EACE;EACA;;AAEA;EACE;EACA;EACA;;AAIJ;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAIA;EACE;EACA;;;AC1rBN;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAEA;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAKJ;EACE;EACA;EACA;EACA;;;AAEA;EACE;EACA;EACA;EACA;;;AAEA;EACE;;;AAIJ;EACE;EACA;;;AC3DJ;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAEA;EACE;EACA;;;AAEA;EACE;;;AAKN;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAEA;EACE;EACA;EACA;;;AAGF;EACE;;;AASJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;ACpEF;EACE;;;AAEA;EACE;EACA;EACA;;;AAGF;EACE;;;AAIJ;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAcF;AAAA;EAEE;EACA;EACA;EACA;EACA;;;AAEA;AAAA;EACE;EACA,OApDS;EAqDT;;;AAGF;AAAA;EAvBA;EACA;EAwBE;EACA;EArBF;EAuBE;EACA;;;AAEA;AAAA;EACE,YA/DK;;;AAmET;AAAA;EACE;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EA/CF;;;AAkDE;AAAA;EACE;;;AAIJ;AAAA;EACE,YA/FY;EAgGZ,cAhGY;EAiGZ;;;AAEA;AAAA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIJ;AAAA;EACE;EACA;EACA;EACA;;;AAGF;AAAA;EACE;EACA,OAxHS;EAsCX;;;AAsFA;AAAA;EACE;;;AAIA;AAAA;EACE,YAhIK;EAiIL,cAhIW;EAiIX;;;AAGF;AAAA;EACE,OArIW;EAsIX;;;AAMN;EACE;IACE;;EAGF;IACE;;EAGF;IACE;;;AC9JJ;AACA;EACE;IACE;IACA;;EAKA;AAAA;IAEE;IACA;;EAIJ;IACE;;EAGF;IAEE;IACA;IACA;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;;EAGF;IACE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAGF;AACE;;EAGF;IACE;IACA;IACA;IACA;IACA;;EAGF;IACE;;EAGF;AAAA;IAEE;IACA;IACA;IACA;IACA;IACA;;EAIF;IACE;;EAGF;IACE;;EAGF;IACE;IACA;IACA;IACA;IAEA;IACA;IACA;IACA;IACA;;EAIF;IAEE;;;ACrGJ;AAAA;AAAA;AAKA;EACE;;;AAIA;EACE;;;AAGF;EACE;;;AAKF;EACE;;;AAEA;EACE;EACA;;;AAKN;EACE;EACA;;;AAGF;AAEE;EACE;EACA;EACA;EACA;EACA;;;AAEA;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAIJ;EACE;EACA;EACA;EACA;EACA;;;AAEA;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAMN;EAyBE;EACA;EACA;EACA;;;AA1BE;EACE;EACA;EACA;EACA;EACA;EACA;;;AAKF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;ACnGN;EACE;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;;;AAIJ;EAEE;IAEE;;EAGF;IACE;;;ACtCJ;EACE;EACA;EACA;;;AAEA;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;;;AAKA;EACE;;;AAIJ;EACE;;;AAGF;EACE;EACA;;;AAEA;EACE;EACA;EACA;;;AP6pBN;EACE;EACA","file":"style.css"} \ No newline at end of file +{"version":3,"sourceRoot":"","sources":["main.scss","_osmose.scss","_recherche.scss","_filters.scss","_mobile.scss","_overrides.scss","_animations.scss","_stats.scss"],"names":[],"mappings":";AAIA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAKA;EACE;;AAGE;EACE;EACA;;AAKJ;EACE;;;AAMN;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;;AAIJ;EACE;;;AAGF;EACE;EACA;EACA;;;AAGF;AAAA;AAAA;AAAA;EAIE;EACA;EACA;EACA;EACA;;;AAKA;EACE;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;EACA;;AAGA;EACE;EACA;;;AAIJ;EACE;;;AAGF;EACE;EACA;EACA;;;AAGF;EAOE;;AANA;EACE;EACA;EACA;;;AAMJ;EACE;;;AAGF;EACE;IACE;;EAGF;IACE;;;AAIJ;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIF;EACE;EACA;EACA;;AAEA;EACE;;;AAIJ;AAAA;AAAA;AAIA;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;AAAA;EAEE;;;AAGF;AAAA;EAEE;;;AAGF;AAAA;EAEE;;;AAGF;AAAA;EAEE;;;AAGF;AAAA;EAEE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;AAEA;EACE;;;AAIJ;EACE;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAIF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAIA;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAIJ;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAGF;EACE;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;;AAIJ;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;;;AAOF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAIA;EACE;EACA;;;AAKN;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAMA;EACE;EACA;EACA;EACA;EACA;EACA;;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAIA;EACE;;;AAIJ;EACE;;AAUE;EACE;EACA;EACA;;AAcJ;EACE;;AAGF;EACE;;AAGF;EACE;EACA;;AAEA;EACE;EACA;EACA;;AAIJ;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAIA;EACE;EACA;;;AAMJ;EAAgB;;AAChB;EAAc;;AACd;EAAgB;;AAEhB;EACE;;;ACrsBJ;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAEA;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAKJ;EACE;EACA;EACA;EACA;;;AAEA;EACE;EACA;EACA;EACA;;;AAEA;EACE;;;AAIJ;EACE;EACA;;;AC3DJ;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAEA;EACE;EACA;;;AAEA;EACE;;;AAKN;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAEA;EACE;EACA;EACA;;;AAGF;EACE;;;AASJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;ACpEF;EACE;;;AAEA;EACE;EACA;EACA;;;AAGF;EACE;;;AAIJ;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAcF;AAAA;EAEE;EACA;EACA;EACA;EACA;;;AAEA;AAAA;EACE;EACA,OApDS;EAqDT;;;AAGF;AAAA;EAvBA;EACA;EAwBE;EACA;EArBF;EAuBE;EACA;;;AAEA;AAAA;EACE,YA/DK;;;AAmET;AAAA;EACE;EACA;EACA;EACA;EACA;;;AAGF;AAAA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EA/CF;;;AAkDE;AAAA;EACE;;;AAIJ;AAAA;EACE,YA/FY;EAgGZ,cAhGY;EAiGZ;;;AAEA;AAAA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIJ;AAAA;EACE;EACA;EACA;EACA;;;AAGF;AAAA;EACE;EACA,OAxHS;EAsCX;;;AAsFA;AAAA;EACE;;;AAIA;AAAA;EACE,YAhIK;EAiIL,cAhIW;EAiIX;;;AAGF;AAAA;EACE,OArIW;EAsIX;;;AAMN;EACE;IACE;;EAGF;IACE;;EAGF;IACE;;;AC9JJ;AACA;EACE;IACE;IACA;;EAKA;AAAA;IAEE;IACA;;EAIJ;IACE;;EAGF;IAEE;IACA;IACA;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;;EAGF;IACE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAGF;AACE;;EAGF;IACE;IACA;IACA;IACA;IACA;;EAGF;IACE;;EAGF;AAAA;IAEE;IACA;IACA;IACA;IACA;IACA;;EAIF;IACE;;EAGF;IACE;;EAGF;IACE;IACA;IACA;IACA;IAEA;IACA;IACA;IACA;IACA;;EAIF;IAEE;;;ACrGJ;AAAA;AAAA;AAUE;EACE;;;AAGF;EACE;;;AAKF;EACE;;;AAEA;EACE;EACA;;;AAKN;EACE;EACA;;;AAGF;AAEE;EACE;EACA;EACA;EACA;EACA;;;AAEA;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAIJ;EACE;EACA;EACA;EACA;EACA;;;AAEA;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAMN;EAyBE;EACA;EACA;EACA;;;AA1BE;EACE;EACA;EACA;EACA;EACA;EACA;;;AAKF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;ACnGN;EACE;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;;;AAIJ;EAEE;IAEE;;EAGF;IACE;;;ACtCJ;EACE;EACA;EACA;;;AAEA;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;;;AAKA;EACE;;;AAIJ;EACE;;;AAGF;EACE;EACA;;;AAEA;EACE;EACA;EACA;;;APuqBN;EACE;EACA","file":"style.css"} \ No newline at end of file