const minZoomForRequest = 16; const urlADSL = 'https://tools.aquilenet.fr/cgi-bin/recherchend.cgi' const urlTestFTTH = 'https://tools.aquilenet.fr/cgi-bin/test.cgi' const streetTypeConversion = new Map(); streetTypeConversion.set("aire", "aire") streetTypeConversion.set("allée", "all") streetTypeConversion.set("allee", "all") streetTypeConversion.set("avenue", "av") streetTypeConversion.set("base", "base") streetTypeConversion.set("boulevard", "bd") streetTypeConversion.set("cami", "cami") streetTypeConversion.set("carrefour", "car") streetTypeConversion.set("chemin", "che") streetTypeConversion.set("cheminement", "chem") streetTypeConversion.set("chaussée", "chs") streetTypeConversion.set("cité", "cite") streetTypeConversion.set("cite", "cite") streetTypeConversion.set("clos", "clos") streetTypeConversion.set("coin", "coin") streetTypeConversion.set("corniche", "cor") streetTypeConversion.set("cote", "cote") streetTypeConversion.set("cour", "cour") streetTypeConversion.set("cours", "crs") streetTypeConversion.set("domaine", "dom") streetTypeConversion.set("descente", "dsc") streetTypeConversion.set("ecart", "eca") streetTypeConversion.set("esplanade", "esp") streetTypeConversion.set("faubourg", "fg") streetTypeConversion.set("gare", "gare") streetTypeConversion.set("grande rue", "gr") streetTypeConversion.set("hameau", "ham") streetTypeConversion.set("halle", "hle") streetTypeConversion.set("ilôt", "ilot") streetTypeConversion.set("impasse", "imp") streetTypeConversion.set("lieu dit", "ld") streetTypeConversion.set("lotissement", "lot") streetTypeConversion.set("marché", "mar") streetTypeConversion.set("montée", "mte") streetTypeConversion.set("parc", "parc") streetTypeConversion.set("passage", "pas") streetTypeConversion.set("place", "pl") streetTypeConversion.set("plan", "plan") streetTypeConversion.set("plaine", "pln") streetTypeConversion.set("plateau", "plt") streetTypeConversion.set("pont", "pont") streetTypeConversion.set("port", "port") streetTypeConversion.set("promenade", "pro") streetTypeConversion.set("parvis", "prv") streetTypeConversion.set("quartier", "qua") streetTypeConversion.set("quai", "quai") streetTypeConversion.set("résidence", "res") streetTypeConversion.set("residence", "res") streetTypeConversion.set("ruelle", "rle") streetTypeConversion.set("rocade", "roc") streetTypeConversion.set("rond point", "rpt") streetTypeConversion.set("route", "rte") streetTypeConversion.set("rue", "rue") streetTypeConversion.set("sentier", "sen") streetTypeConversion.set("sente", "sen") streetTypeConversion.set("square", "sq") streetTypeConversion.set("tour", "tour") streetTypeConversion.set("terre-plein", "tpl") streetTypeConversion.set("traverse", "tra") streetTypeConversion.set("villa", "vla") streetTypeConversion.set("village", "vlge ") streetTypeConversion.set("voie", "voie") streetTypeConversion.set("zone artisanale", "za") streetTypeConversion.set("zone d'aménagement concerté", "zac") streetTypeConversion.set("zone d'aménagement différé", "zad") streetTypeConversion.set("zone industrielle", "zi") streetTypeConversion.set("zone", "zone") let markers = new Map(); // Default search bounds DEFAULT_MAX_LNG_INTERVAL = 0.0028 DEFAULT_MAX_LAT_INTERVAL = 0.0014 // Search bounds from server server_max_lng_interval = undefined server_max_lat_interval = undefined function getRectangleCoord(map) { max_lng_interval = DEFAULT_MAX_LNG_INTERVAL max_lat_interval = DEFAULT_MAX_LAT_INTERVAL if (server_max_lat_interval !== undefined && server_max_lng_interval !== undefined) { max_lng_interval = server_max_lng_interval max_lat_interval = server_max_lat_interval } let center = map.getCenter(); let corner1 = L.latLng(center.lat - (max_lat_interval / 2), center.lng - (max_lng_interval / 2)); let corner2 = L.latLng(center.lat + (max_lat_interval / 2), center.lng + (max_lng_interval / 2)); return [corner1, corner2] } function initMap(btn) { // Init map position/zoom. Potentially using what's in the URL search string. const params = new URLSearchParams(window.location.search); let x = parseFloat(params.get('x')); let y = parseFloat(params.get('y')); let z = parseInt(params.get('z')); let map = L.map('map'); if (x && y && z) { map.setView([y, x], z); fetchEligData(map); } else { map.setView([46.710, 3.669], 6); } L.tileLayer('https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors' }).addTo(map); map.on("zoom move", () => { /* We only want to enable the search button when we reached a sufficient zoom level */ if (btn.disabled && map.getZoom() >= minZoomForRequest) { displayBtn(btn); } if (!btn.disabled && map.getZoom() < minZoomForRequest) { hideBtn(btn); } }); map.on("zoomend moveend", () => { if (map.getZoom() >= minZoomForRequest) { fetchEligData(map); } }); return map; } async function initLimitsBox(map, btn) { // Create box to show where data is fetched const box = createRectangleBox(map); await getServerBoxBounds(map, box); box.addTo(map); map.on("zoom move", () => { box.setBounds(getRectangleCoord(map)) }) btn.addEventListener("click", () => { getServerBoxBounds(map, box) }); } function createRectangleBox(map) { return L.rectangle(getRectangleCoord(map), {color: "#ff7800", fillOpacity: 0.07, weight: 1}); } // Ask server the narrowed area bounds that it will search in async function getServerBoxBounds(map, box) { const bounds = map.getBounds(); const sw = bounds.getSouthWest(); const ne = bounds.getNorthEast(); const reqUri = encodeURI(`eligdata/bounds?swx=${sw.lng}&swy=${sw.lat}&nex=${ne.lng}&ney=${ne.lat}`); const resp = await fetch(reqUri); if (resp.status != 200) { return } const data = await resp.json(); server_max_lat_interval = data.bounds.ney - data.bounds.swy server_max_lng_interval = data.bounds.nex - data.bounds.swx box.setBounds(getRectangleCoord(map)) } function initAddrSearch(map) { const autocompleteOptions = { debounceTime: 300, search: async (query) => { if (query.length > 2) { const mapCenter = map.getCenter(); const reqUri = `https://photon.komoot.io/api/?q=${encodeURI(query)}&lat=${mapCenter.lat}&lon=${mapCenter.lng}&limit=20&lang=fr`; const source = await fetch(reqUri); const data = await source.json(); return data.features; } else { return []; } }, renderResult: (res, props) => { const p = res.properties; if (p.name && p.postcode && p.city && p.county && res.geometry.coordinates && res.geometry.coordinates.length === 2) return `
  • ${p.name} - ${p.postcode} ${p.city}, ${p.county}
  • `; else return ""; }, onSubmit: async (res) => { const searchInput = document.getElementById('search-addr-autocomplete-input'); const p = res.properties; searchInput.value = `${p.name} - ${p.postcode} ${p.city}, ${p.county}`; // We already filtered out the result not having strictly 2 coordinates at item display map.setView([res.geometry.coordinates[1], res.geometry.coordinates[0]], 19); fetchEligData(map); } }; const autocompleteAddr = new Autocomplete("#search-addr-autocomplete", autocompleteOptions); return autocompleteAddr; } function updateEligData(map, eligData) { let buildings = eligData.buildings; buildings.forEach(building => { if (! markers.has(building.idImm)) { const latlng = new L.latLng(building.y, building.x); let addrImm = `${building.numVoieImm} ${building.typeVoieImm} ${building.nomVoieImm}` if (building.bat_info != "") { addrImm += ` (Bat ${building.bat_info})` } let colorMarker = 'black' let messageElig = `` eligTestApi = `eligtest/ftth?idImm=${building.idImm}&codePostal=${building.codePostal}&axione=${building.aquilenetEligStatus.isEligible}&liazo=${building.fdnEligStatus.isEligible}` // éligible chez Aquilenet, lien pour le test if (building.aquilenetEligStatus.isEligible) { // Si fibre Axione déployé mais pas encore commandable if (building.aquilenetEligStatus.ftthStatus == "DEPLOYE MAIS NON COMMANDABLE") { colorMarker = 'orange' messageElig = `

    Fibre deployée mais ne sera commandable qu\'à partir du ${building.aquilenetEligStatus.dateCommandable}

    ` } else { messageElig = `

    Fibre deployée et disponible par Aquilenet !

    ` const zip = encodeURIComponent(building.codePostal); const idImm = encodeURIComponent(building.idImm); messageElig += `
    Tester l'éligibilité` colorMarker = 'green' } // pas de données Axione mais Kosc nous renvoie qque chose à cette adresse (fdnEligStatus) // c'est peut être OK, on croise avec les données ARCEP (othersEligStatus) // Enfin on affiche un lien vers le test d'éligibilté KOSC à cette adresse } else if (building.fdnEligStatus.isEligible && building.othersEligStatus.isEligible) { messageElig = `

    Fibre deployee mais pas chez Axione !` messageElig += `
    Tester l'eligibilite par Kosc et Bouygues

    ` colorMarker = 'orange' // Pas de données Kosc ou Axione mais l'ARCEP nous dit qu'une fibre est déployée à cette adresse } else if (building.othersEligStatus.isEligible) { messageElig = `

    Fibre deployee mais non eligible Aquilenet, desole :(

    ` colorMarker = 'red' // Pas de fibre il semblerait, proposer un test ADSL Aquilenet } else { messageElig = `

    Fibre non deployee :(

    ` const zip = encodeURIComponent(building.codePostal); const comm = encodeURIComponent(building.commune); let convertType = streetTypeConversion.get(building.typeVoieImm.toLowerCase()); if (!convertType) { convertType = building.typeVoieImm; } const street = encodeURIComponent(`${convertType} ${building.nomVoieImm}`) const street_nb = encodeURIComponent(building.numVoieImm) messageElig += `
    Tester ADSL a cette adresse` if (building.othersEligStatus.reasonNotEligible != "") { messageElig += `

    Status general ARCEP: ${building.othersEligStatus.reasonNotEligible}` } } // Si pas d'éligibilité fibre, on affiche la raison si elle existe if (building.aquilenetEligStatus.reasonNotEligible != "") { messageElig += `
    Pour Aquilenet, raison non eligible: ${building.aquilenetEligStatus.reasonNotEligible}` } var markerIcon = new L.Icon({ iconUrl: `static/icons/marker-icon-${colorMarker}.png`, shadowUrl: 'static/vendor/images/marker-shadow.png', iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], shadowSize: [41, 41] }); const marker = new L.marker(latlng, { icon: markerIcon, zIndexOffset: - building.etat_imm_priority }) .bindPopup(`${addrImm}
    ${building.codePostal} ${building.commune}` + `

    ${messageElig}

    Ref Immeuble: ${building.idImm}`, { maxWidth: 560 }); map.addLayer(marker); markers.set(building.idImm, marker) } }); } function updateUrl(map) { const c = map.getCenter(); history.replaceState({}, "", encodeURI(`?x=${c.lng}&y=${c.lat}&z=${map.getZoom()}`)); } async function fetchEligData(map) { const zoom = map.getZoom(); if (zoom >= minZoomForRequest) { const bounds = map.getBounds(); const sw = bounds.getSouthWest(); const ne = bounds.getNorthEast(); let btn = document.getElementById("btn-load-elig-data"); waitBtn(btn); const reqUri = encodeURI(`eligdata?swx=${sw.lng}&swy=${sw.lat}&nex=${ne.lng}&ney=${ne.lat}`); const resp = await fetch(reqUri); if (resp.status == 200) { const eligData = await resp.json(); updateEligData(map, eligData); } else { error = await resp.text() console.log(`Error could not get data from server: ${resp.status} ${error}`) } updateUrl(map); displayBtn(btn); } } function initBtn() { const btn = document.getElementById("btn-load-elig-data"); btn.disabled = true; btn.title = "Veuillez zoomer plus la carte pour charger l'éligibilité."; return btn; } function setBtnListener(btn, map) { btn.onclick = () => { // Reset markers when button is clicked if (markers) { for (let marker of markers.values()){ map.removeLayer(marker); } markers.clear(); } fetchEligData(map); } } function displayBtn(btn) { btn.classList.remove('loader'); btn.disabled = false; btn.title = "Actualiser la recherche dans cette zone" btn.innerHTML = "Actualiser"; } function hideBtn(btn) { btn.disabled = true; btn.innerHTML = "Zoomez sur la carte"; btn.title = "Veuillez zoomer plus la carte afin de lancer la recherche d'éligibilité."; } function waitBtn(btn) { btn.disabled = true; btn.innerHTML = ""; btn.title = "Chargement des batiments..."; btn.classList.add('loader'); } // Init button and map const btn = initBtn(); const map = initMap(btn); const addrSearch = initAddrSearch(map); setBtnListener(btn, map); // Init a limits box that shows area where data will be fetched initLimitsBox(map, btn);