379 lines
14 KiB
JavaScript
379 lines
14 KiB
JavaScript
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: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
|
maxNativeZoom: 19,
|
|
maxZoom: 19
|
|
}).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 zoomend moveend", () => {
|
|
box.setBounds(getRectangleCoord(map))
|
|
})
|
|
|
|
btn.addEventListener("click", () => {
|
|
getServerBoxBounds(map, box);
|
|
});
|
|
|
|
addEventListener("resize", () => {
|
|
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 `<li ${props}>${p.name} - ${p.postcode} ${p.city}, ${p.county}</li>`;
|
|
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 = `<p class=deployeeAquilenet>Fibre deployée mais ne sera commandable qu\'à partir du ${building.aquilenetEligStatus.dateCommandable}</p>`
|
|
} else {
|
|
messageElig = `<p class=deployeeAquilenet>Fibre deployée et disponible par Aquilenet !</p>`
|
|
const zip = encodeURIComponent(building.codePostal);
|
|
const idImm = encodeURIComponent(building.idImm);
|
|
messageElig += `<br/><a href=${urlTestFTTH}?ftth=1&axione=1&adsltel=NOUVEAU&cp=${zip}&refimmeuble=${idImm}` +
|
|
` target="_blank">Tester l'éligibilité</a>`
|
|
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 = `<p class=deployeeFDN>Fibre deployee mais pas chez Axione !`
|
|
messageElig += `<br/><a href=${eligTestApi} target="_blank">Tester l'eligibilite par Kosc, Bouygues et Netwo</a></p>`
|
|
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 = `<p class=deployeeAutres>Fibre deployee mais non eligible Aquilenet, desole :(</p>`
|
|
colorMarker = 'red'
|
|
// Pas de fibre il semblerait, proposer un test ADSL Aquilenet
|
|
} else {
|
|
messageElig = `<p class=nonDeployee>Fibre non deployee :(</p>`
|
|
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 += `<br/><a href=${urlADSL}?zip=${zip}&city=${comm}&street=${street}&street_nb=${street_nb}&gps=&do=1&submit=Valider` +
|
|
`>Tester ADSL a cette adresse</a>`
|
|
if (building.othersEligStatus.reasonNotEligible != "") {
|
|
messageElig += `<br/><br/>Status general ARCEP: ${building.othersEligStatus.reasonNotEligible}`
|
|
}
|
|
}
|
|
// Si pas d'éligibilité fibre, on affiche la raison si elle existe
|
|
if (building.aquilenetEligStatus.reasonNotEligible != "") {
|
|
messageElig += `<br/> Pour Aquilenet, raison non eligible: ${building.aquilenetEligStatus.reasonNotEligible}`
|
|
if (building.aquilenetEligStatus.dateCommandable != "") {
|
|
messageElig += ` (date commandable: ${building.aquilenetEligStatus.dateCommandable})`
|
|
}
|
|
}
|
|
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]
|
|
});
|
|
// if (building.othersEligStatus.isEligible) {
|
|
// messageElig += `<br/><a target="_blank" href=/eligibilite/netwo?lat=${building.y}&lng=${building.x}` +
|
|
// `>Tester d'autres offres via Netwo</a>`
|
|
// }
|
|
const marker = new L.marker(latlng, {
|
|
icon: markerIcon,
|
|
zIndexOffset: - building.etat_imm_priority
|
|
})
|
|
.bindPopup(`${addrImm}<br/>${building.codePostal} ${building.commune}` +
|
|
`<br/><br/>${messageElig}<br/><br/>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);
|