Axione-IPE-Viewer/webapp/templates/app.js

369 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'
}).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 `<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}` +
`>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}>Tester l'eligibilite par Kosc et Bouygues</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]
});
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);