class InitializationHandler { constructor() { } async generateMap() { return new Promise((res) => { require([ "esri/Map", "esri/views/SceneView", "esri/layers/GraphicsLayer", "esri/Graphic", "esri/geometry/Point", "esri/geometry/projection", "dojo", ], ( Map, SceneView, GraphicsLayer, Graphic, Point, Projection, ) => { // console.log(L); const map = new Map({ basemap: "dark-gray" }); const view = new SceneView({ container: "mapDiv", map, scale: 1000, camera: { position: { x: 8.896638, y: 53.054441, z: 400 } } }); const graphicLayer = new GraphicsLayer(); map.add(graphicLayer); res({ map, view, graphicLayer, Projection, Graphic, Point }); }); }) } } class FileManager { constructor() { this.resultXML; this.fileReader = new FileReader(); this.domParser = new DOMParser(); } loadFileContent(file) { return new Promise(res => { this.fileReader.readAsText(file); this.fileReader.onloadend = () => { this.resultXML = this.domParser.parseFromString(this.fileReader.result, "application/xml"); res(); } }) } getFileAsJson() { return this.xmlToJson(this.resultXML); } xmlToJson(xml) { // Create the return object var obj = {}; if (xml.nodeType == 1) { // element // do attributes if (xml.attributes.length > 0) { obj["@attributes"] = {}; for (var j = 0; j < xml.attributes.length; j++) { var attribute = xml.attributes.item(j); obj["@attributes"][attribute.nodeName] = attribute.nodeValue; } } } else if (xml.nodeType == 3) { // text obj = xml.nodeValue; } // do children if (xml.hasChildNodes()) { for (var i = 0; i < xml.childNodes.length; i++) { var item = xml.childNodes.item(i); var nodeName = item.nodeName; if (typeof (obj[nodeName]) == "undefined") { obj[nodeName] = this.xmlToJson(item); } else { if (typeof (obj[nodeName].push) == "undefined") { var old = obj[nodeName]; obj[nodeName] = []; obj[nodeName].push(old); } obj[nodeName].push(this.xmlToJson(item)); } } } return obj; }; cleanBuildingJson(dirtyJson, remove_duplicates = true, fix_esri_bug = true) { let building = {}; building.name = dirtyJson.BuildingVulnerability.BuildingName["#text"]; building.isExpanded = false; building.rooms = []; if (!Array.isArray(dirtyJson.BuildingVulnerability.Rooms.Room)){ dirtyJson.BuildingVulnerability.Rooms.Room = [dirtyJson.BuildingVulnerability.Rooms.Room] } dirtyJson.BuildingVulnerability.Rooms.Room.forEach(room => { let room_tmp = {}; room_tmp.name = room.RoomId["#text"]; room_tmp.isExpanded = false; room_tmp.walls = []; if (room.RoomOuterWalls.OuterWall && Array.isArray(room.RoomOuterWalls.OuterWall)) { let wallCounter = 0; room.RoomOuterWalls.OuterWall.forEach(wall => { let wall_tmp = {} wall_tmp.isSelected = false; wall_tmp.name = wallCounter; wall_tmp.points = []; if (wall.OuterWallAreaElement.PolygonPoint) { wall.OuterWallAreaElement.PolygonPoint.forEach(point => { wall_tmp.points.push({ "x": +point.X["#text"], "y": +point.Y["#text"], "z": +point.Z["#text"] }); }); } room_tmp.walls.push(wall_tmp); wallCounter++; }); } building.rooms.push(room_tmp); }); if (!remove_duplicates) return building building.rooms.forEach(room => { room.walls = room.walls.filter(wall => { let counter = 0; building.rooms.forEach(room_ => { room_.walls.forEach(wall_ => { if (JSON.stringify(wall.points) === JSON.stringify(wall_.points)) { counter++; } }); }); if (counter > 1) return false; return true; }) }); if (!fix_esri_bug) return building; building.rooms.forEach(room => { room.walls.map((wall) => { let lowest_point = wall.points[0].z; wall.points.forEach(point => { if (point.z < lowest_point) lowest_point = point.z; }); wall.points.forEach(point => { if (point.z > lowest_point) point.y += 0.0001; if (point.z > lowest_point) point.x += 0.0001; }); }) }); return building; } cleanEquipmentJson(dirtyJson) { let equipment = {}; equipment.referencePoints = []; //streif/header/group/group/[1]/switch/[0]/group/externalReferences console.log(dirtyJson.STREIF.Header.Group.Group); let groups = dirtyJson.STREIF.Header.Group.Group; groups.shift(); console.log(groups) groups.forEach(group => { console.log(group) if (!Array.isArray(group.Switch)) return; group.Switch.forEach(_switch => { if (!Array.isArray(_switch.Group.External_Reference)){ _switch.Group.External_Reference = [_switch.Group.External_Reference] } _switch.Group.External_Reference.forEach(external_reference => { equipment.referencePoints.push({ isExternal: false, name: external_reference.Name["#text"], coords: { x: +external_reference.Coord["@attributes"].X, y: +external_reference.Coord["@attributes"].Y, z: +external_reference.Coord["@attributes"].Z } }) console.log(external_reference.Name); }); }); }); const referencePoints = dirtyJson.STREIF.Header.Group.External_Reference; referencePoints.forEach(referencePoint => { equipment.referencePoints.push({ isExternal: true, name: referencePoint.Name["#text"], coords: { x: +referencePoint.Coord["@attributes"].X, y: +referencePoint.Coord["@attributes"].Y, z: +referencePoint.Coord["@attributes"].Z } }) }); return equipment; } } class DataProvider { constructor() { this.data = []; this.equipment = []; } addBuilding(building) { this.data.push(building); } getCurrentData() { return this.data; } addEquipment(equipment) { console.log(equipment); this.equipment.push(equipment); } getCurrentEquipment() { return this.equipment; } } class UIHandler { constructor(dataProvider) { this.dataProvider = dataProvider; this.rootElement = document.getElementById("myUL"); } makeBuildingRow(building) { let row = document.createElement('div'); row.classList.add("row"); row.onclick = () => { building.isExpanded = !building.isExpanded; this.render(); } let outerContainer = document.createElement('div'); outerContainer.classList.add('col-12'); outerContainer.classList.add('bg-light'); row.appendChild(outerContainer); let fluidContainer = document.createElement('div'); fluidContainer.classList.add('container-fluid'); outerContainer.appendChild(fluidContainer); let innerRow = document.createElement('div'); innerRow.classList.add('row'); innerRow.classList.add("row-hover"); fluidContainer.appendChild(innerRow); let segOne = document.createElement('div'); segOne.classList.add('col-1'); let segThree = document.createElement('div'); segThree.classList.add('col-11'); segThree.classList.add('p-2'); segThree.classList.add('treeStruct'); let segThreeInner_one = document.createElement('div'); if (building.isExpanded) segThreeInner_one.classList.add('buildingTreeRight'); let segThreeInner_two = document.createElement('div'); if (building.isExpanded) segThreeInner_two.classList.add('buildingTreeBottom'); segThree.innerText = 'Building ' + building.name; segThree.appendChild(segThreeInner_one); segThree.appendChild(segThreeInner_two); innerRow.appendChild(segOne); innerRow.appendChild(segThree); return row; } makeRoomRow(room) { let row = document.createElement('div'); row.classList.add("row"); row.onclick = () => { room.isExpanded = !room.isExpanded; this.render(); } let outerContainer = document.createElement('div'); outerContainer.classList.add('col-12'); outerContainer.classList.add('bg-light'); row.appendChild(outerContainer); let fluidContainer = document.createElement('div'); fluidContainer.classList.add('container-fluid'); outerContainer.appendChild(fluidContainer); let innerRow = document.createElement('div'); innerRow.classList.add('row'); innerRow.classList.add("row-hover"); fluidContainer.appendChild(innerRow); let segOne = document.createElement('div'); segOne.classList.add('col-1'); let segTwo = document.createElement('div'); segTwo.classList.add('col-1'); segTwo.classList.add('border-dark'); segTwo.classList.add('border-end'); let segThree = document.createElement('div'); segThree.classList.add('col-10'); segThree.classList.add('p-2'); segThree.classList.add('treeStruct'); let segThreeInner_one = document.createElement('div'); segThreeInner_one.classList.add('roomTreeRight'); let segThreeInner_two = document.createElement('div'); if (room.isExpanded) segThreeInner_two.classList.add('roomTreeBottom'); segThree.innerText = 'Room ' + room.name; segThree.appendChild(segThreeInner_one); segThree.appendChild(segThreeInner_two); innerRow.appendChild(segOne); innerRow.appendChild(segTwo); innerRow.appendChild(segThree); return row; } makeWallRow(wall) { let row = document.createElement('div'); row.classList.add("row"); let outerContainer = document.createElement('div'); outerContainer.classList.add('col-12'); outerContainer.classList.add('bg-light'); row.appendChild(outerContainer); let fluidContainer = document.createElement('div'); fluidContainer.classList.add('container-fluid'); if (wall.isSelected) fluidContainer.classList.add("selectedWall"); outerContainer.appendChild(fluidContainer); let innerRow = document.createElement('div'); innerRow.classList.add('row'); innerRow.classList.add("row-hover"); fluidContainer.appendChild(innerRow); let segOne = document.createElement('div'); segOne.classList.add('col-1'); let segTwo = document.createElement('div'); segTwo.classList.add('col-2'); segTwo.classList.add('border-dark'); segTwo.classList.add('border-end'); let segThree = document.createElement('div'); segThree.classList.add('col-9'); segThree.classList.add('p-2'); segThree.classList.add('treeStruct'); let segThreeInner = document.createElement('div'); segThreeInner.classList.add('wallTreeRight'); segThree.innerText = 'Wall ' + wall.name; segThree.appendChild(segThreeInner); innerRow.appendChild(segOne); innerRow.appendChild(segTwo); innerRow.appendChild(segThree); return row; } render() { while (this.rootElement.firstChild) { this.rootElement.removeChild(this.rootElement.firstChild); } let buildingArray = this.dataProvider.getCurrentData(); buildingArray.forEach(building => { this.createBuilding(building); }); } createBuilding(buildingConfig) { let buildingListEntry = document.createElement("li"); let buildingListEntrySpan = document.createElement("SPAN"); buildingListEntrySpan.classList.add("caret"); buildingListEntrySpan.appendChild(this.makeBuildingRow(buildingConfig)); buildingListEntry.appendChild(buildingListEntrySpan); buildingListEntry.appendChild(this.createRoomList(buildingConfig.rooms, buildingConfig.isExpanded)); document.getElementById('myUL').appendChild(buildingListEntry); } createRoomList(roomArray, isExpanded) { let roomList = document.createElement("ul"); roomList.classList.add("nested"); if (isExpanded) roomList.classList.add("active"); roomArray.forEach(room => { let roomListEntry = document.createElement("li"); let roomListEntrySpan = document.createElement("SPAN"); roomListEntrySpan.classList.add("caret"); roomListEntrySpan.appendChild(this.makeRoomRow(room)); roomListEntry.appendChild(roomListEntrySpan); roomListEntry.appendChild(this.createWallList(room.walls, room.isExpanded)); roomList.appendChild(roomListEntry); }); return roomList; } createWallList(wallArray, isExpanded) { let wallList = document.createElement("ul"); wallList.classList.add("nested"); if (isExpanded) wallList.classList.add("active"); wallArray.forEach(wall => { let wallListEntry = document.createElement("li"); let wallListEntrySpan = document.createElement("SPAN"); wallListEntrySpan.appendChild(this.makeWallRow(wall)); wallListEntry.appendChild(wallListEntrySpan); wallList.appendChild(wallListEntry); }); return wallList; } } class DrawingHandler { constructor(dataProvider, uiHandler, graphicLayer, Point, Projection, Graphic, view, map) { this.dataProvider = dataProvider; this.uiHandler = uiHandler; this.graphicLayer = graphicLayer; this.Point = Point; this.Projection = Projection; this.Graphic = Graphic; this.view = view; this.map = map this.fillActive = true; this.view.on("click", (e) => { if (e.button === 0) { this.view.hitTest(e).then((res) => { if (res.results[0].graphic.geometry.type == "polygon") res.results[0].graphic.clickCallback() }); } }) const [r, g, b] = [Math.floor(Math.random() * 50) + 100, Math.floor(Math.random() * 50) + 150, 255]; this.r = r; this.g = g; this.b = b; this.fillSymbol = { type: "simple-fill", // autocasts as new SimpleFillSymbol() color: [this.r, this.g, this.b, 0.8], outline: { // autocasts as new SimpleLineSymbol() color: [255, 255, 255], width: 2 } }; this.nonFillSymbol = { type: "simple-fill", // autocasts as new SimpleFillSymbol() color: [this.r, this.g, this.b, 0.8], style: "none", outline: { // autocasts as new SimpleLineSymbol() color: [255, 255, 255], width: 2 } }; } draw() { this.Projection.load().then(() => { let buildings = this.dataProvider.getCurrentData(); buildings.forEach(building => { building.rooms.forEach(room => { room.walls.forEach(wall => { const wallGeometry = { type: "polygon", rings: [], } const markerSymbol = { type: "simple-marker", // autocasts as new SimpleMarkerSymbol() color: [this.r, this.g, this.b], size: "5px" }; wall.points.forEach(point => { let p = { type: "point", // autocasts as new Point() x: 493063.5202829816 + point.x, y: 5878330.672506552 + point.y, z: 0 + point.z, spatialReference: { wkid: 32632 } } let p_transformed = this.Projection.project(p, this.view.spatialReference); wallGeometry.rings.push([p_transformed.longitude, p_transformed.latitude, p_transformed.z]); const pointGraphic = new this.Graphic({ geometry: p_transformed, symbol: markerSymbol }); this.graphicLayer.add(pointGraphic); }); wallGeometry.rings.push(wallGeometry.rings[0]); wallGeometry.rings = wallGeometry.rings.reverse(); let wallCoordTableContent = ``; wall.points.forEach(vertex => { wallCoordTableContent += ` ${parseFloat(vertex.x).toFixed(3)} ${parseFloat(vertex.y).toFixed(3)} ${parseFloat(vertex.z).toFixed(3)} ` }); const wallCoordTable = ` ${wallCoordTableContent}
X Y Z
` let logVertices = { title: "Log Vertices", id: `log${room.name}${wall.name}`, }; const wallAttributes = { name: `Room ${room.name} - Wall ${wall.name}`, ringSize: wallGeometry.rings.length, vertices: wallCoordTable } const wallPopupTemplate = { title: "{name}", content: [ { type: "fields", fieldInfos: [ { fieldName: "ringSize" }, { fieldName: "vertices" }, ] } ], actions: [logVertices] } this.view.popup.on("trigger-action", (event) => { if (event.action.id === `log${room.name}${wall.name}`) { let array = []; wall.points.forEach(point => { array.push([point.x, point.y, point.z * 100]); }); console.log(JSON.stringify(array)); debugger; } }); const polygonGraphic = new this.Graphic({ geometry: wallGeometry, symbol: this.fillActive ? this.fillSymbol : this.nonFillSymbol, attributes: wallAttributes, popupTemplate: wallPopupTemplate }); polygonGraphic.clickCallback = () => { buildings.forEach(building_ => { building_.isExpanded = false; building_.rooms.forEach(room_ => { room_.isExpanded = false; room_.walls.forEach(wall_ => { wall_.isSelected = false; }); }); }); building.isExpanded = true; room.isExpanded = true; wall.isSelected = true; this.uiHandler.render(); } this.graphicLayer.add(polygonGraphic); }); }); }); const externalMarkerSymbol = { type: "simple-marker", // autocasts as new SimpleMarkerSymbol() color: [255, 0, 0], size: "15px" }; const internalMarkerSymbol = { type: "simple-marker", // autocasts as new SimpleMarkerSymbol() color: [0, 255, 0], size: "15px" }; let equipments = this.dataProvider.getCurrentEquipment(); equipments.forEach(equipment => { equipment.referencePoints.forEach(referencePoint => { let p = { type: "point", // autocasts as new Point() x: 493063.5202829816 + referencePoint.coords.x, y: 5878330.672506552 + referencePoint.coords.y, z: 0 + referencePoint.coords.z, spatialReference: { wkid: 32632 } } let p_transformed = this.Projection.project(p, this.view.spatialReference); const referencePointAttribute = { name: referencePoint.name, coords: `
X Y Z
${parseFloat(referencePoint.coords.x).toFixed(3)} ${parseFloat(referencePoint.coords.y).toFixed(3)} ${parseFloat(referencePoint.coords.z).toFixed(3)}
` } const referencePointAttributeTemplate = { title: "{name}", content: [ { type: "fields", fieldInfos: [ { fieldName: "coords" } ] } ], } const pointGraphic = new this.Graphic({ geometry: p_transformed, symbol: referencePoint.isExternal ? externalMarkerSymbol : internalMarkerSymbol, attributes: referencePointAttribute, popupTemplate: referencePointAttributeTemplate }); this.graphicLayer.add(pointGraphic); }); }); }) } toggleFill() { let useFill = !this.fillActive; this.fillActive = !this.fillActive; let symbol = useFill ? this.fillSymbol : this.nonFillSymbol; this.graphicLayer.graphics.forEach(graphic => { if (graphic.geometry.type == "polygon") graphic.set('symbol', symbol); }); } } //This is the main (() => { const fileManager = new FileManager(); const dataProvider = new DataProvider(); const uiHandler = new UIHandler(dataProvider); let drawingHandler; const initializationHandler = new InitializationHandler(); initializationHandler.generateMap().then((esriLoad) => { esriObjects = esriLoad; drawingHandler = new DrawingHandler(dataProvider, uiHandler, esriObjects.graphicLayer, esriObjects.Point, esriObjects.Projection, esriObjects.Graphic, esriObjects.view, esriObjects.map ); }); document.getElementById("flexSwitchCheckDefault").addEventListener("click", () => { drawingHandler.toggleFill(); }) const buildingFile = document.getElementById('exampleFormControlFile1'); buildingFile.onchange = async () => { const file = buildingFile.files[0]; await fileManager.loadFileContent(file); dataProvider.addBuilding(fileManager.cleanBuildingJson(fileManager.getFileAsJson())); uiHandler.render(); drawingHandler.draw(); document.getElementById('modal-close-button').click(); } const equipmentFile = document.getElementById('exampleFormControlFile2'); equipmentFile.onchange = async () => { const file = equipmentFile.files[0]; await fileManager.loadFileContent(file); console.log(fileManager.getFileAsJson()); dataProvider.addEquipment(fileManager.cleanEquipmentJson(fileManager.getFileAsJson())); drawingHandler.draw(); document.getElementById('modal-close-button').click(); } })();