1/* carte.js â la carte des gîtes de l'accueil (design B). Leaflet + OpenStreetMap + Supercluster, 2 servis depuis /grange/vendor/ ; rien n'est chargé tant que le bloc n'approche pas de l'écran (IntersectionObserver), 3 puis les points arrivent en JSON compact [lat, lng, id] (/carte/gites.json, ~6 000 repères groupés en grappes) et la fiche 4 d'un repère se charge au clic (/carte/gite/{id}). Couleurs et formes du socle grange (braise, encre, pilules). */ 5(function(){ 6 'use strict'; 7 var conteneur = document.getElementById('grange-carte'); 8 if (!conteneur) return; 9 var BASE = conteneur.getAttribute('data-vendor') || '/grange/vendor/'; 10 var URL_POINTS = conteneur.getAttribute('data-points'); 11 var URL_FICHE = conteneur.getAttribute('data-fiche'); /* contient __ID__ */ 12 var cadre = conteneur.closest('.grange-plan') || conteneur; 13 var demarre = false; 14 15 function charger(src, css){ 16 return new Promise(function(ok, ko){ 17 var el; 18 if (css){ el = document.createElement('link'); el.rel = 'stylesheet'; el.href = src; } 19 else { el = document.createElement('script'); el.src = src; el.async = true; } 20 el.onload = ok; el.onerror = ko; 21 document.head.appendChild(el); 22 }); 23 } 24 25 var REPERE = '<svg width="30" height="38" viewBox="0 0 30 38" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">' 26 + '<path d="M15 0C6.7 0 0 6.7 0 15c0 11.3 15 23 15 23s15-11.7 15-23C30 6.7 23.3 0 15 0Z" fill="#F0512A" stroke="#fff" stroke-width="2"/>' 27 + '<path d="M9 16 15 11l6 5v6H9z" fill="none" stroke="#fff" stroke-width="2" stroke-linejoin="round"/></svg>'; 28 var REPERE_ACTIF = REPERE.replace('fill="#F0512A"', 'fill="#B93A12"'); 29 30 function iconeRepere(actif){ 31 return L.divIcon({ className: 'grange-repere-carte' + (actif ? ' grange-repere-carte--actif' : ''), html: actif ? REPERE_ACTIF : REPERE, iconSize: [30, 38], iconAnchor: [15, 38], popupAnchor: [0, -40] }); 32 } 33 function iconeGrappe(n){ 34 var taille = n < 50 ? 40 : n < 200 ? 50 : 60; 35 return L.divIcon({ className: 'grange-grappe-carte', html: '<div class="grange-grappe" style="width:' + taille + 'px;height:' + taille + 'px">' + n + '</div>', iconSize: [taille, taille], iconAnchor: [taille / 2, taille / 2] }); 36 } 37 38 function demarrer(){ 39 if (demarre) return; demarre = true; 40 cadre.setAttribute('data-etat', 'chargement'); 41 Promise.all([charger(BASE + 'leaflet.css', true), charger(BASE + 'leaflet.js'), charger(BASE + 'supercluster.min.js')]).then(init).catch(function(){ 42 cadre.setAttribute('data-etat', 'erreur'); 43 }); 44 } 45 46 function init(){ 47 var carte = L.map(conteneur, { scrollWheelZoom: false, zoomControl: false, attributionControl: false }).setView([46.6, 2.4], 6); 48 L.control.zoom({ position: 'bottomright' }).addTo(carte); 49 L.control.attribution({ position: 'bottomleft', prefix: false }) 50 .addAttribution('© <a href="https://www.openstreetmap.org/copyright" rel="noopener">OpenStreetMap</a>').addTo(carte); 51 L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19 }).addTo(carte); 52 53 var grappes = new Supercluster({ radius: 80, maxZoom: 16 }); 54 var couche = L.layerGroup().addTo(carte); 55 var actif = null, cache = {}; 56 57 function dessiner(){ 58 couche.clearLayers(); actif = null; 59 var b = carte.getBounds(), z = Math.round(carte.getZoom()); 60 grappes.getClusters([b.getWest(), b.getSouth(), b.getEast(), b.getNorth()], z).forEach(function(f){ 61 var lng = f.geometry.coordinates[0], lat = f.geometry.coordinates[1], p = f.properties; 62 if (p.cluster){ 63 var g = L.marker([lat, lng], { icon: iconeGrappe(p.point_count), keyboard: false }); 64 g.on('click', function(){ carte.flyTo([lat, lng], grappes.getClusterExpansionZoom(p.cluster_id)); }); 65 couche.addLayer(g); 66 return; 67 } 68 var m = L.marker([lat, lng], { icon: iconeRepere(false), alt: 'Gîte' }); 69 m.on('click', function(){ 70 if (actif && actif !== m) actif.setIcon(iconeRepere(false)); 71 m.setIcon(iconeRepere(true)); actif = m; 72 var bulle = L.popup({ maxWidth: 300, minWidth: 250, className: 'grange-bulle-carte', closeButton: true }); 73 bulle.setContent('<div class="grange-bulle-attente"><span></span></div>'); 74 m.bindPopup(bulle).openPopup(); 75 var id = p.i; 76 var rendre = function(html){ bulle.setContent(html); }; 77 if (cache[id]) return rendre(cache[id]); 78 fetch(URL_FICHE.replace('__ID__', id), { headers: { 'Accept': 'application/json' } }) 79 .then(function(r){ if (!r.ok) throw new Error(r.status); return r.json(); }) 80 .then(function(d){ cache[id] = d.html; rendre(d.html); }) 81 .catch(function(){ rendre('<p class="grange-bulle-erreur">Fiche indisponible pour le moment.</p>'); }); 82 }); 83 couche.addLayer(m); 84 }); 85 } 86 carte.on('popupclose', function(){ if (actif){ actif.setIcon(iconeRepere(false)); actif = null; } }); 87 88 fetch(URL_POINTS, { headers: { 'Accept': 'application/json' } }) 89 .then(function(r){ return r.json(); }) 90 .then(function(d){ 91 /* [lat, lng, id] -> GeoJSON pour Supercluster */ 92 var features = (d.p || []).map(function(pt){ return { type: 'Feature', geometry: { type: 'Point', coordinates: [pt[1], pt[0]] }, properties: { i: pt[2] } }; }); 93 grappes.load(features); 94 dessiner(); 95 carte.on('moveend', dessiner); 96 cadre.setAttribute('data-etat', 'pret'); 97 var compte = document.getElementById('grange-carte-compte'); 98 if (compte) compte.textContent = features.length.toLocaleStr
98ing('fr-FR') + ' gîtes géolocalisés'; 99 }) 100 .catch(function(){ cadre.setAttribute('data-etat', 'erreur'); }); 101 } 102 103 if ('IntersectionObserver' in window){ 104 var obs = new IntersectionObserver(function(entrees){ 105 entrees.forEach(function(e){ if (e.isIntersecting){ obs.disconnect(); demarrer(); } }); 106 }, { rootMargin: '400px 0px' }); 107 obs.observe(conteneur); 108 } else { 109 demarrer(); 110 } 111 /* un clic ou une touche sur le cadre lance aussi le chargement (au cas où l'observateur tarde) */ 112 conteneur.addEventListener('click', demarrer, { once: true }); 113})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.