var coordinatesBB = [] //var url = "https://simstadt-api.iaf-ex.hft-stuttgart.de:8080/workflow/execute" //old link var url = "http://vm24.fkc.hft-stuttgart.de:8082/workflow/execute" // URL to API var url2 = "http://vm24.fkc.hft-stuttgart.de:8082/workflow/timedShadowValueByDay/" var pvURL = "http://vm24.fkc.hft-stuttgart.de:8082/workflow/readPVPotential" var localShadowData = "/public/test/APIdata/shadowData.json" var localPvpotentialData = "/public/test/APIdata/buildingInformation.json" var buildingFunctionSort var constructionYearSortPick var heightSortPick var heatedVolumeSortPick var totalSurfaceAreaSortPick var roofTypeSortPick var uValueSortPick var shadowdata var pvPotentialSurfaces; //array which holds the pvpotential of all surfaces async function fetchPvPotentialJSON() { var bottomLat = coordinatesBB[1] var leftLng = coordinatesBB[0] var rightLng = coordinatesBB[2] var topLat = coordinatesBB[3] const response = await fetch(pvURL, { method: "POST", body: JSON.stringify({ "boundingBox": { "bottomLat": bottomLat, //48.779004965, "leftLng": leftLng, //9.1686843081, "lodType": "LOD2", "rightLng": rightLng, //9.175336684, "topLat": topLat //48.7822869656 }, "cityGMLRef": "campusLOD2" }), headers: { "Content-Type": "application/json", "Authorization": "Basic YWRtaW46YWRtaW4xMjM=" } }) const data = await response.json(); return data } async function fetchshadowDataJSON() { var bottomLat = coordinatesBB[1] var leftLng = coordinatesBB[0] var rightLng = coordinatesBB[2] var topLat = coordinatesBB[3] // var day = "1"; const response = await fetch(url2 + day, { method: "POST", body: JSON.stringify({ "boundingBox": { "bottomLat": bottomLat, //48.779004965, "leftLng": leftLng, //9.1686843081, "lodType": "LOD2", "rightLng": rightLng, //9.175336684, "topLat": topLat //48.7822869656 }, "cityGMLRef": "campusLOD2" }), headers: { "Content-Type": "application/json", "Authorization": "Basic YWRtaW46YWRtaW4xMjM=" } }) const data = await response.json(); return data } async function fetchDataJSON() { var bottomLat = coordinatesBB[1] var leftLng = coordinatesBB[0] var rightLng = coordinatesBB[2] var topLat = coordinatesBB[3] // const response = await fetch(url, { method: "POST", body: JSON.stringify({ "boundingBox": { "bottomLat": bottomLat, //48.779004965, "leftLng": leftLng, //9.1686843081, "lodType": "LOD2", "rightLng": rightLng, //9.175336684, "topLat": topLat //48.7822869656 }, "cityGMLRef": "campusLOD2", "interestedAttributes": [ "uValue", "volume", "height", "heatedVolume", "yearOfConstruction", "buildingFunction", "monthlyHeating", "monthlyCooling", "pvPotential", "roofType", "totalSurfaceArea" ], "properies": { "physicsUseScenario": false } }), headers: { "Content-Type": "application/json", "Authorization": "Basic YWRtaW46YWRtaW4xMjM=" } }) const data = await response.json() return data } document.getElementById("loader").style.visibility = "hidden" async function getLocalShadowdata() { // gets the response from localShadowData and put it inside a constant const response = await fetch(localShadowData); //the response have to be converted to json type file, so it can be used const data = await response.json(); //console.log(data) return data; } async function processData() { console.log("Waiting for data....") shadowdata = await getLocalShadowdata() //waiting 25sec for the shadowData fetch from server: catching error if no answer in 25sec timeout(25000, fetchshadowDataJSON()).then((response) => { shadowdata = response; }).catch((error) => { //catching the error(no connection)/ timeout and displaying an alert for the user console.log(shadowdata); }) timeout(10000, fetchPvPotentialJSON()).then((response) => { pvPotentialSurfaces = getPvPotentialOfSurfaces(response["buildings"]); }).catch((error) => { console.log(error) }) timeout(10000, fetchDataJSON()).then((response) => { calculateData(response); }).catch((error) => { console.log(error) fetch(localPvpotentialData) .then(response => response.text()) .then(text => calculateData(JSON.parse(text))) }) } function calculateData(data) { document.getElementById("cesiumContainer").style.opacity = "1"; document.getElementById("loader").style.visibility = "hidden" console.log("....received data") var buildingsMAP = new Map() data.buildings.forEach(bu => { var partsArray = [] var surefacesArray = [] bu.parts.forEach(p => p.surfaces.forEach(s => surefacesArray.push(new Surface(s.id, s.attributes.uValue, s.attributes.totalSurfaceArea)))) bu.parts.forEach(p => partsArray.push(new Part(p.id, surefacesArray, p.attributes.volume, p.attributes.height, p.attributes.heatedVolume, p.attributes.yearOfConstruction, p.attributes.buildingFunction, p.attributes.monthlyHeating, p.attributes.monthlyCooling, p.attributes.roofType))) buildingsMAP.set(bu.id, new Building(bu.id, partsArray)) //puts buildings with parts and surfaces in a map }) var partHeightMAP = new Map() var partVolumeMAP = new Map() var partHeatedVolumeMAP = new Map() var partConstructionYearMAP = new Map() var partBuildingTypeMAP = new Map() var partMonthlyHeatingMAP = new Map() var partMonthlyCoolingMAP = new Map() var surfaceUValueMAP = new Map() var partRoofTypeMAP = new Map() var surfaceTotalSurfaceAreaMAP = new Map() //fill height, heated volume and construction year map buildingsMAP.forEach(b => { b.parts.forEach(part => { if (part.height !== undefined) { partHeightMAP.set(part.id, part.height) } if (part.volume !== undefined) { partVolumeMAP.set(part.id, part.volume) } if (part.heatedVolume !== undefined) { partHeatedVolumeMAP.set(part.id, part.heatedVolume) } if (part.yearOfConstruction !== undefined && part.yearOfConstruction <= "2020") { partConstructionYearMAP.set(part.id, part.yearOfConstruction) } if (part.buildingFunction !== undefined) { partBuildingTypeMAP.set(part.id, part.buildingFunction) } if (part.monthlyHeating !== undefined) { partMonthlyHeatingMAP.set(part.id, part.monthlyHeating) } if (part.monthlyCooling !== undefined) { partMonthlyCoolingMAP.set(part.id, part.monthlyCooling) } if (part.roofType !== undefined) { partRoofTypeMAP.set(part.id, part.roofType) } part.surfaces.forEach(s => { if (s.uValue !== undefined) { surfaceUValueMAP.set(s.id, s.uValue) } }) //totalSurfaceArea surfaceTotalSurfaceAreaMAP.set(part.id, part.surfaces) }) }) //sort maps const heightSort = new Map([...partHeightMAP.entries()].sort((a, b) => b[1] - a[1])); const heatedVolumeSort = new Map([...partHeatedVolumeMAP.entries()].sort((a, b) => b[1] - a[1])); const constructionYearSort = new Map([...partConstructionYearMAP.entries()].sort((a, b) => a[1] - b[1])); const uValueSort = new Map([...surfaceUValueMAP.entries()].sort((a, b) => b[1] - a[1])); //for Properties Single Buildings buildingFunctionSortPick = new Map([...partBuildingTypeMAP.entries()].sort((a, b) => b[1] - a[1])); constructionYearSortPick = new Map([...partConstructionYearMAP.entries()].sort((a, b) => a[1] - b[1])); heightSortPick = new Map([...partHeightMAP.entries()].sort((a, b) => b[1] - a[1])); heatedVolumeSortPick = new Map([...partHeatedVolumeMAP.entries()].sort((a, b) => b[1] - a[1])); totalSurfaceAreaSortPick = new Map([...surfaceTotalSurfaceAreaMAP.entries()].sort((a, b) => b[1] - a[1])); roofTypeSortPick = new Map([...partRoofTypeMAP.entries()].sort((a, b) => b[1] - a[1])); uValueSortPick = new Map([...surfaceUValueMAP.entries()].sort((a, b) => b[1] - a[1])); //fill arrays needed for charts heightSort.forEach((value, key) => addHeightInfosToArrays(key, value)) heatedVolumeSort.forEach((value, key) => addHeatedVolumeInfosToArrays(key, value)) constructionYearSort.forEach((value) => yearOfConstructionValues.push(value)) partBuildingTypeMAP.forEach((value) => buildingTypeValues.push(value)) partMonthlyHeatingMAP.forEach((valueArray, key) => yearlyHeatingDemand(key, valueArray)) partMonthlyCoolingMAP.forEach((valueArray, key) => yearlyCoolingDemand(key, valueArray)) uValueSort.forEach((value, key) => { uValueSurfaces(key, value) uValuesAll.push(value) }) partMonthlyHeatingMAP.forEach((value, key) => addmonthlyHeatingInfosToArrays(key, value)) partMonthlyCoolingMAP.forEach((value, key) => addmonthlyCoolingInfosToArrays(key, value)) partVolumeMAP.forEach((value, key) => addVolumeValues(key, value)) //calculates year of construction frequency yearFrequency() //calculates building type frequency buildingTypeFrequency() //calculates uValue frequency uValueFrequency() //sorts yearly heating & cooling demand for charts sortMap() //disables attributes in chart without values availableAttributes() //color buildings with heating demand document.getElementById("checkbox2").addEventListener("change", function() { if (this.checked) { tileContent.forEach(t => { let tileID = t.getProperty("gml_parent_id") let tileColor = heatingIDColorMAP.get(tileID) if (tileColor !== undefined) { t.color = Cesium.Color.fromCssColorString(tileColor) } else { t.color = new Cesium.Color(1, 1, 1, 1) } }) console.log("colored") } else { tileContent.forEach(t => t.color = new Cesium.Color(1, 1, 1, 1)) console.log("not colored") } }) //color surfaces with uValue document.getElementById("checkbox1").addEventListener("change", function() { if (this.checked) { tileContent.forEach(t => { let tileID = t.getProperty("gml_id") let tileColor = surfaceIDColorMAP.get(tileID) if (tileColor !== undefined) { t.color = Cesium.Color.fromCssColorString(tileColor) } else { t.color = new Cesium.Color(1, 1, 1, 1) } }) console.log("colored") } else { tileContent.forEach(t => t.color = new Cesium.Color(1, 1, 1, 1)) console.log("not colored") } }) } function showAllUVales() { this.parts.forEach(p => p.surfaces.forEach(s => console.log(s.uValue))) } function Building(id, parts) { this.id = id this.parts = parts this.showAllUVales = showAllUVales } function Part(id, surfaces, volume, height, heatedVolume, yearOfConstruction, buildingFunction, monthlyHeating, monthlyCooling, roofType) { this.id = id; this.surfaces = surfaces this.volume = volume this.height = height this.heatedVolume = heatedVolume this.yearOfConstruction = yearOfConstruction this.buildingFunction = buildingFunction this.monthlyHeating = monthlyHeating this.monthlyCooling = monthlyCooling this.roofType = roofType } function Surface(id, uValue, totalSurfaceArea) { this.id = id; this.uValue = uValue this.totalSurfaceArea = totalSurfaceArea } let tileContent = [] // When the user clicks the button, open the modal var elemurlevt = document.getElementById("submitID"); elemurlevt.addEventListener("click", loadTileset); //Get the modal var modal = document.getElementById("myModal"); var span = document.getElementsByClassName("close")[0]; //close the modal span.onclick = function() { modal.style.display = "none"; deleteTilesetButtons() } // modal closes, when the user clicks anywhere outside of the modal window.onclick = function(event) { if (event.target == modal) { modal.style.display = "none"; deleteTilesetButtons() } } //------------------------------------------------------------------------------- var tileData = null; var tileset = null; var tilesetURL = 'http://vm24.fkc.hft-stuttgart.de:8081/CampusLOD2/tileset.json'; var localTestTileset = getAbsoulteTestPath("/test/gmlTileset_v1.json"); function timeout(ms, promise) { return new Promise(function(resolve, reject) { setTimeout(function() { reject(new Error("timeout")) }, ms) promise.then(resolve, reject) }) } //getting the pvPotential of all surfaces from the pvPotential array, which the api returns function getPvPotentialOfSurfaces(pvPotentialarray) { var pvPotentialArray = []; pvPotentialarray.forEach( building => building["parts"].forEach( parts => parts["surfaces"].forEach( surface => pvPotentialArray.push(surface) ) ) ); return pvPotentialArray; } //fetching the tileset and handling the connection //waiting 1sec for the tileSetData fetch from server: catching error if no answer in 1sec function fetchTileset() { timeout(1000, fetch(tilesetURL)).then((response) => { loadAndZoomToTileset(tilesetURL); }).catch((error) => { //catching the error(no connection)/ timeout and displaying an alert for the user swal({ text: "Could not connect to Server. Using now: local data", icon: "info" }); console.log("Using local test data"); loadAndZoomToTileset(localTestTileset); }) } /* NOTE #1: -load the models but the are in the too high in the "air" -building view doesn´t work because all buildings are grouped together -surfaces are also broken -->this fixme is the problem of the backendteam ! ? maybe add old menu back and the option to also load the new ones */ //loads tileset after submit button is clicked function loadTileset() { viewer.scene.primitives.remove(tileset); tileContent = []; modal.style.display = "block"; fetchTileset(); } //loads the tileset from the url into the cesium viewer and zooms to it function loadAndZoomToTileset(url) { tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({ url: url })); viewer.zoomTo(tileset, new Cesium.HeadingPitchRange(0, -0.5, 0)); modal.style.display = "none"; saveTilesetContent(tileset) deleteTilesetButtons() } function useContent(content) { content.forEach(cont => { var element = document.createElement("input") element.type = "button" element.value = cont.title element.value = cont.title element.name = "individualTileset" document.getElementById("myList").appendChild(element); element.onclick = function() { tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({ url: cont.href })); viewer.zoomTo(tileset, new Cesium.HeadingPitchRange(0, -0.5, 0)); modal.style.display = "none"; saveTilesetContent(tileset) deleteTilesetButtons() }; }) } function saveTilesetContent(tileset) { tileset.tileLoad.addEventListener(tile => { const content = tile.content; for (let i = 0; i < content.featuresLength; i++) { let f = content.getFeature(i); tileContent.push(f) } }) } function deleteTilesetButtons() { var x = document.getElementsByName("individualTileset") var len = x.length //checking if there are even tileset to delete if (x.length > 0) { parentNode = x[0].parentNode; for (var i = 0; i < len; i++) { parentNode.removeChild(x[0]); } } } //expects path to test data, from the 'public' folder as origin // for example: getAbsoulteTestPath("/test/gmlTileset_v1.json") function getAbsoulteTestPath(testdataPath) { var a = window.location.pathname.split("/") a.pop(); a.reverse(); a.pop(); a.reverse() var path = ""; a.forEach(element => path += "/" + element); var path = window.location.origin + "/" + path + testdataPath; return path; }