diff --git a/public/js/connectToAPI.js b/public/js/connectToAPI.js index c3d879b7ff51ce7e8d109bc50557905badf035d6..96c395bba77105042d0825126708e3f201a758b8 100644 --- a/public/js/connectToAPI.js +++ b/public/js/connectToAPI.js @@ -1,5 +1,13 @@ var coordinatesBB = [] -var url = "https://simstadt-api.iaf-ex.hft-stuttgart.de:8080/workflow/execute" +//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" + +/*TODO#1: -get current data from the api and create local test data (apiData foler) + -add connection handeling (error messages when there isnt a connection and then using the local test data) +*/ +var localShadowData = "/3dclient4simstadtapi/public/test/APIdata/shadowData.json" var buildingFunctionSort var constructionYearSortPick @@ -8,6 +16,65 @@ var heatedVolumeSortPick var totalSurfaceAreaSortPick var roofTypeSortPick var uValueSortPick +var shadowdata + + +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] @@ -15,7 +82,7 @@ async function fetchDataJSON() { var rightLng = coordinatesBB[2] var topLat = coordinatesBB[3]// - const response = await fetch(url, { +const response = await fetch(url, { method: "POST", body: JSON.stringify({ "boundingBox": { @@ -25,7 +92,7 @@ async function fetchDataJSON() { "rightLng": rightLng, //9.175336684, "topLat": topLat //48.7822869656 }, - // "cityGMLRef": "campus", + "cityGMLRef": "campusLOD2", "interestedAttributes": [ "uValue", "volume", @@ -37,7 +104,7 @@ async function fetchDataJSON() { "monthlyCooling", "pvPotential", "roofType", - "totalSurfaceArea" + "totalSurfaceArea" ], "properies": { "physicsUseScenario": false @@ -51,181 +118,222 @@ async function fetchDataJSON() { const data = await response.json() return data } + document.getElementById("loader").style.visibility = "hidden" +async function getLocalShadowdata(){ + // gets the response from the api 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) + // shadowData=data; + return data; + } + function processData() { console.log(coordinatesBB) console.log("Waiting for data....") - fetchDataJSON().then(data => { - console.log(data); - document.getElementById("cesiumContainer").style.opacity = "1"; - document.getElementById("loader").style.visibility = "hidden" - console.log("....received data") + timeout(25000, fetchshadowDataJSON()).then((response)=>{ + console.log(response) + shadowdata = response ; + }).catch((error)=>{ //catching the error(no connection)/ timeout and displaying an alert for the user + // shadowdata= getLocalShadowdata(); + console.log(shadowdata); + //loadLocalAPIshadowData here... + }) + + timeout(10000, fetchPvPotentialJSON()).then((response)=>{ + console.log(response) + }).catch((error) => { + console.log(error) + }) + + + timeout(10000, fetchDataJSON()).then((response)=>{ + calculateData(response); + }).catch((error) => { + console.log(error) + /* + fetch("/3dclient4simstadtapi/public/test/APIdata/buildingInformation.json") + .then(response => response.text()) + .then(text => calculateData( JSON.parse(text))) + */ + }) - 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))) +function calculateData(data){ + console.log(data); + document.getElementById("cesiumContainer").style.opacity = "1"; + document.getElementById("loader").style.visibility = "hidden" + console.log("....received data") - buildingsMAP.set(bu.id, new Building(bu.id, partsArray)) //puts buildings with parts and surfaces in a map + var buildingsMAP = new Map() - }) + data.buildings.forEach(bu => { - 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) + 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) } - part.surfaces.forEach(s => { - if (s.uValue !== undefined) { - surfaceUValueMAP.set(s.id, s.uValue) - } - }) - //totalSurfaceArea - surfaceTotalSurfaceAreaMAP.set(part.id, part.surfaces) }) + //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) - }) + //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") - } - }) + partMonthlyHeatingMAP.forEach((value, key) => addmonthlyHeatingInfosToArrays(key, value)) + partMonthlyCoolingMAP.forEach((value, key) => addmonthlyCoolingInfosToArrays(key, value)) + partVolumeMAP.forEach((value, key) => addVolumeValues(key, value)) - //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") - } - }) + //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() - }).catch((err) => { - console.log(err) + //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") + } }) } @@ -282,31 +390,109 @@ window.onclick = function (event) { } } -var tileData = null -var tileset = null +//------------------------------------------------------------------------------- +var tileData = null; +var tileset = null; +//var tilesetURL = 'http://vm24.fkc.hft-stuttgart.de:8081/CampusLOD2Old/tileset.json'; +var tilesetURL = 'http://vm24.fkc.hft-stuttgart.de:8081/CampusLOD2/tileset.json'; +var tilesetURLb1 = 'http://vm24.fkc.hft-stuttgart.de:8081/Baue/bau1u3.json'; +var tilesetURLb2 = 'http://vm24.fkc.hft-stuttgart.de:8081/Baue/bau2.json'; +var tilesetURLb4 = 'http://vm24.fkc.hft-stuttgart.de:8081/Baue/bau4.json'; +var tilesetURLb5 = 'http://vm24.fkc.hft-stuttgart.de:8081/Baue/bau5.json'; +var tilesetURLb6 = 'http://vm24.fkc.hft-stuttgart.de:8081/Baue/bau6.json'; +var tilesetURLb7 = 'http://vm24.fkc.hft-stuttgart.de:8081/Baue/bau7.json'; +var tilesetURLb8 = 'http://vm24.fkc.hft-stuttgart.de:8081/Baue/bau8.json'; + +var localTestTileset = 'test/gmlTileset_v1.json'; +var localB1 = 'test/bau1u3.json'; +var localB2 = 'test/bau2.json'; +var localB4 = 'test/bau4.json'; +var localB5 = 'test/bau5.json'; +var localB6 = 'test/bau6.json'; +var localB7 = 'test/bau7.json'; +var localB8 = 'test/bau8.json'; + + +function timeout(ms, promise) { + return new Promise(function(resolve, reject) { + setTimeout(function() { + reject(new Error("timeout")) + }, ms) + promise.then(resolve, reject) + }) +} + +function pageLoad() { + if (window.location.hash === "#load-bau1") { + loadAndZoomToTileset(tilesetURLb1); + }if (window.location.hash === "#load-bau2") { + loadAndZoomToTileset(tilesetURLb2); + }if (window.location.hash === "#load-bau4") { + loadAndZoomToTileset(tilesetURLb4); + }if (window.location.hash === "#load-bau5") { + loadAndZoomToTileset(tilesetURLb5); + }if (window.location.hash === "#load-bau6") { + loadAndZoomToTileset(tilesetURLb6); + }if (window.location.hash === "#load-bau7") { + loadAndZoomToTileset(tilesetURLb7); + }if (window.location.hash === "#load-bau8") { + loadAndZoomToTileset(tilesetURLb8); + } +} + +//fetching the tileset and handling the connection +async 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 + //var errorString = error["stack"]+"\n"+error["message"]; // formatting the error array + swal({text:"Could not connect to Server. Using now: local data",icon:"info" } ); + console.log("Using local test data"); + loadAndZoomToTileset(localTestTileset); //TODO#3: fix the link so the local tileset can be loaded + }) +} + + + +/* + 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 ! -fetch('https://boxofcare.de/3DContainerTile/collections/') - .then(response => response.json()) - .then(data => { - tileData = data - }); + ? maybe add old menu back and the option to also load the new ones + +*/ -function loadTileset() { - viewer.scene.primitives.remove(tileset) - tileContent = [] + +//loads tileset after submit button is clicked +function loadTileset() { + viewer.scene.primitives.remove(tileset); + tileContent = []; modal.style.display = "block"; - console.log(tileData) + + fetchTileset(); + + //var userurl = document.getElementById("3Durl").value; //returns the chosen area from the dropdown +} +//loads the tileset from the url into the cesium viewer and zooms to it - var userurl = document.getElementById("3Durl").value; +function loadAndZoomToTileset(url){ + tileset=viewer.scene.primitives.add(new Cesium.Cesium3DTileset({ + + url: url + })); + - tileData.collections.forEach(c => { - if (userurl === 'hftcampus' && c.id === "HftCampus") useContent(c.content) - if (userurl === 'paderborn' && c.id === "Paderborn") useContent(c.content) - }) + viewer.zoomTo(tileset, new Cesium.HeadingPitchRange(0, -0.5, 0)); + modal.style.display = "none"; + saveTilesetContent(tileset) + deleteTilesetButtons() } -function useContent(content) { +function useContent(content) { content.forEach(cont => { var element = document.createElement("input") element.type = "button" @@ -341,9 +527,13 @@ function saveTilesetContent(tileset) { function deleteTilesetButtons() { var x = document.getElementsByName("individualTileset") var len = x.length - - parentNode = x[0].parentNode; - for (var i = 0; i < len; i++) { - parentNode.removeChild(x[0]); + + //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]); + } } + } diff --git a/public/main.html b/public/main.html index 5a536f08481d803a81044f1d19cf59b7c2741ee9..afbfcf2a916de2fa18c2dade55906a20ac119cb2 100644 --- a/public/main.html +++ b/public/main.html @@ -36,6 +36,7 @@ </style> <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/2.1.2/sweetalert.min.js" integrity="sha512-AA1Bzp5Q0K1KanKKmvN/4d3IRKVlv9PYgwFPvm32nPO6QS8yH1HO7LbgB1pgiOxPtfeg5zEn2ba64MUcqJx6CA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> + <!-- TODO: maybe add this to a external js file --> <script type="text/javascript"> var arrLang = { 'en': { @@ -124,7 +125,7 @@ </script> </head> -<body> +<body onload="pageLoad()"> <a href="https://www.hft-stuttgart.de/" target="_blank"> <div class="credit"></div> </a> @@ -211,7 +212,7 @@ </div> <div class="hilfe"> - <p> <a href="/pdf/Benutzerhandbuch.pdf" target="_blank"><button class="lang" id="Handbuch" key="userguide">User Guide</button></a></p> + <p> <a href="/3dclient4simstadtapi/public/pdf/Benutzerhandbuch.pdf" target="_blank"><button class="lang" id="Handbuch" key="userguide">User Guide</button></a></p> </div> <!--Sidebar--> @@ -241,9 +242,15 @@ <input id="building" type="radio" name="credit-card" value="building" checked> <div class="lang" key="buildingview">Building-View</div> <label class="drinkcard-cc building" for="building"></label> + <input id="surface" type="radio" name="credit-card" value="surface"> <div class="lang" key="surfaceview">Surface-View</div> <label class="drinkcard-cc surface" for="surface"></label> + + <input id="roof" type="radio" name="credit-card" value="roof"> + <div class="lang" key="roofview">Roof-View</div> + <label class="drinkcard-cc surface" for="roof"></label> + </div> </div> <!--Chartbutton--> @@ -336,6 +343,9 @@ <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"> </script> + + <script type="text/javascript" src="js/shadowPalette.js"></script> + <script type="text/javascript" src="js/sidebar.js"></script> <script type="text/javascript" src="js/globe.js"></script> <script type="text/javascript" src="js/areaCharts.js"></script>