Axione-IPE-Viewer/webapp/templates/app.js
2023-10-05 22:06:37 +02:00

374 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: '&copy; <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 = ``
// On construit l'appel API pour le test FTTH, on indique si c'est éligible Kosc et/ou Axione dans l'url
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 éligible peut-être Kosc ou au moins ARCEP
// Enfin on affiche un lien vers le test d'éligibilté FTTH avec Kosc & Netwo
} 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, Netwo et Bouygues</a></p>`
colorMarker = 'orange'
} 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><br/>Si la fibre a été recemment installée chez vous, il se pourrait que ce test soit erroné, <a href=${eligTestApi}>cliquez ici pour tout de même tester l'eligibilité fibre</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);