/** * js/map.js */ /** * Récupérer le nom du fichier actuel (ex: 971.php) et en extraire le code du département (ex: 971). */ const currentFileName = window.location.pathname.split('/').pop() const codeDepartement = currentFileName.split('.')[0] /** * Définir le centre , le niveau de zoom et le style de la carte en fonction du code du département. */ let centerCoordinates let zoomLevel let styleFileName switch (codeDepartement) { case '971': centerCoordinates = [-61.4167, 16.25] // Guadeloupe zoomLevel = 9 styleFileName = 'ortho.json' break case '972': centerCoordinates = [-61.01635, 14.60285] // Martinique zoomLevel = 9.5 styleFileName = 'ortho.json' break case '973': centerCoordinates = [-53.1258, 3.9339] // Guyane française zoomLevel = 7 styleFileName = 'ortho-jwe.json' break case '974': centerCoordinates = [55.52905, -21.13014] // La Réunion styleFileName = 'ortho.json' zoomLevel = 9.5 break default: centerCoordinates = [-61.4167, 16.25] // Par défaut (Guadeloupe) styleFileName = 'ortho.json' zoomLevel = 9.5 } /** * Initialise et configure la carte */ const map = new maplibregl.Map({ container: 'map', style: `../kat/styles/${styleFileName}`, center: centerCoordinates, zoom: zoomLevel }) if (codeDepartement !== '973') { /** * Désactive le zoom, le double-clic, le déplacement de la carte pour les cartes autres que celle la Guyane. */ map.scrollZoom.disable() map.doubleClickZoom.disable() map.dragPan.disable() } else { /** * Ajoute les contrôles de navigation à la carte, et définit les niveaux de zoom minimum et maximum pour la Guyane. */ map.addControl(new maplibregl.NavigationControl({showCompass: false})) map.setMinZoom(7) map.setMaxZoom(9.5) } /** * Définit les décalages des popups en fonction de leur position. */ const popupOffsets = { 'top': [0, 0], 'top-left': [0, 0], 'top-right': [0, 0], 'bottom': [0, -30], 'bottom-left': [0, -50], 'bottom-right': [0, -50], 'left': [25, -25], 'right': [-25, -25] } /** * Référence aux éléments HTML pour afficher le score. */ const ok = document.getElementById('OK') const ko = document.getElementById('KO') /** * État actuel de la commune survolée. */ let hoveredStateId = null /** * Référence à la commune actuellement sélectionnée pour trouver. */ let currentCommune = null /** * Ensemble des codes des communes déjà trouvées correctement. */ const correctAnswers = new Set() /** * Récupère les propriétés des communes depuis un fichier GeoJSON en fonction du code du département. * * @async * @param {string} codeDepartement - Numéro du département. * @returns {Promise} Promesse résolue avec les propriétés des communes. */ async function getFile(codeDepartement) { try { const response = await fetch(`../kat/data/${codeDepartement}/contours-communes.geojson`) if (!response.ok) { throw new Error(`Échec du chargement du fichier JSON : ${response.statusText}`) } data = await response.json() return data.features.map(({properties}) => properties) } catch (error) { console.error('Erreur:', error) throw new Error(error) } } /** * Récupère les coordonnées du centre de la commune depuis le fichier "centres.json" en fonction du code du département. * * @param {string} codeDepartement - Numéro du département. * @param {string} communeCode - Code de la commune. * @returns {Promise} Promesse résolue avec les coordonnées du centre de la commune. */ async function getCommuneCenterCoordinates(codeDepartement, communeCode) { try { // Utiliser fetch pour lire le fichier "centres.json" const response = await fetch(`../kat/data/${codeDepartement}/centres.json`) if (!response.ok) { throw new Error(`Échec du chargement du fichier JSON : ${response.statusText}`) } const centerData = await response.json() // Vérifier si le code de la commune existe dans les données if (communeCode in centerData) { const coordinates = centerData[communeCode] return coordinates } else { throw new Error(`Aucune donnée de centre trouvée pour la commune : ${communeCode}`) } } catch (error) { console.error('Erreur lors de la récupération des coordonnées du centre de la commune :', error) throw new Error(error) } } /** * Met à jour le score en fonction de la réponse. * * @param {boolean} isCorrect - Indique si la réponse est correcte. */ function updateScore(isCorrect) { if (isCorrect) { ok.innerText = Number.parseInt(ok.innerText, 10) + 1 } else { ko.innerText = Number.parseInt(ko.innerText, 10) + 1 } } /** * Sélectionne une commune au hasard parmi celles qui n'ont pas encore été trouvées. * * @param {Array} communes - Liste de toutes les communes. * @returns {Object|null} Retourne la commune sélectionnée ou null si toutes les communes ont été trouvées. */ function pickRandomCommune(communes) { const communesRestantes = communes.filter(commune => !correctAnswers.has(commune.code)) if (communesRestantes.length === 0) { return null } const index = Math.floor(Math.random() * communesRestantes.length) return communesRestantes[index] } /** * Définit la commune actuelle à trouver et met à jour l'affichage. * * @param {Object} commune - La commune à définir comme actuelle. */ function setCommune(commune) { if (currentCommune) { map.setFeatureState( {source: 'communes', id: currentCommune.code}, {current: false} ) } currentCommune = commune document.getElementById('commune').innerText = commune.nom map.setFeatureState( {source: 'communes', id: commune.code}, {current: true} ) } /** * Vérifie si le code de la commune cliquée correspond à la commune actuelle à trouver. * * @param {string} communeCode - Code de la commune à vérifier. * @returns {boolean} Résultat de la vérification. */ function checkAnswer(communeCode) { return currentCommune && communeCode === currentCommune.code } /** * Code pour la gestion des événements de la carte (load, mousemove, mouseleave, click). */ map.on('load', async () => { const communes = await getFile(codeDepartement) /** * Ajouter une source de données pour les communes. */ map.addSource('communes', { 'type': 'geojson', 'data': `../kat/data/${codeDepartement}/contours-communes.geojson`, 'promoteId': 'code' }) /** * Ajouter une couche de remplissage pour les communes. */ map.addLayer({ 'id': 'drom', 'type': 'fill', 'source': 'communes', 'layout': {}, 'paint': { 'fill-color': '#1F51FF', 'fill-opacity': [ 'case', ['boolean', ['feature-state', 'hover'], false], 0.8, 0 ] } }) /** * Ajouter une couche de remplissage pour les communes (2ème couche), en prenant en compte les réponses correctes et incorrectes. */ map.addLayer({ 'id': 'drom-2', 'type': 'fill', 'source': 'communes', 'layout': {}, 'paint': { 'fill-color': [ 'case', ['boolean', ['feature-state', 'correct'], false], '#00FF00', ['boolean', ['feature-state', 'incorrect'], false], '#FF0000', 'rgba(0,0,0,0)' ], 'fill-opacity': [ 'case', ['boolean', ['feature-state', 'hover'], false], 0.5, 0.8 ] } }) /** * Gère l'evenement mousemove (quand la souris survole la commune) */ map.on('mousemove', 'drom', e => { map.getCanvas().style.cursor = 'pointer' if (e.features.length > 0) { if (hoveredStateId) { map.setFeatureState( {source: 'communes', id: hoveredStateId}, {hover: false} ) } hoveredStateId = e.features[0].id map.setFeatureState( {source: 'communes', id: hoveredStateId}, {hover: true} ) } }) /** * Gère l'evenement mouseleave (quand la souris quitte la commune) */ map.on('mouseleave', 'drom', () => { map.getCanvas().style.cursor = '' if (hoveredStateId) { map.setFeatureState( {source: 'communes', id: hoveredStateId}, {hover: false} ) } hoveredStateId = null }) /** * Gère l'evenement click (quand on clique sur la commune) */ map.on('click', 'drom', async e => { if (e.features.length > 0) { const clickedCommuneCode = e.features[0].id const clickedCommuneNom = e.features[0].properties.nom const isCorrect = checkAnswer(clickedCommuneCode) if (isCorrect) { updateScore(true) const centerCoordinates = await getCommuneCenterCoordinates(codeDepartement, clickedCommuneCode) const popup = new maplibregl.Popup({offset: popupOffsets, closeButton: false, className: 'popup-ok'}) .setLngLat([centerCoordinates[0], centerCoordinates[1]]) .setHTML(`

Bravo, c'est ${clickedCommuneNom}

`) .setMaxWidth('200px') .addTo(map) setTimeout(() => { popup.remove() }, 1500) correctAnswers.add(clickedCommuneCode) communes.forEach(commune => { map.setFeatureState( {source: 'communes', id: commune.code}, {incorrect: false} ) }) map.setFeatureState( {source: 'communes', id: clickedCommuneCode}, {correct: true, current: false} ) const newCommune = pickRandomCommune(communes) if (newCommune) { setCommune(newCommune) } else { const totalAnswers = Number.parseInt(ok.innerText, 10) + Number.parseInt(ko.innerText, 10) const percentageCorrectAnswers = (Number.parseInt(ok.innerText, 10) / totalAnswers) * 100 alert(`Fin du jeu, ${Math.round(percentageCorrectAnswers)} % de bonnes réponses !`, ) setTimeout(() => { location.reload() }, 1500) } } else { updateScore(false) const centerCoordinates = await getCommuneCenterCoordinates(codeDepartement, clickedCommuneCode) const popup = new maplibregl.Popup({offset: popupOffsets, closeButton: false, className: 'popup-ko'}) .setLngLat([centerCoordinates[0], centerCoordinates[1]]) .setHTML(`

Faux, c'est ${clickedCommuneNom}

`) .setMaxWidth('200px') .addTo(map) setTimeout(() => { popup.remove() }, 1500) map.setFeatureState( {source: 'communes', id: clickedCommuneCode}, {incorrect: true} ) } } }) const commune = pickRandomCommune(communes) setCommune(commune) })