Files
JWE/js/map.js
T

406 lines
12 KiB
JavaScript
Raw Normal View History

2024-02-05 00:00:56 +01:00
/**
* js/map.js
*/
2024-05-04 19:18:12 +04:00
/**
* Typos
*
* Après l'ajout de l'Afrique, on remplace "communes" par "zones"
* Zones = Communes ou Pays
*/
2024-02-05 00:00:56 +01:00
/**
* 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()
2024-05-04 19:18:12 +04:00
const codeCarte = currentFileName.split('.')[0]
2024-02-05 00:00:56 +01:00
/**
* 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
2024-05-04 19:18:12 +04:00
switch (codeCarte) {
2024-05-03 23:25:24 +04:00
case 'KAMA':
centerCoordinates = [21.21, 1.36] // Afrique
zoomLevel = 2.7
styleFileName = 'ortho-jwe-KAMA.json'
break
2024-02-05 00:00:56 +01:00
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',
2024-02-05 15:17:01 +01:00
style: `../kat/styles/${styleFileName}`,
2024-02-05 00:00:56 +01:00
center: centerCoordinates,
zoom: zoomLevel
})
2024-05-04 19:18:12 +04:00
if (codeCarte !== '973') {
2024-02-05 00:00:56 +01:00
/**
* 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)
}
2024-05-04 19:18:12 +04:00
if (codeCarte === 'KAMA') {
2024-05-03 23:25:24 +04:00
/**
2024-05-04 19:18:12 +04:00
* Ajoute les contrôles de navigation à la carte, et définit les niveaux de zoom minimum et maximum pour l'Afrique'.
2024-05-03 23:25:24 +04:00
*/
map.addControl(new maplibregl.NavigationControl({showCompass: false}))
map.setMinZoom(2.4)
map.setMaxZoom(9)
map.dragPan.enable()
}
2024-02-05 00:00:56 +01:00
/**
* 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.
*/
2024-05-04 19:18:12 +04:00
let currentZone = null
2024-02-05 00:00:56 +01:00
/**
* 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
2024-05-04 19:18:12 +04:00
* @param {string} codeCarte - Code de la carte.
2024-02-05 00:00:56 +01:00
* @returns {Promise<Object[]>} Promesse résolue avec les propriétés des communes.
*/
2024-05-04 19:18:12 +04:00
async function getFile(codeCarte) {
2024-02-05 00:00:56 +01:00
try {
2024-05-04 19:18:12 +04:00
const response = await fetch(`../kat/data/${codeCarte}/contours-${codeCarte === 'KAMA' ? 'pays' : 'communes'}.geojson`)
2024-02-05 00:00:56 +01:00
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.
*
2024-05-04 19:18:12 +04:00
* @param {string} codeCarte - Code de la carte.
* @param {string} codeZone - Code de la zone.
2024-02-05 00:00:56 +01:00
* @returns {Promise<number[]>} Promesse résolue avec les coordonnées du centre de la commune.
*/
2024-05-04 19:18:12 +04:00
async function getZoneCenterCoordinates(codeCarte, codeZone) {
2024-02-05 00:00:56 +01:00
try {
// Utiliser fetch pour lire le fichier "centres.json"
2024-05-04 19:18:12 +04:00
const response = await fetch(`../kat/data/${codeCarte}/centres.json`)
2024-02-05 00:00:56 +01:00
if (!response.ok) {
throw new Error(`Échec du chargement du fichier JSON : ${response.statusText}`)
}
const centerData = await response.json()
2024-05-04 19:18:12 +04:00
// Vérifier si le code de la zone existe dans les données
if (codeZone in centerData) {
const coordinates = centerData[codeZone]
2024-02-05 00:00:56 +01:00
return coordinates
} else {
2024-05-04 19:18:12 +04:00
throw new Error(`Aucune donnée de centre trouvée pour la commune : ${codeZone}`)
2024-02-05 00:00:56 +01:00
}
} 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.
*
2024-05-04 19:18:12 +04:00
* @param {Array} zones - Liste de toutes les zones.
* @returns {Object|null} Retourne la commune sélectionnée ou null si toutes les zones ont été trouvées.
2024-02-05 00:00:56 +01:00
*/
2024-05-04 19:18:12 +04:00
function pickRandomZone(zones) {
const zonesRestantes = zones.filter(commune => !correctAnswers.has(commune.code))
2024-02-05 00:00:56 +01:00
2024-05-04 19:18:12 +04:00
if (zonesRestantes.length === 0) {
2024-02-05 00:00:56 +01:00
return null
}
2024-05-04 19:18:12 +04:00
const index = Math.floor(Math.random() * zonesRestantes.length)
return zonesRestantes[index]
2024-02-05 00:00:56 +01:00
}
/**
2024-05-04 19:18:12 +04:00
* Définit la zone actuelle à trouver et met à jour l'affichage.
2024-02-05 00:00:56 +01:00
*
2024-05-04 19:18:12 +04:00
* @param {Object} zone - La zone à définir comme actuelle.
2024-02-05 00:00:56 +01:00
*/
2024-05-04 19:18:12 +04:00
function setZone(zone) {
if (currentZone) {
2024-02-05 00:00:56 +01:00
map.setFeatureState(
2024-05-04 19:18:12 +04:00
{source: 'communes', id: currentZone.code},
2024-02-05 00:00:56 +01:00
{current: false}
)
}
2024-05-04 19:18:12 +04:00
currentZone = zone
document.getElementById('commune').innerText = zone.nom
2024-02-05 00:00:56 +01:00
map.setFeatureState(
2024-05-04 19:18:12 +04:00
{source: 'communes', id: zone.code},
2024-02-05 00:00:56 +01:00
{current: true}
)
}
/**
2024-05-04 19:18:12 +04:00
* Vérifie si le code de la zone cliquée correspond à la commune actuelle à trouver.
2024-02-05 00:00:56 +01:00
*
2024-05-04 19:18:12 +04:00
* @param {string} codeZone - code de la zone à vérifier.
2024-02-05 00:00:56 +01:00
* @returns {boolean} Résultat de la vérification.
*/
2024-05-04 19:18:12 +04:00
function checkAnswer(codeZone) {
return currentZone && codeZone === currentZone.code
2024-02-05 00:00:56 +01:00
}
/**
* Code pour la gestion des événements de la carte (load, mousemove, mouseleave, click).
*/
map.on('load', async () => {
2024-05-04 19:18:12 +04:00
const zones = await getFile(codeCarte)
2024-02-05 00:00:56 +01:00
/**
* Ajouter une source de données pour les communes.
*/
map.addSource('communes', {
'type': 'geojson',
2024-05-04 19:18:12 +04:00
'data': `../kat/data/${codeCarte}/contours-${codeCarte === 'KAMA' ? 'pays' : 'communes'}.geojson`,
2024-02-05 00:00:56 +01:00
'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}
)
}
})
/**
2024-05-04 19:18:12 +04:00
* Gère l'evenement mouseleave (quand la souris quitte la zone)
2024-02-05 00:00:56 +01:00
*/
map.on('mouseleave', 'drom', () => {
map.getCanvas().style.cursor = ''
if (hoveredStateId) {
map.setFeatureState(
{source: 'communes', id: hoveredStateId},
{hover: false}
)
}
hoveredStateId = null
})
/**
2024-05-04 19:18:12 +04:00
* Gère l'evenement click (quand on clique sur la zone)
2024-02-05 00:00:56 +01:00
*/
map.on('click', 'drom', async e => {
if (e.features.length > 0) {
2024-05-04 19:18:12 +04:00
const clickedCodeZone = e.features[0].id
const clickedZoneNom = e.features[0].properties.nom
const isCorrect = checkAnswer(clickedCodeZone)
2024-02-05 00:00:56 +01:00
if (isCorrect) {
updateScore(true)
2024-05-04 19:18:12 +04:00
const centerCoordinates = await getZoneCenterCoordinates(codeCarte, clickedCodeZone)
2024-02-05 00:00:56 +01:00
const popup = new maplibregl.Popup({offset: popupOffsets, closeButton: false, className: 'popup-ok'})
.setLngLat([centerCoordinates[0], centerCoordinates[1]])
2024-05-04 19:18:12 +04:00
.setHTML(`<h3>Bravo, c'est ${clickedZoneNom}</h3>`)
2024-02-05 00:00:56 +01:00
.setMaxWidth('200px')
.addTo(map)
setTimeout(() => {
popup.remove()
}, 1500)
2024-05-04 19:18:12 +04:00
correctAnswers.add(clickedCodeZone)
zones.forEach(commune => {
2024-02-05 00:00:56 +01:00
map.setFeatureState(
{source: 'communes', id: commune.code},
{incorrect: false}
)
})
map.setFeatureState(
2024-05-04 19:18:12 +04:00
{source: 'communes', id: clickedCodeZone},
2024-02-05 00:00:56 +01:00
{correct: true, current: false}
)
2024-05-04 19:18:12 +04:00
const newZone = pickRandomZone(zones)
if (newZone) {
setZone(newZone)
2024-02-05 00:00:56 +01:00
} 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)
2024-05-04 19:18:12 +04:00
const centerCoordinates = await getZoneCenterCoordinates(codeCarte, clickedCodeZone)
2024-02-05 00:00:56 +01:00
const popup = new maplibregl.Popup({offset: popupOffsets, closeButton: false, className: 'popup-ko'})
.setLngLat([centerCoordinates[0], centerCoordinates[1]])
2024-05-04 19:18:12 +04:00
.setHTML(`<h3>Faux, c'est ${clickedZoneNom}</h3>`)
2024-02-05 00:00:56 +01:00
.setMaxWidth('200px')
.addTo(map)
setTimeout(() => {
popup.remove()
}, 1500)
map.setFeatureState(
2024-05-04 19:18:12 +04:00
{source: 'communes', id: clickedCodeZone},
2024-02-05 00:00:56 +01:00
{incorrect: true}
)
}
}
})
2024-05-04 19:18:12 +04:00
const zone = pickRandomZone(zones)
setZone(zone)
2024-02-05 00:00:56 +01:00
})