PageSourceSearch

https://123gite.fr/grange/carte.js?v=1790490828

js 123gite.fr collected 2026-10-10 00:43:51 UTC 6,251 bytes, 113 lines download raw bytes

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('&copy; <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.