From c131364791cf1538d08a1ca3df0edf0fa04109be Mon Sep 17 00:00:00 2001
From: Lauri Himanen <lauri.himanen@gmail.com>
Date: Wed, 7 Apr 2021 11:02:06 +0300
Subject: [PATCH] Fixed the info system values, fixed issue with loading
 spinner staying visible after reroute.

---
 client/bundle.js                              |  8 +++---
 client/infosys.json                           | 27 ++++++++++++-------
 client/src/common/Router.js                   |  2 ++
 client/src/material-mod/Overview.view.js      | 14 +++++-----
 .../src/material-mod/StructureDetails.view.js | 12 ++++-----
 client/src/search-mod/FilterPanel.view.js     | 18 +++----------
 6 files changed, 40 insertions(+), 41 deletions(-)

diff --git a/client/bundle.js b/client/bundle.js
index a104e6be..359db79d 100644
--- a/client/bundle.js
+++ b/client/bundle.js
@@ -82,7 +82,7 @@ eval("\n/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apac
 /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
 
 "use strict";
-eval("\n/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n\n /*\n   This file implements the app Routing system: the feature that allows\n   the page navigation in a single-page environment.\n */\n\n\n\n\nlet LoadingPopup = __webpack_require__(/*! ../common/LoadingPopup.js */ \"./src/common/LoadingPopup.js\");\n\nlet routes = new Map();\n\n\nfunction add(route, func){\n  routes.set(route, func);\n}\n\n\nwindow.addEventListener(\"hashchange\", route);\n\nvar hashHistory = [window.location.hash];\nvar historyLength = window.history.length;\nfunction route() {\n\n  var hash = window.location.hash, length = window.history.length;\n  if (hashHistory.length && historyLength == length) {\n    if (hashHistory[hashHistory.length - 2] == hash) {\n      hashHistory = hashHistory.slice(0, -1);\n    } else {\n      hashHistory.push(hash);\n    }\n  } else {\n    hashHistory.push(hash);\n    historyLength = length;\n  }\n\n  let hashPath = document.location.hash.substring(2);\n  let command, param, subparam;\n\n  // Remove the ending /\n  if (hashPath.lastIndexOf('/') === (hashPath.length-1))\n    hashPath = hashPath.substring(0,hashPath.length-1);\n\n  // Remove state parameters from authentication\n  let stateIndex = hashPath.indexOf('&state');\n  if (stateIndex != -1) {\n    hashPath = hashPath.substring(0, stateIndex);\n  }\n\n  if (hashPath.indexOf('/') > 0){\n    let a= hashPath.split('/');\n    command= a[0];\n    param= a[1];\n    subparam= a[2];\n  }\n  else command = hashPath;\n\n  if (routes.has(command)) {\n    routes.get(command)(param, subparam);\n  }\n};\n\n\nfunction print(){\n  console.log('Router data: ');\n  routes.forEach(function(func, url) {\n    console.log(url + ': ' + func);\n  });\n}\n\n\n// EXPORTS\nmodule.exports = { add: add, route: route };\n\n\n//# sourceURL=webpack:///./src/common/Router.js?");
+eval("\n/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n\n /*\n   This file implements the app Routing system: the feature that allows\n   the page navigation in a single-page environment.\n */\n\n\n\n\nlet LoadingPopup = __webpack_require__(/*! ../common/LoadingPopup.js */ \"./src/common/LoadingPopup.js\");\n\nlet routes = new Map();\n\n\nfunction add(route, func){\n  routes.set(route, func);\n}\n\n\nwindow.addEventListener(\"hashchange\", route);\n\nvar hashHistory = [window.location.hash];\nvar historyLength = window.history.length;\nfunction route() {\n\n  var hash = window.location.hash, length = window.history.length;\n  if (hashHistory.length && historyLength == length) {\n    if (hashHistory[hashHistory.length - 2] == hash) {\n      hashHistory = hashHistory.slice(0, -1);\n    } else {\n      hashHistory.push(hash);\n    }\n  } else {\n    hashHistory.push(hash);\n    historyLength = length;\n  }\n\n  let hashPath = document.location.hash.substring(2);\n  let command, param, subparam;\n\n  // Remove the ending /\n  if (hashPath.lastIndexOf('/') === (hashPath.length-1))\n    hashPath = hashPath.substring(0,hashPath.length-1);\n\n  // Remove state parameters from authentication\n  let stateIndex = hashPath.indexOf('&state');\n  if (stateIndex != -1) {\n    hashPath = hashPath.substring(0, stateIndex);\n  }\n\n  if (hashPath.indexOf('/') > 0){\n    let a= hashPath.split('/');\n    command= a[0];\n    param= a[1];\n    subparam= a[2];\n  }\n  else command = hashPath;\n\n  if (routes.has(command)) {\n    // When entering a new page, reset the spinner.\n    LoadingPopup.reset();\n    routes.get(command)(param, subparam);\n  }\n};\n\n\nfunction print(){\n  console.log('Router data: ');\n  routes.forEach(function(func, url) {\n    console.log(url + ': ' + func);\n  });\n}\n\n\n// EXPORTS\nmodule.exports = { add: add, route: route };\n\n\n//# sourceURL=webpack:///./src/common/Router.js?");
 
 /***/ }),
 
@@ -297,7 +297,7 @@ eval("\n/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apac
 /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
 
 "use strict";
-eval("\n/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n\n /*\n  This file implements the Overview view component in the  Material Module.\n */\n\n\n\n\nlet util = __webpack_require__(/*! ../common/util.js */ \"./src/common/util.js\");\nlet InfoSys = __webpack_require__(/*! ../common/InfoSys.js */ \"./src/common/InfoSys.js\");\nlet LoadingPopup = __webpack_require__(/*! ../common/LoadingPopup.js */ \"./src/common/LoadingPopup.js\");\n\nlet BSPlotter = __webpack_require__(/*! ./BSPlotter.js */ \"./src/material-mod/BSPlotter.js\");\nlet DOSPlotter = __webpack_require__(/*! ./DOSPlotter.js */ \"./src/material-mod/DOSPlotter.js\");\nlet HeatCapPlotter = __webpack_require__(/*! ./HeatCapPlotter.js */ \"./src/material-mod/HeatCapPlotter.js\");\nlet MaterialMod = __webpack_require__(/*! ./MaterialMod.js */ \"./src/material-mod/MaterialMod.js\");\nlet DataStore = __webpack_require__(/*! ./DataStore.js */ \"./src/material-mod/DataStore.js\");\nlet SimilarityFinder = __webpack_require__(/*! ./Similarity.js */ \"./src/material-mod/Similarity.js\").SimilarityFinder;\n\nconst ELEMENT_INCLUDED_MSG = 'ELEMENT ALREADY INCLUDED';\n\n\nclass Overview {\n\n  constructor() {\n\n    this.element = document.createElement('div');\n    this.element.setAttribute('id','overview');\n    this.materialId;\n    let bsLoaded = false;\n    let phononLoaded = false;\n    let dosLoaded = false;\n    this.calcMaterialId = null;\n    this.element.innerHTML=`\n\n    <div class=\"material-title\">\n    </div>\n\n    <div style=\"float: left; width: 40%;\">\n\n      <div id=\"structure-ov\" class=\"view-box\">\n        <div class=\"title\">Structure\n          <img style=\"float: right\" class=\"to-detail\" src=\"img/more.svg\" />\n          <div style=\"clear: both;\"></div>\n        </div>\n\n        <div class=\"viz-box-container\" style=\"height: 260px; position: relative\">\n          <div class=\"viz-box\" style=\"height: 90%\"></div>\n        </div>\n\n        <div class=\"footer\">\n          <div ><b><span>Material type</span></b>:\n            <span class=\"material-type-field\" ></span>\n          </div>\n          <div class=\"space-group-field\" style=\"display: none\">\n            <b><span info-sys-data=\"space-group\">Space group</span></b>:\n            <span class=\"space-group-value\" ></span>\n          </div>\n          <div class=\"structure-type-field\" style=\"display: none\">\n            <b><span info-sys-data=\"structure-type\">Structure type</span></b>:\n            <span class=\"structure-type-value\" ></span>\n          </div>\n        </div>\n      </div>\n\n\n<!-- ***** Elastic Constants Box\n\n      <div id=\"elastic-ov\" class=\"view-box\">\n        <div class=\"title\">Elastic constants\n          <img style=\"float: right\" class=\"to-detail\" src=\"img/more.svg\" />\n          <div style=\"clear: both;\"></div>\n        </div>\n\n        <div class=\"info-fields\">\n          Not analyzed yet\n        </div>\n\n      </div>\n-->\n\n\n      <div id=\"methodology-ov\" class=\"view-box\">\n        <div class=\"title\">Methodology\n          <img style=\"float: right\" class=\"to-detail\" src=\"img/more.svg\" />\n          <div style=\"clear: both;\"></div>\n        </div>\n\n        <div class=\"info-fields\">\n\n          <div class=\"info-fields-label\" > Available calculations </div>\n\n          <div style=\"float: left; width: 45%\" >\n            <b><span info-sys-data=\"functional-type\">Functional</span></b>\n            <div class=\"functional-field\" > </div>\n          </div>\n          <div style=\"float: right; width: 45%\" >\n            <b><span info-sys-data=\"code-name\">Code</span></b>\n            <div class=\"code-field\"> </div>\n           </div>\n           <div style=\"clear: both;\"></div>\n        </div>\n\n      </div>\n\n    </div>\n\n    <div style=\"float: right; width: 60%;\">\n\n      <div id=\"e-structure-ov\" class=\"view-box\" style=\"display: block\">\n        <div class=\"title\">Electronic structure\n          <img style=\"float: right\" class=\"to-detail\" src=\"img/more.svg\" />\n          <div style=\"clear: both;\"></div>\n        </div>\n\n        <div > <!-- style=\"margin: 12% 0; \" -->\n\n        <div style=\"float: left; width: 60%;  \">\n        <div style=\"padding: 20px 0 20px 30px\">\n          <div  class=\"info-fields-label\">\n            <span info-sys-data=\"band-structure\">Band structure</span>\n          </div>\n          <div>\n              <div id=\"band-plotter\" >  </div>\n          </div>\n\n          <div class=\"footer-bs-calc\"></div>\n        </div>\n        </div>\n\n        <div style=\"float: left; width: 40%;  \">\n          <div style=\"padding: 20px 30px 20px 40px\">\n            <div class=\"info-fields-label\">\n              <span info-sys-data=\"DOS\">DOS</span>\n            </div>\n\n            <div>\n                <div id=\"dos-plotter\" >  </div>\n            </div>\n            <div class=\"footer-dos-calc\"></div>\n          </div>\n        </div>\n\n\n\n        <div style=\"clear: both;\"></div>\n        <table style=\"width: 100%\">\n        <tr>\n          <td class=\"spin-legend\" style=\"font-size: 0.9em; padding: 6px 30px 10px; display: none;\">\n            <svg width=\"15px\" height=\"10px\"> <polyline points=\"0,5 15,5\" class=\"plotSpin1\"/></svg>\n              Spin <span style='font-size: 1.1em'>⇧</span>  &nbsp;&nbsp;&nbsp;\n\n              <svg width=\"15px\" height=\"10px\"> <polyline points=\"0,5 15,5\" class=\"plotSpin2\"/></svg>\n              Spin <span style='font-size: 1.1em'>⇩</span>\n          </td>\n          <td class = \"similarity-data-field\">\n          <div style=\"float: right; padding: 0px 50px 10px 0px; margin-top: 1px;\" class=\"similarity-finder\">\n          </div>\n          </td>\n          </tr>\n          </table>\n        </div>\n        <div style=\"clear: both;\"></div>\n        <!--\n        <div class=\"footer\">\n\n          <b>Band gap</b>: <span class=\"e-struct-field\" ></span>\n        </div>\n        -->\n      </div>\n\n      <div id=\"thermal-props-ov\" class=\"view-box\" style=\"visibility: hidden\">\n        <div class=\"title\">Vibrational and thermal properties\n          <img style=\"float: right\" class=\"to-detail thermal-props\" src=\"img/more.svg\" />\n          <div style=\"clear: both;\"></div>\n        </div>\n\n        <div style=\"padding: 36px; \">\n          <div class=\"info-fields-label\">\n            <span info-sys-data=\"heat-capacity-cv\">Specific heat</span>\n          </div>\n\n\n          <div>\n              <div id=\"heat-plotter\" >  </div>\n          </div>\n          <div class=\"footer-heat-calc\" style=\"text-align: center\"></div>\n        </div>\n\n      </div>\n\n    </div>\n\n    <div style=\"clear: both;\"></div>\n    `;\n\n    this.materialTitle= this.element.getElementsByClassName('material-title')[0];\n\n    this.systemType= this.element.querySelector('.material-type-field');\n    this.spaceGroupField = this.element.querySelector('.space-group-field');\n    this.spaceGroupValue = this.element.querySelector('.space-group-value');\n    this.structTypeField= this.element.querySelector('.structure-type-field');\n    this.structTypeValue= this.element.querySelector('.structure-type-value');\n    //this.band_gap = this.element.getElementsByClassName('e-struct-field')[0];\n    //fields= this.element.getElementsByClassName('method-field');\n    this.functional= this.element.querySelector('.functional-field');//fields[0];\n    this.code= this.element.querySelector('.code-field');//fields[1];\n\n    let fields= this.element.getElementsByClassName('to-detail');\n    this.structureDetailBtn= fields[0];\n    this.electronicStructDetailBtn= fields[2];\n    this.methodologyDetailBtn= fields[1];\n    this.thermalDetailBtn= fields[3];\n/*\n    this.elasticDetailBtn= fields[1];\n    this.methodologyDetailBtn= fields[2];\n    this.electronicStructDetailBtn= fields[3];\n    this.thermalDetailBtn= fields[4];\n    */\n\n    this.vizBox = this.element.getElementsByClassName('viz-box')[0];\n    this.bandPlotter= null;\n    this.bsCalcIdBox = this.element.getElementsByClassName('footer-bs-calc')[0];\n    this.dosPlotter= null;\n    this.dosCalcIdBox = this.element.getElementsByClassName('footer-dos-calc')[0];\n    this.heatPlotter= null;\n    this.heatCalcIdBox = this.element.querySelector('.footer-heat-calc');\n\n    this.spinLegend = this.element.querySelector('.spin-legend');\n\n    // For static ones\n    InfoSys.addToInfoSystem(this.element);\n\n    // Store the state of the calcs chosen on the Elec. Structure box\n    this.eStructCalcs = { bs: null, dos: null};\n  }\n\n\n  attachAndSetEvents(element){\n    element.appendChild(this.element);\n    this._events();\n  }\n\n\n  _events() {\n\n    this.structureDetailBtn.addEventListener( \"click\", (e) => {\n      util.setBrowserHashPath('material', this.materialId+'/'+util.MAT_VIEW.structure);\n    });\n\n    this.electronicStructDetailBtn.addEventListener( \"click\", (e) => {\n      util.setBrowserHashPath('material', this.materialId+'/'+util.MAT_VIEW.electronicstruct);\n    });\n\n    this.methodologyDetailBtn.addEventListener( \"click\", (e) => {\n      util.setBrowserHashPath('material', this.materialId+'/'+util.MAT_VIEW.methodology);\n    });\n\n    this.thermalDetailBtn.addEventListener( \"click\", (e) => {\n      util.setBrowserHashPath('material', this.materialId+'/'+util.MAT_VIEW.thermalprops);\n    });\n\n/*\n    this.elasticDetailBtn.addEventListener( \"click\", (e) => {\n      util.setBrowserHashPath('material', this.materialId+'/'+util.MAT_VIEW.elasticconst);\n    });\n*/\n\n\n    //******* Optimize, genralize:\n    //this.element.querySelectorAll('.to-detail+.'+detailsId).addEventListener( \"click\", (e) => {\n    // util.setBrowserHashPath('material', this.materialId+'/'+detailsId);\n  }\n\n\n  getEStructChosenCalcs(){\n    return this.eStructCalcs;\n  }\n\n\n  setDetailViewsListener(listener){\n    this.detailViewsListener= listener;\n  }\n\n  setVisible() {\n    this.element.style.display = 'block';\n  }\n\n\n  setMaterialData() {\n\n    let data = DataStore.getMaterialData();\n    this.materialTitle.innerHTML= util.getMaterialTitle(data);\n    this.materialId = data.material_id;\n\n    let isBulk = (data.material_type === 'bulk');\n    this.systemType.textContent= data.material_type;\n    this.structTypeField.style.display =\n      (isBulk && data.structure_type !== null ? 'block' : 'none');\n    this.spaceGroupField.style.display = (isBulk ? 'block' : 'none');\n\n    if (isBulk){\n      this.structTypeValue.textContent= data.structure_type;\n      this.spaceGroupValue.textContent = data.space_group_number+\n        ' ('+data.space_group_international_short_symbol+')';\n      InfoSys.addElementToInfoSystem(this.spaceGroupValue,\n        'space-group.value:'+data.space_group_number);\n    }\n\n    if (this.similarityFinder) {\n      this.similarityFinder.element.remove();\n    }\n\n    if (data.similarity) {\n      this.similarityFinder = new SimilarityFinder({left: 40, right: 16, top: 0, bottom: 30});\n\n      const similarityFinderContainer = this.element.querySelector('.similarity-finder');\n      this.similarityFinder.setSimilarityData(data.similarity);\n      similarityFinderContainer.appendChild(this.similarityFinder.element);\n      this.similartyDataField = this.element.querySelector('.similarity-data-field');\n      InfoSys.addToInfoSystem(this.similartyDataField);\n    }\n  }\n\n  isLoaded(hasBs, hasDOS, hasPhonon) {\n    let materialData = DataStore.getMaterialData();\n    let material_id = materialData.material_id;\n    if (this.calcMaterialId === material_id) {\n      if (hasBs && !this.bsLoaded) {\n        return false;\n      }\n      if (hasDOS && !this.dosLoaded) {\n        return false;\n      }\n      if (hasPhonon && !this.phononLoaded) {\n        return false;\n      }\n      return true;\n    }\n    return false;\n  }\n\n  clearCalcsData() {\n    this.materialId = null;\n    this.calcMaterialId = null;\n    let bsLoaded = false;\n    let phononLoaded = false;\n    let dosLoaded = false;\n  }\n\n  setCalcsData(markedTreeLeafs) {\n    let matData = DataStore.getMaterialData();\n    let calcs = DataStore.getCalculations();\n    let functionalMap = new Map();\n    let codeMap = new Map();\n\n    // Get the representative calculations from the material data returned\n    let calcWithBS = DataStore.getCalc(DataStore.getRepresentatives().electronic_band_structure);\n    let calcWithDOS = DataStore.getCalc(DataStore.getRepresentatives().electronic_dos);\n    let calcWithHeat = DataStore.getCalc(DataStore.getRepresentatives().thermodynamical_properties);\n\n    if (this.isLoaded(calcWithBS !== undefined, calcWithDOS !== undefined, calcWithHeat !== undefined)) {\n      return;\n    }\n    this.calcMaterialId = matData.material_id;\n    this.bsLoaded = false;\n    this.dosLoaded = false;\n    this.phononLoaded = false;\n\n    // Gather how many calculations there are for each functional and code\n    for (let i = 0; i < calcs.length; i++) {\n      if (functionalMap.has(calcs[i].functional_type)) {\n        let num = functionalMap.get(calcs[i].functional_type);\n        functionalMap.set(calcs[i].functional_type, ++num);\n      } else {\n        functionalMap.set(calcs[i].functional_type, 1);\n      }\n\n      let codeNameTrimed= calcs[i].code_name.trim();\n      if (codeMap.has(codeNameTrimed)) {\n        let num= codeMap.get(codeNameTrimed);\n        codeMap.set(codeNameTrimed, ++num);\n      } else {\n        codeMap.set(codeNameTrimed, 1);\n      }\n    }\n\n    if (calcWithBS !== undefined)  this.eStructCalcs.bs = calcWithBS.calc_id;\n    if (calcWithDOS !== undefined)  this.eStructCalcs.dos = calcWithDOS.calc_id;\n\n    let tempCalcId = null;\n    if (calcWithBS !== undefined)  tempCalcId = calcWithBS.calc_id;\n    else if (calcWithDOS !== undefined)  tempCalcId = calcWithDOS.calc_id;\n\n    if (tempCalcId === null) {\n      markedTreeLeafs.eStruct = null; // no graph data\n    } else\n      markedTreeLeafs.eStruct = +tempCalcId;\n\n    if (calcWithHeat === undefined) {\n      markedTreeLeafs.thermalProps = null;\n    } else {\n      markedTreeLeafs.thermalProps = +calcWithHeat.calc_id;\n    }\n\n    // Add list of functionals\n    this.functional.textContent = \"\";\n    let container = document.createElement(\"div\");\n    functionalMap.forEach((number, functional) => {\n      let span = document.createElement(\"span\");\n      span.setAttribute(\"info-sys-data\", \"functional-type.value:\" + util.getDefault(functional));\n      span.textContent = number + ' ' + util.getDefault(functional);\n      container.appendChild(span);\n      let linebreak = document.createElement(\"br\");\n      container.appendChild(linebreak);\n    });\n    this.functional.append(container);\n    InfoSys.addToInfoSystem(this.functional);\n\n    // Add list of codes\n    this.code.textContent = \"\";\n    let container2 = document.createElement(\"div\");\n    codeMap.forEach((number, codeName) => {\n      let span = document.createElement(\"span\");\n      span.setAttribute(\"info-sys-data\", \"code-name.value:\" + codeName);\n      span.textContent = number + ' ' + codeName;\n      container2.appendChild(span);\n      let linebreak = document.createElement(\"br\");\n      container2.appendChild(linebreak);\n    });\n    this.code.append(container2);\n    InfoSys.addToInfoSystem(this.code);\n\n    if (DataStore.hasElecStructureData()) {\n      document.getElementById('e-structure-ov').style.display = 'block';\n      let isReady = () => {\n        if (this.dosLoaded && this.bsLoaded) {\n          document.getElementById('e-structure-ov').style.visibility = 'visible';\n        }\n      };\n\n      if (this.bandPlotter === null){\n        this.bandPlotter= new BSPlotter();\n        this.bandPlotter.attach(document.getElementById('band-plotter'),undefined,316);\n      }\n      if (this.dosPlotter === null){\n        this.dosPlotter= new DOSPlotter({left: 40, right: 20, top: 0, bottom: 30});\n        this.dosPlotter.attach(document.getElementById('dos-plotter'),undefined,317);\n      }\n\n      if (calcWithBS === undefined){\n        this.bandPlotter.setNoData();\n        this.bsCalcIdBox.innerHTML = '';\n        this.bsLoaded = true;\n      } else {\n        let url = util.getMaterialCalcURL(this.materialId, calcWithBS.calc_id);\n        LoadingPopup.show(\"overview_electronic_band_structure\");\n        let query = JSON.stringify({properties: [\"electronic_band_structure\"]});\n        util.serverReqPOST(url, query, e => {\n          if (e.target.status === 200){\n            let bandStructData = JSON.parse(e.target.response).electronic_band_structure;\n            this.bandPlotter.setBandStructureData(bandStructData);\n            this.bsCalcIdBox.innerHTML = 'From calculation <b>' + util.getShortCode(calcWithBS.calc_id)+\n              '</b><br><span style=\"font-size: 0.8em\">('+calcWithBS.functional_type+' - '+calcWithBS.code_name+')</span>';\n            if (bandStructData.section_k_band_segment[0].band_energies.length === 2)\n              this.spinLegend.style.display = 'block';\n          } else {\n            this.bandPlotter.setNoData();\n          }\n          this.bsLoaded = true;\n          isReady();\n          LoadingPopup.hide(\"overview_electronic_band_structure\");\n        });\n      }\n\n      if (calcWithDOS === undefined){\n        this.dosPlotter.setNoData();\n        this.dosCalcIdBox.innerHTML = '';\n        this.dosLoaded = true;\n      } else {\n        let url = util.getMaterialCalcURL(this.materialId, calcWithDOS.calc_id);\n        LoadingPopup.show(\"overview_electronic_dos\");\n        let query = JSON.stringify({properties: [\"electronic_dos\"]});\n        util.serverReqPOST(url, query, e => {\n          if (e.target.status === 200){\n            let dosData= JSON.parse(e.target.response).electronic_dos;\n            this.dosPlotter.setPoints(dosData, calcWithDOS);\n            this.dosCalcIdBox.innerHTML = 'From calculation <b>'+util.getShortCode(calcWithDOS.calc_id)+\n            '</b><br><span style=\"font-size: 0.8em\">('+calcWithDOS.functional_type+' - '+calcWithDOS.code_name+')</span>';\n            if (dosData.dos_values.length === 2)\n              this.spinLegend.style.display = 'block';\n          } else {\n            this.dosPlotter.setNoData();\n          }\n          this.dosLoaded = true;\n          isReady();\n          LoadingPopup.hide(\"overview_electronic_dos\");\n        });\n      }\n    }\n\n    if (!DataStore.hasThermalData()) {\n      document.getElementById('thermal-props-ov').style.display = 'none';\n    } else {\n      document.getElementById('thermal-props-ov').style.display = 'block';\n\n      if (this.heatPlotter === null){\n        this.heatPlotter= new HeatCapPlotter();\n        this.heatPlotter.attach(document.getElementById('heat-plotter'),undefined,317);\n      }\n\n      if (calcWithHeat === undefined){\n        this.heatPlotter.setNoData();\n        this.heatCalcIdBox.innerHTML = '';\n      } else {\n        let url = util.getMaterialCalcURL(this.materialId, calcWithHeat.calc_id);\n        LoadingPopup.show(\"overview_thermodynamical\");\n        let query = JSON.stringify({properties: [\"thermodynamical_properties\"]});\n        util.serverReqPOST(url, query, e => {\n          if (e.target.status === 200) {\n            let response = JSON.parse(e.target.response);\n            let thermoProp = response.thermodynamical_properties;\n            let t = thermoProp.thermodynamical_property_temperature;\n            this.heatPlotter.setData(t, thermoProp.specific_heat_capacity);\n            this.heatCalcIdBox.innerHTML = 'From calculation <b>'+util.getShortCode(calcWithHeat.calc_id)+'</b>'+\n            '</b> <span style=\"font-size: 0.8em\">('+calcWithHeat.functional_type+' - '+calcWithHeat.code_name+')</span>';\n            this.phononLoaded = true;\n            document.getElementById('thermal-props-ov').style.visibility = 'visible';\n          }\n          LoadingPopup.hide(\"overview_thermodynamical\");\n        });\n      }\n    }\n  }\n}\n\n// EXPORTS\nmodule.exports = Overview;\n\n\n//# sourceURL=webpack:///./src/material-mod/Overview.view.js?");
+eval("\n/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n\n /*\n  This file implements the Overview view component in the  Material Module.\n */\n\n\n\n\nlet util = __webpack_require__(/*! ../common/util.js */ \"./src/common/util.js\");\nlet InfoSys = __webpack_require__(/*! ../common/InfoSys.js */ \"./src/common/InfoSys.js\");\nlet LoadingPopup = __webpack_require__(/*! ../common/LoadingPopup.js */ \"./src/common/LoadingPopup.js\");\n\nlet BSPlotter = __webpack_require__(/*! ./BSPlotter.js */ \"./src/material-mod/BSPlotter.js\");\nlet DOSPlotter = __webpack_require__(/*! ./DOSPlotter.js */ \"./src/material-mod/DOSPlotter.js\");\nlet HeatCapPlotter = __webpack_require__(/*! ./HeatCapPlotter.js */ \"./src/material-mod/HeatCapPlotter.js\");\nlet MaterialMod = __webpack_require__(/*! ./MaterialMod.js */ \"./src/material-mod/MaterialMod.js\");\nlet DataStore = __webpack_require__(/*! ./DataStore.js */ \"./src/material-mod/DataStore.js\");\nlet SimilarityFinder = __webpack_require__(/*! ./Similarity.js */ \"./src/material-mod/Similarity.js\").SimilarityFinder;\n\nconst ELEMENT_INCLUDED_MSG = 'ELEMENT ALREADY INCLUDED';\n\n\nclass Overview {\n\n  constructor() {\n\n    this.element = document.createElement('div');\n    this.element.setAttribute('id','overview');\n    this.materialId;\n    let bsLoaded = false;\n    let phononLoaded = false;\n    let dosLoaded = false;\n    this.calcMaterialId = null;\n    this.element.innerHTML=`\n\n    <div class=\"material-title\">\n    </div>\n\n    <div style=\"float: left; width: 40%;\">\n\n      <div id=\"structure-ov\" class=\"view-box\">\n        <div class=\"title\">Structure\n          <img style=\"float: right\" class=\"to-detail\" src=\"img/more.svg\" />\n          <div style=\"clear: both;\"></div>\n        </div>\n\n        <div class=\"viz-box-container\" style=\"height: 260px; position: relative\">\n          <div class=\"viz-box\" style=\"height: 90%\"></div>\n        </div>\n\n        <div class=\"footer\">\n          <div ><b><span>Material type</span></b>:\n            <span class=\"material-type-field\" ></span>\n          </div>\n          <div class=\"space-group-field\" style=\"display: none\">\n            <b><span info-sys-data=\"space_group_number\">Space group</span></b>:\n            <span class=\"space-group-value\" ></span>\n          </div>\n          <div class=\"structure-type-field\" style=\"display: none\">\n            <b><span info-sys-data=\"structure_type\">Structure type</span></b>:\n            <span class=\"structure-type-value\" ></span>\n          </div>\n        </div>\n      </div>\n\n\n<!-- ***** Elastic Constants Box\n\n      <div id=\"elastic-ov\" class=\"view-box\">\n        <div class=\"title\">Elastic constants\n          <img style=\"float: right\" class=\"to-detail\" src=\"img/more.svg\" />\n          <div style=\"clear: both;\"></div>\n        </div>\n\n        <div class=\"info-fields\">\n          Not analyzed yet\n        </div>\n\n      </div>\n-->\n\n\n      <div id=\"methodology-ov\" class=\"view-box\">\n        <div class=\"title\">Methodology\n          <img style=\"float: right\" class=\"to-detail\" src=\"img/more.svg\" />\n          <div style=\"clear: both;\"></div>\n        </div>\n\n        <div class=\"info-fields\">\n\n          <div class=\"info-fields-label\" > Available calculations </div>\n\n          <div style=\"float: left; width: 45%\" >\n            <b><span info-sys-data=\"functional_type\">Functional</span></b>\n            <div class=\"functional-field\" > </div>\n          </div>\n          <div style=\"float: right; width: 45%\" >\n            <b><span info-sys-data=\"code_name\">Code</span></b>\n            <div class=\"code-field\"> </div>\n           </div>\n           <div style=\"clear: both;\"></div>\n        </div>\n\n      </div>\n\n    </div>\n\n    <div style=\"float: right; width: 60%;\">\n\n      <div id=\"e-structure-ov\" class=\"view-box\" style=\"display: block\">\n        <div class=\"title\">Electronic structure\n          <img style=\"float: right\" class=\"to-detail\" src=\"img/more.svg\" />\n          <div style=\"clear: both;\"></div>\n        </div>\n\n        <div > <!-- style=\"margin: 12% 0; \" -->\n\n        <div style=\"float: left; width: 60%;  \">\n        <div style=\"padding: 20px 0 20px 30px\">\n          <div  class=\"info-fields-label\">\n            <span info-sys-data=\"band-structure\">Band structure</span>\n          </div>\n          <div>\n              <div id=\"band-plotter\" >  </div>\n          </div>\n\n          <div class=\"footer-bs-calc\"></div>\n        </div>\n        </div>\n\n        <div style=\"float: left; width: 40%;  \">\n          <div style=\"padding: 20px 30px 20px 40px\">\n            <div class=\"info-fields-label\">\n              <span info-sys-data=\"DOS\">DOS</span>\n            </div>\n\n            <div>\n                <div id=\"dos-plotter\" >  </div>\n            </div>\n            <div class=\"footer-dos-calc\"></div>\n          </div>\n        </div>\n\n\n\n        <div style=\"clear: both;\"></div>\n        <table style=\"width: 100%\">\n        <tr>\n          <td class=\"spin-legend\" style=\"font-size: 0.9em; padding: 6px 30px 10px; display: none;\">\n            <svg width=\"15px\" height=\"10px\"> <polyline points=\"0,5 15,5\" class=\"plotSpin1\"/></svg>\n              Spin <span style='font-size: 1.1em'>⇧</span>  &nbsp;&nbsp;&nbsp;\n\n              <svg width=\"15px\" height=\"10px\"> <polyline points=\"0,5 15,5\" class=\"plotSpin2\"/></svg>\n              Spin <span style='font-size: 1.1em'>⇩</span>\n          </td>\n          <td class = \"similarity-data-field\">\n          <div style=\"float: right; padding: 0px 50px 10px 0px; margin-top: 1px;\" class=\"similarity-finder\">\n          </div>\n          </td>\n          </tr>\n          </table>\n        </div>\n        <div style=\"clear: both;\"></div>\n        <!--\n        <div class=\"footer\">\n\n          <b>Band gap</b>: <span class=\"e-struct-field\" ></span>\n        </div>\n        -->\n      </div>\n\n      <div id=\"thermal-props-ov\" class=\"view-box\" style=\"visibility: hidden\">\n        <div class=\"title\">Vibrational and thermal properties\n          <img style=\"float: right\" class=\"to-detail thermal-props\" src=\"img/more.svg\" />\n          <div style=\"clear: both;\"></div>\n        </div>\n\n        <div style=\"padding: 36px; \">\n          <div class=\"info-fields-label\">\n            <span info-sys-data=\"heat-capacity-cv\">Specific heat</span>\n          </div>\n\n\n          <div>\n              <div id=\"heat-plotter\" >  </div>\n          </div>\n          <div class=\"footer-heat-calc\" style=\"text-align: center\"></div>\n        </div>\n\n      </div>\n\n    </div>\n\n    <div style=\"clear: both;\"></div>\n    `;\n\n    this.materialTitle= this.element.getElementsByClassName('material-title')[0];\n\n    this.systemType= this.element.querySelector('.material-type-field');\n    this.spaceGroupField = this.element.querySelector('.space-group-field');\n    this.spaceGroupValue = this.element.querySelector('.space-group-value');\n    this.structTypeField= this.element.querySelector('.structure-type-field');\n    this.structTypeValue= this.element.querySelector('.structure-type-value');\n    //this.band_gap = this.element.getElementsByClassName('e-struct-field')[0];\n    //fields= this.element.getElementsByClassName('method-field');\n    this.functional= this.element.querySelector('.functional-field');//fields[0];\n    this.code= this.element.querySelector('.code-field');//fields[1];\n\n    let fields= this.element.getElementsByClassName('to-detail');\n    this.structureDetailBtn= fields[0];\n    this.electronicStructDetailBtn= fields[2];\n    this.methodologyDetailBtn= fields[1];\n    this.thermalDetailBtn= fields[3];\n/*\n    this.elasticDetailBtn= fields[1];\n    this.methodologyDetailBtn= fields[2];\n    this.electronicStructDetailBtn= fields[3];\n    this.thermalDetailBtn= fields[4];\n    */\n\n    this.vizBox = this.element.getElementsByClassName('viz-box')[0];\n    this.bandPlotter= null;\n    this.bsCalcIdBox = this.element.getElementsByClassName('footer-bs-calc')[0];\n    this.dosPlotter= null;\n    this.dosCalcIdBox = this.element.getElementsByClassName('footer-dos-calc')[0];\n    this.heatPlotter= null;\n    this.heatCalcIdBox = this.element.querySelector('.footer-heat-calc');\n\n    this.spinLegend = this.element.querySelector('.spin-legend');\n\n    // For static ones\n    InfoSys.addToInfoSystem(this.element);\n\n    // Store the state of the calcs chosen on the Elec. Structure box\n    this.eStructCalcs = { bs: null, dos: null};\n  }\n\n\n  attachAndSetEvents(element){\n    element.appendChild(this.element);\n    this._events();\n  }\n\n\n  _events() {\n\n    this.structureDetailBtn.addEventListener( \"click\", (e) => {\n      util.setBrowserHashPath('material', this.materialId+'/'+util.MAT_VIEW.structure);\n    });\n\n    this.electronicStructDetailBtn.addEventListener( \"click\", (e) => {\n      util.setBrowserHashPath('material', this.materialId+'/'+util.MAT_VIEW.electronicstruct);\n    });\n\n    this.methodologyDetailBtn.addEventListener( \"click\", (e) => {\n      util.setBrowserHashPath('material', this.materialId+'/'+util.MAT_VIEW.methodology);\n    });\n\n    this.thermalDetailBtn.addEventListener( \"click\", (e) => {\n      util.setBrowserHashPath('material', this.materialId+'/'+util.MAT_VIEW.thermalprops);\n    });\n\n/*\n    this.elasticDetailBtn.addEventListener( \"click\", (e) => {\n      util.setBrowserHashPath('material', this.materialId+'/'+util.MAT_VIEW.elasticconst);\n    });\n*/\n\n\n    //******* Optimize, genralize:\n    //this.element.querySelectorAll('.to-detail+.'+detailsId).addEventListener( \"click\", (e) => {\n    // util.setBrowserHashPath('material', this.materialId+'/'+detailsId);\n  }\n\n\n  getEStructChosenCalcs(){\n    return this.eStructCalcs;\n  }\n\n\n  setDetailViewsListener(listener){\n    this.detailViewsListener= listener;\n  }\n\n  setVisible() {\n    this.element.style.display = 'block';\n  }\n\n\n  setMaterialData() {\n\n    let data = DataStore.getMaterialData();\n    this.materialTitle.innerHTML= util.getMaterialTitle(data);\n    this.materialId = data.material_id;\n\n    let isBulk = (data.material_type === 'bulk');\n    this.systemType.textContent= data.material_type;\n    this.structTypeField.style.display =\n      (isBulk && data.structure_type !== null ? 'block' : 'none');\n    this.spaceGroupField.style.display = (isBulk ? 'block' : 'none');\n\n    if (isBulk){\n      this.structTypeValue.textContent= data.structure_type;\n      this.spaceGroupValue.textContent = data.space_group_number+\n        ' ('+data.space_group_international_short_symbol+')';\n      InfoSys.addElementToInfoSystem(this.spaceGroupValue,\n        'space_group_number.value:' + data.space_group_number);\n    }\n\n    if (this.similarityFinder) {\n      this.similarityFinder.element.remove();\n    }\n\n    if (data.similarity) {\n      this.similarityFinder = new SimilarityFinder({left: 40, right: 16, top: 0, bottom: 30});\n\n      const similarityFinderContainer = this.element.querySelector('.similarity-finder');\n      this.similarityFinder.setSimilarityData(data.similarity);\n      similarityFinderContainer.appendChild(this.similarityFinder.element);\n      this.similartyDataField = this.element.querySelector('.similarity-data-field');\n      InfoSys.addToInfoSystem(this.similartyDataField);\n    }\n  }\n\n  isLoaded(hasBs, hasDOS, hasPhonon) {\n    let materialData = DataStore.getMaterialData();\n    let material_id = materialData.material_id;\n    if (this.calcMaterialId === material_id) {\n      if (hasBs && !this.bsLoaded) {\n        return false;\n      }\n      if (hasDOS && !this.dosLoaded) {\n        return false;\n      }\n      if (hasPhonon && !this.phononLoaded) {\n        return false;\n      }\n      return true;\n    }\n    return false;\n  }\n\n  clearCalcsData() {\n    this.materialId = null;\n    this.calcMaterialId = null;\n    let bsLoaded = false;\n    let phononLoaded = false;\n    let dosLoaded = false;\n  }\n\n  setCalcsData(markedTreeLeafs) {\n    let matData = DataStore.getMaterialData();\n    let calcs = DataStore.getCalculations();\n    let functionalMap = new Map();\n    let codeMap = new Map();\n\n    // Get the representative calculations from the material data returned\n    let calcWithBS = DataStore.getCalc(DataStore.getRepresentatives().electronic_band_structure);\n    let calcWithDOS = DataStore.getCalc(DataStore.getRepresentatives().electronic_dos);\n    let calcWithHeat = DataStore.getCalc(DataStore.getRepresentatives().thermodynamical_properties);\n\n    if (this.isLoaded(calcWithBS !== undefined, calcWithDOS !== undefined, calcWithHeat !== undefined)) {\n      return;\n    }\n    this.calcMaterialId = matData.material_id;\n    this.bsLoaded = false;\n    this.dosLoaded = false;\n    this.phononLoaded = false;\n\n    // Gather how many calculations there are for each functional and code\n    for (let i = 0; i < calcs.length; i++) {\n      if (functionalMap.has(calcs[i].functional_type)) {\n        let num = functionalMap.get(calcs[i].functional_type);\n        functionalMap.set(calcs[i].functional_type, ++num);\n      } else {\n        functionalMap.set(calcs[i].functional_type, 1);\n      }\n\n      let codeNameTrimed= calcs[i].code_name.trim();\n      if (codeMap.has(codeNameTrimed)) {\n        let num= codeMap.get(codeNameTrimed);\n        codeMap.set(codeNameTrimed, ++num);\n      } else {\n        codeMap.set(codeNameTrimed, 1);\n      }\n    }\n\n    if (calcWithBS !== undefined)  this.eStructCalcs.bs = calcWithBS.calc_id;\n    if (calcWithDOS !== undefined)  this.eStructCalcs.dos = calcWithDOS.calc_id;\n\n    let tempCalcId = null;\n    if (calcWithBS !== undefined)  tempCalcId = calcWithBS.calc_id;\n    else if (calcWithDOS !== undefined)  tempCalcId = calcWithDOS.calc_id;\n\n    if (tempCalcId === null) {\n      markedTreeLeafs.eStruct = null; // no graph data\n    } else\n      markedTreeLeafs.eStruct = +tempCalcId;\n\n    if (calcWithHeat === undefined) {\n      markedTreeLeafs.thermalProps = null;\n    } else {\n      markedTreeLeafs.thermalProps = +calcWithHeat.calc_id;\n    }\n\n    // Add list of functionals\n    this.functional.textContent = \"\";\n    let container = document.createElement(\"div\");\n    functionalMap.forEach((number, functional) => {\n      let span = document.createElement(\"span\");\n      span.setAttribute(\"info-sys-data\", \"functional_type.value:\" + util.getDefault(functional));\n      span.textContent = number + ' ' + util.getDefault(functional);\n      container.appendChild(span);\n      let linebreak = document.createElement(\"br\");\n      container.appendChild(linebreak);\n    });\n    this.functional.append(container);\n    InfoSys.addToInfoSystem(this.functional);\n\n    // Add list of codes\n    this.code.textContent = \"\";\n    let container2 = document.createElement(\"div\");\n    codeMap.forEach((number, codeName) => {\n      let span = document.createElement(\"span\");\n      span.setAttribute(\"info-sys-data\", \"code_name.value:\" + codeName);\n      span.textContent = number + ' ' + codeName;\n      container2.appendChild(span);\n      let linebreak = document.createElement(\"br\");\n      container2.appendChild(linebreak);\n    });\n    this.code.append(container2);\n    InfoSys.addToInfoSystem(this.code);\n\n    if (DataStore.hasElecStructureData()) {\n      document.getElementById('e-structure-ov').style.display = 'block';\n      let isReady = () => {\n        if (this.dosLoaded && this.bsLoaded) {\n          document.getElementById('e-structure-ov').style.visibility = 'visible';\n        }\n      };\n\n      if (this.bandPlotter === null){\n        this.bandPlotter= new BSPlotter();\n        this.bandPlotter.attach(document.getElementById('band-plotter'),undefined,316);\n      }\n      if (this.dosPlotter === null){\n        this.dosPlotter= new DOSPlotter({left: 40, right: 20, top: 0, bottom: 30});\n        this.dosPlotter.attach(document.getElementById('dos-plotter'),undefined,317);\n      }\n\n      if (calcWithBS === undefined){\n        this.bandPlotter.setNoData();\n        this.bsCalcIdBox.innerHTML = '';\n        this.bsLoaded = true;\n      } else {\n        let url = util.getMaterialCalcURL(this.materialId, calcWithBS.calc_id);\n        LoadingPopup.show(\"overview_electronic_band_structure\");\n        let query = JSON.stringify({properties: [\"electronic_band_structure\"]});\n        util.serverReqPOST(url, query, e => {\n          if (e.target.status === 200){\n            let bandStructData = JSON.parse(e.target.response).electronic_band_structure;\n            this.bandPlotter.setBandStructureData(bandStructData);\n            this.bsCalcIdBox.innerHTML = 'From calculation <b>' + util.getShortCode(calcWithBS.calc_id)+\n              '</b><br><span style=\"font-size: 0.8em\">('+calcWithBS.functional_type+' - '+calcWithBS.code_name+')</span>';\n            if (bandStructData.section_k_band_segment[0].band_energies.length === 2)\n              this.spinLegend.style.display = 'block';\n          } else {\n            this.bandPlotter.setNoData();\n          }\n          this.bsLoaded = true;\n          isReady();\n          LoadingPopup.hide(\"overview_electronic_band_structure\");\n        });\n      }\n\n      if (calcWithDOS === undefined){\n        this.dosPlotter.setNoData();\n        this.dosCalcIdBox.innerHTML = '';\n        this.dosLoaded = true;\n      } else {\n        let url = util.getMaterialCalcURL(this.materialId, calcWithDOS.calc_id);\n        LoadingPopup.show(\"overview_electronic_dos\");\n        let query = JSON.stringify({properties: [\"electronic_dos\"]});\n        util.serverReqPOST(url, query, e => {\n          if (e.target.status === 200){\n            let dosData= JSON.parse(e.target.response).electronic_dos;\n            this.dosPlotter.setPoints(dosData, calcWithDOS);\n            this.dosCalcIdBox.innerHTML = 'From calculation <b>'+util.getShortCode(calcWithDOS.calc_id)+\n            '</b><br><span style=\"font-size: 0.8em\">('+calcWithDOS.functional_type+' - '+calcWithDOS.code_name+')</span>';\n            if (dosData.dos_values.length === 2)\n              this.spinLegend.style.display = 'block';\n          } else {\n            this.dosPlotter.setNoData();\n          }\n          this.dosLoaded = true;\n          isReady();\n          LoadingPopup.hide(\"overview_electronic_dos\");\n        });\n      }\n    }\n\n    if (!DataStore.hasThermalData()) {\n      document.getElementById('thermal-props-ov').style.display = 'none';\n    } else {\n      document.getElementById('thermal-props-ov').style.display = 'block';\n\n      if (this.heatPlotter === null){\n        this.heatPlotter= new HeatCapPlotter();\n        this.heatPlotter.attach(document.getElementById('heat-plotter'),undefined,317);\n      }\n\n      if (calcWithHeat === undefined){\n        this.heatPlotter.setNoData();\n        this.heatCalcIdBox.innerHTML = '';\n      } else {\n        let url = util.getMaterialCalcURL(this.materialId, calcWithHeat.calc_id);\n        LoadingPopup.show(\"overview_thermodynamical\");\n        let query = JSON.stringify({properties: [\"thermodynamical_properties\"]});\n        util.serverReqPOST(url, query, e => {\n          if (e.target.status === 200) {\n            let response = JSON.parse(e.target.response);\n            let thermoProp = response.thermodynamical_properties;\n            let t = thermoProp.thermodynamical_property_temperature;\n            this.heatPlotter.setData(t, thermoProp.specific_heat_capacity);\n            this.heatCalcIdBox.innerHTML = 'From calculation <b>'+util.getShortCode(calcWithHeat.calc_id)+'</b>'+\n            '</b> <span style=\"font-size: 0.8em\">('+calcWithHeat.functional_type+' - '+calcWithHeat.code_name+')</span>';\n            this.phononLoaded = true;\n            document.getElementById('thermal-props-ov').style.visibility = 'visible';\n          }\n          LoadingPopup.hide(\"overview_thermodynamical\");\n        });\n      }\n    }\n  }\n}\n\n// EXPORTS\nmodule.exports = Overview;\n\n\n//# sourceURL=webpack:///./src/material-mod/Overview.view.js?");
 
 /***/ }),
 
@@ -349,7 +349,7 @@ eval("\n/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apac
 /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
 
 "use strict";
-eval("\n/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n /*\n  'Details' view container that shows all the material info related to\n  its structure.\n\n  This container is extremely complex.\n\n  In the file there are two defined (classes) components used in the container:\n  - TreeLeafViewer: The panel on the right showing the data of the tree leaf marked\n  - SummaryByFunctionalsComponent: the component (central panel, below part)\n  showing a summary for the selected item on the tree (by functional)\n */\n\n\n\nlet DetailsViewBase = __webpack_require__(/*! ./DetailsViewBase.js */ \"./src/material-mod/DetailsViewBase.js\");\nlet util = __webpack_require__(/*! ../common/util.js */ \"./src/common/util.js\");\nlet InfoSys = __webpack_require__(/*! ../common/InfoSys.js */ \"./src/common/InfoSys.js\");\nlet NavTree = __webpack_require__(/*! ./NavTree.js */ \"./src/material-mod/NavTree.js\");\nlet CalcSelectorBar = __webpack_require__(/*! ./CalcSelectorBar.js */ \"./src/material-mod/CalcSelectorBar.js\");\nlet StatsViewer = __webpack_require__(/*! ./StatsViewer.js */ \"./src/material-mod/StatsViewer.js\");\nlet EquationOfStateViewer = __webpack_require__(/*! ./EquationOfStateViewer.js */ \"./src/material-mod/EquationOfStateViewer.js\");\nlet DataStore = __webpack_require__(/*! ./DataStore.js */ \"./src/material-mod/DataStore.js\");\n\n\nclass StructureDetails extends DetailsViewBase {\n\n  constructor() {\n    super('Structure');\n    this.navTree = new NavTree();\n    this.groupsData;\n    this.element.innerHTML+=`\n\n      <div style=\"float: left; width: 36%;\">\n        <div class=\"view-box\">\n          <div class=\"title\">Structure </div>\n          <div class=\"viz-box-container\" style=\"height: 400px; position: relative\">\n            <div class=\"viz-box\" style=\"height: 90%\"></div>\n          </div>\n\n          <div class=\"footer-flex-wrapper\">\n\n            <div class=\"fields-container\">\n              <div><b><span>System type</span></b>:\n                <span class=\"struct-field\" ></span>\n              </div>\n              <div class=\"structure-type-field\" style=\"display: none\">\n                <b><span info-sys-data=\"structure-type\">Structure type</span></b>:\n                <span class=\"structure-type-value\" ></span>\n              </div>\n              <div class=\"structure-prototype-field\" style=\"display: none\">\n                <b><span info-sys-data=\"structure-prototype\">Structure prototype</span></b>:\n                <span class=\"structure-prototype-value\" ></span>\n              </div>\n              <div class=\"strukturbericht-field\" style=\"display: none\">\n                <b><span info-sys-data=\"strukturbericht\">Strukturbericht designation</span></b>:\n                <span class=\"strukturbericht-value\" ></span>\n              </div>\n            </div>\n\n            <div class=\"footer-flex\" style=\"display: none\">\n\n              <div class=\"fields-container\"\n                style=\"flex-basis: 70%; border-right: 1px solid #E4E4E4; \">\n\n                <div>\n                  <b><span info-sys-data=\"crystal-system\">Lattice</span></b>:\n                  <span class=\"lattice-value\" ></span>\n                </div>\n                <div>\n                  <b><span info-sys-data=\"space-group\">Space group</span></b>:\n                  <span class=\"space-group-value\" ></span>\n                </div>\n                <div>\n                  <b><span info-sys-data=\"point-group\">Point group</span></b>:\n                  <span class=\"point-group-value\" ></span>\n                </div>\n              </div>\n\n              <div style=\"flex-basis: 30%; margin-left: 30px;\">\n                <div class=\"fields-container\">\n                  <div><b><span info-sys-data=\"wyckoff-position-population\">Wyckoff sites</span></b></div>\n                  <div class=\"wyckoff-sites-value\"> </div>\n                </div>\n              </div>\n\n            </div>\n\n          </div>\n\n        </div>\n      </div>\n\n      <div style=\"float: left; width: 36%;\">\n        <div class=\"view-box\">\n          <div class=\"title\">Calculations</div>\n          <div class=\"navTreeWrapper\"></div>\n\n          <div class=\"summary-title\">Summary  </div>\n          <div style=\"font-size: 0.85em; text-align: center; padding: 4px;\">Based on the calculations selected above</div>\n\n          <div class=\"info-fields summary-box\">\n          <!-- Lattice constants Cell volume, Density panel dynamically generated\n            -->\n          </div>\n        </div>\n      </div>\n\n      <div style=\"float: right; width: 28%;\">\n        <div class=\"calc-specifics-box\">\n          <div style=\"padding-top: 10px; \" >\n            <div class=\"tree-leaf-title\"></div>\n          </div>\n          <div class=\"tree-leaf-viewer-host\"></div>\n          </div>\n        </div>\n      </div>\n    </div>\n    `;\n\n    this.navTreeWrapper =\n        this.element.getElementsByClassName(\"navTreeWrapper\")[0];\n\n    let fields= this.element.getElementsByClassName('struct-field');\n    this.systemTypeField= fields[0];\n    this.structTypeField= this.element.querySelector('.structure-type-field');\n    this.structTypeValue= this.element.querySelector('.structure-type-value');\n    this.structPrototypeField= this.element.querySelector('.structure-prototype-field');\n    this.structPrototypeValue= this.element.querySelector('.structure-prototype-value');\n    this.strukturberichtField= this.element.querySelector('.strukturbericht-field');\n    this.strukturberichtValue= this.element.querySelector('.strukturbericht-value');\n\n    this.lowerBox = this.element.querySelector('.footer-flex');\n    this.latticeValue= this.element.querySelector('.lattice-value');\n    this.spaceGroupValue= this.element.querySelector('.space-group-value');\n    this.pointGroupValue= this.element.querySelector('.point-group-value');\n    this.wyckoffValue= this.element.querySelector('.wyckoff-sites-value');\n\n    this.summaryByFunctionals = null;\n\n    this.leafTitle = this.element.querySelector('.tree-leaf-title');\n\n    this.summaryBox = this.element.querySelector('.summary-box');\n    this.summaryByFunctionals = new SummaryByFunctionalsComponent(this.summaryBox);\n\n    this.calcSpecificsBox = this.element.querySelector('.calc-specifics-box');\n\n    this.treeLeafViewer = new TreeLeafViewer();\n    this.element.querySelector('.tree-leaf-viewer-host').\n      appendChild(this.treeLeafViewer.element);\n\n    this.vizBox = this.element.querySelector('.viz-box');\n\n    // For static ones\n    InfoSys.addToInfoSystem(this.element);\n  }\n\n  setMaterialData() {\n    let data = DataStore.getMaterialData();\n    let idealizedStructure = DataStore.getIdealizedStructure();\n    super.setMaterialData(data);\n\n    // Build the navigation tree and attach listeners\n    let name = (data.material_name === null ?\n      data.formula : data.material_name);\n    this.navTree.build(name, \"structure\");\n    this.navTree.selectAll();\n    this.navTree.setHeight(250);\n    this.navTree.setMarkedLeafIfNoneMarked(null); // Set the first leaf marked\n    this.attachNavTree(this.navTree);\n    this.updateSelection(this.navTree.getTreeSelectedCalcs());\n    this.updateMarkedLeaf(this.navTree.getMarkedLeaf());\n    this.navTree.setTreeSelectionListener( leafIds => {\n      this.updateSelection(leafIds);\n    });\n    this.navTree.setLeafMarkedListener( leafId => {\n      this.updateMarkedLeaf(leafId);\n    });\n\n    this.isBulk = (data.material_type === 'bulk');\n\n    this.systemTypeField.textContent= data.material_type;\n    this.structTypeField.style.display =\n      (this.isBulk && data.structure_type !== null ? 'block' : 'none');\n    this.structPrototypeField.style.display =\n      (this.isBulk && data.structure_prototype !== null ? 'block' : 'none');\n    this.strukturberichtField.style.display =\n      (this.isBulk && data.strukturbericht_designation !== null ? 'block' : 'none');\n\n    this.lowerBox.style.display = (this.isBulk ? 'flex' : 'none');\n\n    if (this.isBulk){\n      this.structTypeValue.textContent= data.structure_type;\n      this.structPrototypeValue.textContent= data.structure_prototype;\n      this.strukturberichtValue.textContent= data.strukturbericht_designation;\n      this.spaceGroupValue.textContent = data.space_group_number\n        +' ('+data.space_group_international_short_symbol+')';\n      this.pointGroupValue.textContent = data.point_group;\n      this.latticeValue.textContent = data.crystal_system;\n\n      // Wyckoff processing\n      let wyckoffMap = new Map();\n      let valueSet= new Set();\n\n      for (var i = 0; i < idealizedStructure.wyckoff_sets.length; i++) {\n        let wset = idealizedStructure.wyckoff_sets[i];\n        let element = wset.element;\n        if (wyckoffMap.has(element)){\n          wyckoffMap.get(element).add(wset.wyckoff_letter);\n        } else {\n          let newSet = new Set();\n          newSet.add(wset.wyckoff_letter);\n          wyckoffMap.set(element, newSet);\n        }\n      }\n\n      let wyckoffHTML= '';\n      wyckoffMap.forEach((posSet, element) => {\n        let firstPos = true;\n        wyckoffHTML += '<tr> <td>'+element+': </td>';\n        posSet.forEach( pos => {\n          if (firstPos){\n            firstPos = false;\n            wyckoffHTML += '<td>'+pos+'</td></tr>';\n          }else\n            wyckoffHTML += '<tr><td> </td><td>'+pos+'</td></tr>';\n        });\n      });\n\n      this.wyckoffValue.innerHTML = '<table>' + wyckoffHTML+'</table>';\n    }\n\n    InfoSys.addElementToInfoSystem(this.spaceGroupValue,\n      'space-group.value:'+data.space_group_number);\n    InfoSys.addElementToInfoSystem(this.latticeValue,\n      'crystal-system.value:'+data.crystal_system);\n    InfoSys.addElementToInfoSystem(this.pointGroupValue,\n      'point-group.value:'+data.point_group);\n    //InfoSys.addElementToInfoSystem(this.wyckoffValue, 'wyckoff-position-population.value:'+);\n  }\n\n  /**\n   * Called whenever selections (checkboxes) in the navigation tree are\n   * modified.\n   */\n  updateSelection(leafIds) {\n\n    if (leafIds.size > 0) {\n\n      // Create a list of calculation ids for which statistics are fetched. For\n      // calculation groups, the first calculation is included in the\n      // statistics, as it corresponds to the lowest energy calculation.\n      let calcs = [];\n      leafIds.forEach(leafId => {\n        let isGroup = DataStore.isGroup(leafId);\n        if (isGroup) {\n          let groupType = DataStore.getGroupType(leafId);\n          let groupId = DataStore.getGroupId(leafId);\n          let calculations = DataStore.getGroups().get(groupType).get(groupId);\n          // Calculations are sorted by energy, first has lowest energy.\n          calcs.push(DataStore.getCalc(calculations[0]));\n        } else {\n          calcs.push(DataStore.getCalc(leafId));\n        }\n      });\n\n      this.summaryBox.style.visibility = 'visible';\n\n      // Groups calculation by their functional\n      let calcMapByFunctional = util.getCalcMapByFunctional(calcs);\n\n      // Build new summary based on the selection\n      this.summaryByFunctionals.build(calcMapByFunctional);\n\n    // Hide statistics box if no selections are made\n    } else {\n      this.summaryBox.style.visibility = 'hidden';\n    }\n  }\n\n  /**\n   * Called whenever individual calculations are selected in the navigation\n   * tree.\n   */\n  updateMarkedLeaf(leafId) {\n    let isGroup = false;\n    if (leafId !== null){\n\n      // Update leaf component title\n      this.calcSpecificsBox.style.visibility = 'visible';\n      isGroup = DataStore.isGroup(leafId);\n      if (isGroup) {\n        let groupType = DataStore.getGroupType(leafId);\n        let groupId = DataStore.getGroupId(leafId);\n        let calculations;\n        calculations = DataStore.getGroups().get(groupType).get(groupId);\n        this.leafTitle.innerHTML = util.getShortCode(leafId) +\n          ' ('+calculations.length+')';\n      } else {\n        this.leafTitle.innerHTML = util.getShortCode(leafId);\n      }\n    } else {\n      this.calcSpecificsBox.style.visibility = 'hidden';\n    }\n    this.treeLeafViewer.update(leafId, isGroup);\n  }\n}\n\n\nclass TreeLeafViewer {\n  constructor(hostClass) {\n    this.groupCalcs = null;\n    this.element = document.createElement('div');\n    this.element.innerHTML = `\n    <div>\n\n      <div class=\"group-components\" style=\"display: none\">\n        <div style=\"padding: 10px 0 30px 10px; \" class=\"eos-host\">\n        </div>\n\n        <div style=\"padding-top: 10px; \" class=\"calc-selector-host\">\n        </div>\n      </div>\n\n      <div class=\"info-fields\">\n        <div><b>Lattice constants</b></div>\n        <div class=\"latt-constants\"></div>\n        <div class=\"volume-field\"><b><span info-sys-data=\"cell-volume\">Volume</span></b>:\n          <span class=\"volume-value\" ></span>\n        </div>\n        <!-- <div><b>Pressure</b>: <span class=\"\" ></span>  </div>-->\n        <div class=\"density-field\"><b>Density</b>:\n            <div class=\"stats-fields\" >\n              <span info-sys-data=\"mass-density\">Mass density</span> =\n              <span class=\"mass-density-value\" ></span>\n            </div>\n            <div class=\"stats-fields\" >\n              <span info-sys-data=\"atomic-density\">Atomic density</span> =\n              <span class=\"atomic-density-value\" ></span>\n            </div>\n        </div>\n\n        <div class=\"energy-field\"><b><span info-sys-data=\"energies\">Energies</span></b> (code-specific)</div>\n        <div class=\"energy-descomp\"> </div>\n\n        <div class=\"wyckoff-pos-calc-field\" >\n          <b><span info-sys-data=\"free-wyckoff-parameters\">Wyckoff sites</span></b>\n          (fractional coordinates)\n          <div class=\"wyckoff-pos-calc-table\"> </div>\n        </div>\n\n      </div>\n\n    </div>\n    `;\n\n    this.groupComponents = this.element.querySelector('.group-components');\n\n    this.calcSelector = new CalcSelectorBar('calc-selector-bar','60%');\n    this.element.querySelector('.calc-selector-host').\n      appendChild(this.calcSelector.element);\n\n    this.lattConstantsField = this.element.querySelector('.latt-constants');\n    this.volumeField = this.element.querySelector('.volume-field');\n    this.volumeValue = this.element.querySelector('.volume-value');\n    this.densityField = this.element.querySelector('.density-field');\n    this.massDensityValue = this.element.querySelector('.mass-density-value');\n    this.atomicDensityValue = this.element.querySelector('.atomic-density-value');\n\n    this.energyField= this.element.querySelector('.energy-field');\n    this.energyDescompValue= this.element.querySelector('.energy-descomp');\n\n    this.wyckoffPosField = this.element.querySelector('.wyckoff-pos-calc-field');\n    this.wyckoffPosTable = this.element.querySelector('.wyckoff-pos-calc-table');\n\n    this.eosViewer = new EquationOfStateViewer();\n    this.eosViewer.attach(this.element.querySelector('.eos-host'),320, 280);\n\n      this.eosViewer.setClickPointListener( calc => {\n      this.groupCalcUpdate(calc+'');\n    });\n\n    InfoSys.addToInfoSystem(this.element);\n\n    this._events();\n  }\n\n  _events() {\n    this.calcSelector.setPrevListener(e => {\n      if (this.groupIndex > 0){\n        this.groupCalcUpdate(this.groupCalcs[--this.groupIndex]+'');\n        return this.groupIndex === 0; // the first\n      }\n    });\n\n    this.calcSelector.setNextListener( e => {\n      if (this.groupIndex < this.groupCalcs.length-1){\n        this.groupCalcUpdate(this.groupCalcs[++this.groupIndex]+'');\n        return this.groupIndex === this.groupCalcs.length-1; // the last\n      }\n    });\n  }\n\n  /**\n  * Called when a specific calculation or group is selected in the navigation tree.\n  */\n  update(leafId, isGroup) {\n    this.representative = leafId;\n\n    // If a group is selected, the EOS data is fetched and displayed.\n    this.isGroup = isGroup;\n    if (isGroup){\n      let groupType = DataStore.getGroupType(leafId);\n      let groupId = DataStore.getGroupId(leafId);\n      let materialData = DataStore.getMaterialData();\n      let materialId = materialData.material_id;\n      let groupR = util.serverReq(util.getMaterialGroupURL(materialId, groupType, groupId), () => {\n        if (groupR.status === 200) {\n          let groupData = JSON.parse(groupR.response);\n          let volumes = groupData.volumes.map(x => x/1e-30);\n          let energies = groupData.energies.map(x => x/1.602176565e-19);\n          let calculations = groupData.calculations;\n          let eZero = energies[0];\n          this.groupCalcs = calculations;\n          this.groupIndex = 0;\n          this.groupComponents.style.display = 'block';\n          this.eosViewer.clear();\n          this.eosViewer.draw(volumes, energies, this.groupCalcs, eZero);\n          this.groupCalcUpdate(calculations[0]);\n        }\n      });\n    } else {\n      this.groupComponents.style.display = 'none';\n      this.groupCalcUpdate(leafId);\n    }\n  }\n\n  /**\n  * Updates the information that is displayed for a single calculation.\n  */\n  groupCalcUpdate(calcId) {\n    if (calcId !== null){\n\n      // Updates the selected calculation in the Equation of State viewer.\n      if (this.groupCalcs !== null){\n        this.groupIndex = this.groupCalcs.indexOf(calcId);\n        if (this.groupIndex >= 0){\n          let t = util.getShortCode(calcId)+' ('+(this.groupIndex+1)+'/'+this.groupCalcs.length+')';\n          this.calcSelector.setState(t, this.groupIndex === 0, this.groupIndex === this.groupCalcs.length-1);\n          this.eosViewer.selectCalc(calcId);\n        }\n      }\n\n      // Load data that is available already through the pre-fetched material\n      // and calculation data.\n      let materialData = DataStore.getMaterialData();\n      let materialId = materialData.material_id;\n      let is2Dsystem = (materialData.material_type === '2D');\n      let isBulk = (materialData.material_type === 'bulk');\n      let calc = DataStore.getCalc(calcId);\n      let thereIsWyckoffData = DataStore.getMaterialData().has_free_wyckoff_parameters;\n\n      // Make an API call to retrieve larger, calculation specific data.\n      let properties = [\"energies\", \"lattice_parameters\", \"mass_density\", \"atomic_density\", \"cell_volume\"];\n      if (thereIsWyckoffData) {\n        properties.push(\"wyckoff_sets\");\n      };\n      let query = JSON.stringify({properties: properties});\n      let calcR = util.serverReqPOST(util.getMaterialCalcURL(materialId, calcId), query, () => {\n        if (calcR.status === 200) {\n          let response = JSON.parse(calcR.response);\n\n          // Lattice parameters\n          let lattParams = response.lattice_parameters;\n          let lattCFieldHTML = ((is2Dsystem  || isBulk) ?\n            `<div>b = ${util.m2Angstrom(lattParams.b)}</div>` : '');\n          lattCFieldHTML += (isBulk ?\n            `<div>c = ${util.m2Angstrom(lattParams.c)}</div>` : '');\n          let lattBetaGammaFieldHTML = (isBulk ?\n              `<div>&alpha; = ${util.rad2degree(lattParams.alpha)}</div>\n              <div>&beta; = ${util.rad2degree(lattParams.beta)}</div>` : '');\n          lattBetaGammaFieldHTML += ((is2Dsystem  || isBulk) ?\n              `<div>&gamma; = ${util.rad2degree(lattParams.gamma)}</div>` : '');\n          this.lattConstantsField.innerHTML= `\n            <div style=\"float: left; \">\n              <div>a = ${util.m2Angstrom(lattParams.a)}</div>\n              ${lattCFieldHTML}\n            </div>\n            <div style=\"float: left; padding-left: 40px;\">\n              ${lattBetaGammaFieldHTML}\n            </div>\n            <div style=\"clear: both;padding: 0\"></div>\n          `;\n\n          // Volume, densities\n          this.densityField.style.display = (isBulk ? 'block' : 'none');\n          this.volumeField.style.display = (isBulk ? 'block' : 'none');\n          if (isBulk) {\n            this.volumeValue.innerHTML= util.m3ToAngstrom3(response.cell_volume);\n            this.atomicDensityValue.innerHTML= util.toAngstromMinus3(response.atomic_density);\n            this.massDensityValue.innerHTML = response.mass_density.toFixed(1) + ' kg/m<sup>3</sup>';\n          }\n\n          // Energies\n          let energyFound = false;\n          let energies = response.energies;\n          if (energies !== undefined) {\n            let energy_total = energies.energy_total;\n            if (energy_total !== undefined) {\n              energyFound = true;\n              this.energyDescompValue.innerHTML =\n                '<div>Total E = &nbsp; ' + util.J2eV(energy_total) + ' eV</div>';\n            }\n          }\n          this.energyField.style.display = (energyFound ? 'block' : 'none');\n          this.energyDescompValue.style.display = (energyFound ? 'block' : 'none');\n\n          // Wyckoff position parameters\n          this.wyckoffPosField.style.display = (thereIsWyckoffData ? 'block' : 'none');\n\n          if (thereIsWyckoffData) {\n            let wyckoffMap = new Map(); // Map(element, Array of pairArray[w-pos, coor])\n            response.wyckoff_sets.forEach(d => {\n              // Only entries having items in .variables are included\n              let varsHtml = '';\n              let hasVariables = false;\n              let variables = d.variables;\n              if (variables !== undefined) {\n                hasVariables = true;\n                [\"x\", \"y\", \"z\"].forEach(variable => {\n                  if (variable in variables) {\n                    let v = variables[variable];\n                    varsHtml += '' + variable + ' = ' + v.toFixed(2) + '<br>';\n                  }\n                });\n              }\n\n\n              if (hasVariables) {\n                let wyckoffVarsPair = [];\n                wyckoffVarsPair.push(d.wyckoff_letter);\n                wyckoffVarsPair.push(varsHtml);\n\n                if (wyckoffMap.has(d.element)) {\n                  wyckoffMap.get(d.element).push(wyckoffVarsPair);\n                } else {\n                  wyckoffMap.set(d.element, [wyckoffVarsPair]);\n                }\n              }\n\n            });\n\n            // Update Wyckoff information in the GUI\n            let wyckoffHTML= '';\n            wyckoffMap.forEach((posSet, element) => {\n              posSet.sort( (a, b) => {\n                return (a[0] > b[0] ? 1 : -1);\n              });\n              let firstPos = true;\n              wyckoffHTML += '<tr > <td style=\"width: 30%;\">'+element+' </td>';\n              posSet.forEach( pos => {\n                if (firstPos){\n                  firstPos = false;\n                  wyckoffHTML += '<td style=\"width: 30%; \">'+pos[0]+'</td><td style=\"width: 40%;\">'+pos[1]+'</td></tr>';\n                }else\n                  wyckoffHTML += '<tr><td> </td><td>'+pos[0]+'</td><td>'+pos[1]+'</td></tr>';\n              });\n            });\n            this.wyckoffPosTable.innerHTML = '<table id=\"calc-wyckoff\">' + wyckoffHTML+'</table>';\n          }\n        }\n      });\n    }\n  }\n}\n\n\nclass SummaryByFunctionalsComponent {\n\n  constructor(hostElement) {\n    this.calcMapByFunctional = null;\n    this.quantitiesMap = null;\n    this.hostElement = hostElement;\n    this.graphTrigger = null;\n    this.viewType = 'text';\n    this.functional = null;\n    this.nBins = 15;\n    this.hostElement.innerHTML+=`\n      <div style=\"float: left\" >\n        <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"chart-tab\"\n          viewBox=\"0 0 15 15\" width=\"15\" height=\"15\" style=\"fill: #c7c7c7;\">\n            <rect x=\"0\" y=\"0\"  width=\"2\" height=\"15\" />\n            <rect   x=\"3\" y=\"5\"  width=\"1.8\" height=\"7\"  />\n            <rect  x=\"6\" y=\"3\"  width=\"1.8\" height=\"9\"  />\n            <rect   x=\"9\" y=\"6\"  width=\"1.8\" height=\"6\"  />\n            <rect  x=\"12\" y=\"2\"  width=\"1.8\" height=\"10\"  />\n            <rect x=\"2\" y=\"13\"   width=\"13\" height=\"2\" />\n        </svg>\n        <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"text-tab\"\n          viewBox=\"0 0 15 15\" width=\"15\" height=\"15\" style=\"fill: #777;\">\n            <rect x=\"0\" y=\"1\"   width=\"15\" height=\"2.5\" />\n            <rect   x=\"0\" y=\"6\"  width=\"15\" height=\"2.5\"  />\n            <rect  x=\"0\" y=\"11\"  width=\"15\" height=\"2.5\"  />\n        </svg>\n      </div>\n\n      <div class=\"functional-tabs\" style=\"float: right\">\n      </div>\n\n      <div style=\"clear: both;\"></div>\n\n      <div class=\"content-placeholder\" >\n\n        <div style=\"display: block\" class=\"text-panel\" >\n          <div><b>Lattice constants</b>:\n            <div class=\"stats-fields latt-constants-field\" >\n            </div>\n          </div>\n          <div class=\"volume-field\"><b><span info-sys-data=\"cell-volume\">Volume</span></b> (&#197;<sup>3</sup>):\n            <div class=\"stats-fields volume-value\" > </div>\n          </div>\n          <div class=\"density-field\"><b>Density</b> :\n            <div >\n              <div class=\"stats-fields\" >\n                <span info-sys-data=\"mass-density\">Mass density</span> (kg/m<sup>3</sup>) =\n                <span class=\"mass-density-value\" ></span>\n              </div>\n              <div class=\"stats-fields\" >\n                <span info-sys-data=\"atomic-density\">Atomic density</span> (&#197;<sup>-3</sup>) =\n                <span class=\"atomic-density-value\" ></span>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <div style=\"display:none\" class=\"chart-panel\" >\n          <div class=\"charts-placeholder\" > </div>\n          <div class=\"charts-selector\" >\n\n          </div>\n        </div>\n\n      </div>\n    `;\n    this.chartTab = this.hostElement.querySelector('.chart-tab');\n    this.textTab = this.hostElement.querySelector('.text-tab');\n    this.functionalTabs = this.hostElement.querySelector('.functional-tabs');\n    this.chartPanel = this.hostElement.querySelector('.chart-panel');\n    this.textPanel = this.hostElement.querySelector('.text-panel');\n    this.lattConstantsField = this.hostElement.querySelector('.latt-constants-field');\n    this.volumeField = this.hostElement.querySelector('.volume-field');\n    this.volumeFieldValue = this.hostElement.querySelector('.volume-value');\n    this.densityField = this.hostElement.querySelector('.density-field');\n    this.massDensityValue = this.hostElement.querySelector('.mass-density-value');\n    this.atomicDensityValue = this.hostElement.querySelector('.atomic-density-value');\n\n    this.statsViewer = new StatsViewer();\n    let chartsPlaceholder = this.hostElement.querySelector('.charts-placeholder');\n    this.statsViewer.attach(chartsPlaceholder, 350, 200);\n\n    this.chartsSelector = this.hostElement.querySelector('.charts-selector');\n\n    this.chartTab.addEventListener( \"click\", e => {\n      this.chartTab.style.fill = '#777';\n      this.viewType = 'chart';\n      this.textTab.style.fill = '#c7c7c7';\n      this.chartPanel.style.display = 'block';\n      this.textPanel.style.display = 'none';\n    });\n\n    this.textTab.addEventListener( \"click\", e => {\n      this.textTab.style.fill = '#777';\n      this.viewType = 'text';\n      this.chartTab.style.fill = '#c7c7c7';\n      this.textPanel.style.display = 'block';\n      this.chartPanel.style.display = 'none';\n    });\n\n    this.functionalTabs.addEventListener( \"click\", e => {\n      if (e.target.className === 'tab'){\n        this.statsViewer.clear();\n        this.functionalTabs.querySelector('[data-tab=\"'+this.functional+'\"]')\n          .className = 'tab';\n        this.functional = e.target.getAttribute('data-tab');\n        this.functionalTabs.querySelector('[data-tab=\"'+this.functional+'\"]')\n          .className = 'tab-selected';\n        this._setData();\n      }\n    });\n\n    this.chartsSelector.addEventListener( \"click\", e => {\n      if (e.target.className.indexOf('quantity') === 0){\n        this.statsViewer.clear();\n        let quantity = e.target.getAttribute('data-quantity');\n\n        let quantityData = this.quantitiesMap.get(quantity);\n        let label = quantityData.label;\n        let stats = quantityData.stats;\n        this.statsViewer.drawPoints(stats.histogram, label, this.nBins);\n        this.chartsSelector.querySelector('.quantity-selected').className = 'quantity';\n        e.target.className = 'quantity-selected';\n      }\n    });\n\n  }\n\n  /**\n   * Called when a functional is selected.\n   */\n  _setData() {\n    let is2Dsystem = (DataStore.getMaterialData().material_type === '2D');\n    let isBulk = (DataStore.getMaterialData().material_type === 'bulk');\n    let functional = this.functional;\n    let calcs = Array.from(this.calcMapByFunctional.get(this.functional));\n    let matId = DataStore.getMaterialData().material_id;\n    let quantitiesMap = new Map();\n    quantitiesMap.set(\"lattice_a\", {label: 'a (Å)'});\n\n    if (is2Dsystem | isBulk) {\n      quantitiesMap.set(\"lattice_b\", {label: 'b (Å)'});\n      quantitiesMap.set(\"gamma\", {label: '&gamma'});\n    }\n    if (isBulk) {\n      quantitiesMap.set(\"cell_volume\", {label: 'Volume (ų)'});\n      quantitiesMap.set(\"atomic_density\", {label: 'Atomic density (Å⁻³)'});\n      quantitiesMap.set(\"mass_density\", {label: 'Mass density (kg/m³)'});\n      quantitiesMap.set(\"lattice_c\", {label: 'c ()'});\n      quantitiesMap.set(\"alpha\", {label: '&alpha'});\n      quantitiesMap.set(\"beta\", {label: '&beta'});\n    }\n\n    // Query statistics from the API\n    let query = JSON.stringify({\n      calculations: calcs,\n      properties: Array.from(quantitiesMap.keys()),\n      n_histogram_bins: this.nBins,\n    });\n    util.serverReqPOST(util.getMaterialStatsURL(matId), query, e3 => {\n      let results = JSON.parse(e3.target.response);\n\n      // Create formatted string for each stat\n      for (let quantity of quantitiesMap.keys()) {\n\n        let stats = results[quantity];\n\n        // Unit conversions\n        if (quantity == \"cell_volume\") {\n          stats.min *= 1e30;\n          stats.avg *= 1e30;\n          stats.max *= 1e30;\n          stats.histogram.values = stats.histogram.values.map(x => x*1e30);\n        } else if (quantity == \"atomic_density\") {\n          stats.min *= 1e-30;\n          stats.avg *= 1e-30;\n          stats.max *= 1e-30;\n          stats.histogram.values = stats.histogram.values.map(x => x*1e-30);\n        } else if (quantity.startsWith(\"lattice_\")) {\n          stats.min *= 1e10;\n          stats.avg *= 1e10;\n          stats.max *= 1e10;\n          stats.histogram.values = stats.histogram.values.map(x => x*1e10);\n        }\n        let label = quantitiesMap.get(quantity).label;\n        stats.equal = (stats.min === stats.max);\n        let lls = label.split(':');\n        stats.label = lls[0];\n        if (lls.length === 2) {\n          stats.units = lls[1];\n        } else {\n          stats.units = '';\n        }\n        let decimals = 3;\n        if (quantity === 'mass_density') decimals = 1;\n        let html;\n        if (quantity == \"alpha\" || quantity == \"beta\" || quantity == \"gamma\") {\n          html = util.rad2degree(stats.avg.toFixed(decimals));\n        } else {\n          html = stats.avg.toFixed(decimals)+\n            ' &nbsp; <span style=\"font-size: 0.9em\">['+stats.min.toFixed(decimals)\n            +' , '+stats.max.toFixed(decimals)+']</span>';\n        }\n\n        quantitiesMap.get(quantity).html = html;\n        quantitiesMap.get(quantity).stats = stats;\n      };\n\n      let lattCFieldHTML = ((is2Dsystem || isBulk) ?\n            `<div>b (&#197;) = ${quantitiesMap.get('lattice_b').html}</div>` : '');\n\n      lattCFieldHTML += (isBulk ?\n        `<div>c (&#197;) = ${quantitiesMap.get('lattice_c').html}</div>` : '');\n\n      // Construct angle field\n      let lattBetaGammaFieldHTML = (isBulk ?\n          `<div>&alpha; = ${quantitiesMap.get('alpha').html}</div>\n          <div>&beta; = ${quantitiesMap.get('beta').html}</div>` : '');\n      lattBetaGammaFieldHTML += ((is2Dsystem  || isBulk) ?\n          `<div>&gamma; = ${quantitiesMap.get('gamma').html}</div>` : '');\n\n      // Set text data\n      this.lattConstantsField.innerHTML = `\n        <div style=\"float: left; \">\n          <div>a (&#197;) = ${quantitiesMap.get('lattice_a').html}</div>\n          ${lattCFieldHTML}\n        </div>\n      <div style=\"float: left; padding-left: 40px;\">\n        ${lattBetaGammaFieldHTML}\n      </div>\n        <div style=\"clear: both;padding: 0\"></div>\n        `;\n\n      let chartSelectorHTML= `\n      <span class=\"quantity-selected\" data-quantity=\"lattice_a\">a</span>\n      `;\n\n      if (is2Dsystem || isBulk)\n        chartSelectorHTML += `<span class=\"quantity\" data-quantity=\"lattice_b\">b</span>`;\n      this.densityField.style.display = (isBulk ? 'block' : 'none');\n      this.volumeField.style.display = (isBulk ? 'block' : 'none');\n      if (isBulk) { // bulk type\n        this.volumeFieldValue.innerHTML = quantitiesMap.get('cell_volume').html;\n        this.massDensityValue.innerHTML = quantitiesMap.get('mass_density').html;\n        this.atomicDensityValue.innerHTML = quantitiesMap.get('atomic_density').html;\n        chartSelectorHTML += `\n          <span class=\"quantity\" data-quantity=\"lattice_c\">c</span>\n          <span class=\"quantity\" data-quantity=\"cell_volume\">volume</span>\n          <span class=\"quantity\" data-quantity=\"mass_density\">mass density</span>\n          <span class=\"quantity\" data-quantity=\"atomic_density\">atomic density</span>\n        `;\n      }\n\n      this.chartsSelector.innerHTML = chartSelectorHTML;\n      this.quantitiesMap = quantitiesMap;\n\n      // Display histogram\n      let hist = results.lattice_a.histogram;\n      this.statsViewer.drawPoints(hist, quantitiesMap.get(\"lattice_a\").label, this.nBins);\n    });\n  }\n\n  build(calcMapByFunctional) {\n    this.calcMapByFunctional = calcMapByFunctional;\n    this.graphTrigger = null;\n    this.statsViewer.clear();\n    this.unfoldedElement = null;\n    this.functionalQuantityMap = new Map();\n\n    // Create tabs for each functional\n    this.functionalTabs.innerHTML = \"\";\n    this.calcMapByFunctional.forEach( (calcs, functionalName) => {\n      this.functionalTabs.innerHTML +=\n        '<span class=\"tab\" data-tab=\"'+functionalName+'\">'+functionalName+'</span>';\n    });\n\n    // Preselect the first functional\n    let functionals = Array.from(this.calcMapByFunctional.keys());\n    if (this.functional === null || functionals.indexOf(this.functional) < 0)\n      this.functional = functionals[0]; // the first one is selected\n    this._setData();\n    this.functionalTabs.querySelector('[data-tab=\"'+this.functional+'\"]').className = 'tab-selected';\n\n    InfoSys.addToInfoSystem(this.hostElement);\n  }\n\n}\n\n\n// EXPORTS\nmodule.exports = StructureDetails;\n\n\n//# sourceURL=webpack:///./src/material-mod/StructureDetails.view.js?");
+eval("\n/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n /*\n  'Details' view container that shows all the material info related to\n  its structure.\n\n  This container is extremely complex.\n\n  In the file there are two defined (classes) components used in the container:\n  - TreeLeafViewer: The panel on the right showing the data of the tree leaf marked\n  - SummaryByFunctionalsComponent: the component (central panel, below part)\n  showing a summary for the selected item on the tree (by functional)\n */\n\n\n\nlet DetailsViewBase = __webpack_require__(/*! ./DetailsViewBase.js */ \"./src/material-mod/DetailsViewBase.js\");\nlet util = __webpack_require__(/*! ../common/util.js */ \"./src/common/util.js\");\nlet InfoSys = __webpack_require__(/*! ../common/InfoSys.js */ \"./src/common/InfoSys.js\");\nlet NavTree = __webpack_require__(/*! ./NavTree.js */ \"./src/material-mod/NavTree.js\");\nlet CalcSelectorBar = __webpack_require__(/*! ./CalcSelectorBar.js */ \"./src/material-mod/CalcSelectorBar.js\");\nlet StatsViewer = __webpack_require__(/*! ./StatsViewer.js */ \"./src/material-mod/StatsViewer.js\");\nlet EquationOfStateViewer = __webpack_require__(/*! ./EquationOfStateViewer.js */ \"./src/material-mod/EquationOfStateViewer.js\");\nlet DataStore = __webpack_require__(/*! ./DataStore.js */ \"./src/material-mod/DataStore.js\");\n\n\nclass StructureDetails extends DetailsViewBase {\n\n  constructor() {\n    super('Structure');\n    this.navTree = new NavTree();\n    this.groupsData;\n    this.element.innerHTML+=`\n\n      <div style=\"float: left; width: 36%;\">\n        <div class=\"view-box\">\n          <div class=\"title\">Structure </div>\n          <div class=\"viz-box-container\" style=\"height: 400px; position: relative\">\n            <div class=\"viz-box\" style=\"height: 90%\"></div>\n          </div>\n\n          <div class=\"footer-flex-wrapper\">\n\n            <div class=\"fields-container\">\n              <div><b><span>System type</span></b>:\n                <span class=\"struct-field\" ></span>\n              </div>\n              <div class=\"structure-type-field\" style=\"display: none\">\n                <b><span info-sys-data=\"structure_type\">Structure type</span></b>:\n                <span class=\"structure-type-value\" ></span>\n              </div>\n              <div class=\"structure-prototype-field\" style=\"display: none\">\n                <b><span info-sys-data=\"structure_prototype\">Structure prototype</span></b>:\n                <span class=\"structure-prototype-value\" ></span>\n              </div>\n              <div class=\"strukturbericht-field\" style=\"display: none\">\n                <b><span info-sys-data=\"strukturbericht\">Strukturbericht designation</span></b>:\n                <span class=\"strukturbericht-value\" ></span>\n              </div>\n            </div>\n\n            <div class=\"footer-flex\" style=\"display: none\">\n\n              <div class=\"fields-container\"\n                style=\"flex-basis: 70%; border-right: 1px solid #E4E4E4; \">\n\n                <div>\n                  <b><span info-sys-data=\"crystal_system\">Lattice</span></b>:\n                  <span class=\"lattice-value\" ></span>\n                </div>\n                <div>\n                  <b><span info-sys-data=\"space_group_number\">Space group</span></b>:\n                  <span class=\"space-group-value\" ></span>\n                </div>\n                <div>\n                  <b><span info-sys-data=\"point-group\">Point group</span></b>:\n                  <span class=\"point-group-value\" ></span>\n                </div>\n              </div>\n\n              <div style=\"flex-basis: 30%; margin-left: 30px;\">\n                <div class=\"fields-container\">\n                  <div><b><span info-sys-data=\"wyckoff-position-population\">Wyckoff sites</span></b></div>\n                  <div class=\"wyckoff-sites-value\"> </div>\n                </div>\n              </div>\n\n            </div>\n\n          </div>\n\n        </div>\n      </div>\n\n      <div style=\"float: left; width: 36%;\">\n        <div class=\"view-box\">\n          <div class=\"title\">Calculations</div>\n          <div class=\"navTreeWrapper\"></div>\n\n          <div class=\"summary-title\">Summary  </div>\n          <div style=\"font-size: 0.85em; text-align: center; padding: 4px;\">Based on the calculations selected above</div>\n\n          <div class=\"info-fields summary-box\">\n          <!-- Lattice constants Cell volume, Density panel dynamically generated\n            -->\n          </div>\n        </div>\n      </div>\n\n      <div style=\"float: right; width: 28%;\">\n        <div class=\"calc-specifics-box\">\n          <div style=\"padding-top: 10px; \" >\n            <div class=\"tree-leaf-title\"></div>\n          </div>\n          <div class=\"tree-leaf-viewer-host\"></div>\n          </div>\n        </div>\n      </div>\n    </div>\n    `;\n\n    this.navTreeWrapper =\n        this.element.getElementsByClassName(\"navTreeWrapper\")[0];\n\n    let fields= this.element.getElementsByClassName('struct-field');\n    this.systemTypeField= fields[0];\n    this.structTypeField= this.element.querySelector('.structure-type-field');\n    this.structTypeValue= this.element.querySelector('.structure-type-value');\n    this.structPrototypeField= this.element.querySelector('.structure-prototype-field');\n    this.structPrototypeValue= this.element.querySelector('.structure-prototype-value');\n    this.strukturberichtField= this.element.querySelector('.strukturbericht-field');\n    this.strukturberichtValue= this.element.querySelector('.strukturbericht-value');\n\n    this.lowerBox = this.element.querySelector('.footer-flex');\n    this.latticeValue= this.element.querySelector('.lattice-value');\n    this.spaceGroupValue= this.element.querySelector('.space-group-value');\n    this.pointGroupValue= this.element.querySelector('.point-group-value');\n    this.wyckoffValue= this.element.querySelector('.wyckoff-sites-value');\n\n    this.summaryByFunctionals = null;\n\n    this.leafTitle = this.element.querySelector('.tree-leaf-title');\n\n    this.summaryBox = this.element.querySelector('.summary-box');\n    this.summaryByFunctionals = new SummaryByFunctionalsComponent(this.summaryBox);\n\n    this.calcSpecificsBox = this.element.querySelector('.calc-specifics-box');\n\n    this.treeLeafViewer = new TreeLeafViewer();\n    this.element.querySelector('.tree-leaf-viewer-host').\n      appendChild(this.treeLeafViewer.element);\n\n    this.vizBox = this.element.querySelector('.viz-box');\n\n    // For static ones\n    InfoSys.addToInfoSystem(this.element);\n  }\n\n  setMaterialData() {\n    let data = DataStore.getMaterialData();\n    let idealizedStructure = DataStore.getIdealizedStructure();\n    super.setMaterialData(data);\n\n    // Build the navigation tree and attach listeners\n    let name = (data.material_name === null ?\n      data.formula : data.material_name);\n    this.navTree.build(name, \"structure\");\n    this.navTree.selectAll();\n    this.navTree.setHeight(250);\n    this.navTree.setMarkedLeafIfNoneMarked(null); // Set the first leaf marked\n    this.attachNavTree(this.navTree);\n    this.updateSelection(this.navTree.getTreeSelectedCalcs());\n    this.updateMarkedLeaf(this.navTree.getMarkedLeaf());\n    this.navTree.setTreeSelectionListener( leafIds => {\n      this.updateSelection(leafIds);\n    });\n    this.navTree.setLeafMarkedListener( leafId => {\n      this.updateMarkedLeaf(leafId);\n    });\n\n    this.isBulk = (data.material_type === 'bulk');\n\n    this.systemTypeField.textContent= data.material_type;\n    this.structTypeField.style.display =\n      (this.isBulk && data.structure_type !== null ? 'block' : 'none');\n    this.structPrototypeField.style.display =\n      (this.isBulk && data.structure_prototype !== null ? 'block' : 'none');\n    this.strukturberichtField.style.display =\n      (this.isBulk && data.strukturbericht_designation !== null ? 'block' : 'none');\n\n    this.lowerBox.style.display = (this.isBulk ? 'flex' : 'none');\n\n    if (this.isBulk){\n      this.structTypeValue.textContent= data.structure_type;\n      this.structPrototypeValue.textContent= data.structure_prototype;\n      this.strukturberichtValue.textContent= data.strukturbericht_designation;\n      this.spaceGroupValue.textContent = data.space_group_number\n        +' ('+data.space_group_international_short_symbol+')';\n      this.pointGroupValue.textContent = data.point_group;\n      this.latticeValue.textContent = data.crystal_system;\n\n      // Wyckoff processing\n      let wyckoffMap = new Map();\n      let valueSet= new Set();\n\n      for (var i = 0; i < idealizedStructure.wyckoff_sets.length; i++) {\n        let wset = idealizedStructure.wyckoff_sets[i];\n        let element = wset.element;\n        if (wyckoffMap.has(element)){\n          wyckoffMap.get(element).add(wset.wyckoff_letter);\n        } else {\n          let newSet = new Set();\n          newSet.add(wset.wyckoff_letter);\n          wyckoffMap.set(element, newSet);\n        }\n      }\n\n      let wyckoffHTML= '';\n      wyckoffMap.forEach((posSet, element) => {\n        let firstPos = true;\n        wyckoffHTML += '<tr> <td>'+element+': </td>';\n        posSet.forEach( pos => {\n          if (firstPos){\n            firstPos = false;\n            wyckoffHTML += '<td>'+pos+'</td></tr>';\n          }else\n            wyckoffHTML += '<tr><td> </td><td>'+pos+'</td></tr>';\n        });\n      });\n\n      this.wyckoffValue.innerHTML = '<table>' + wyckoffHTML+'</table>';\n    }\n\n    InfoSys.addElementToInfoSystem(this.spaceGroupValue,\n      'space_group_number.value:'+data.space_group_number);\n    InfoSys.addElementToInfoSystem(this.latticeValue,\n      'crystal_system.value:'+data.crystal_system);\n    InfoSys.addElementToInfoSystem(this.pointGroupValue,\n      'point-group.value:'+data.point_group);\n    //InfoSys.addElementToInfoSystem(this.wyckoffValue, 'wyckoff-position-population.value:'+);\n  }\n\n  /**\n   * Called whenever selections (checkboxes) in the navigation tree are\n   * modified.\n   */\n  updateSelection(leafIds) {\n\n    if (leafIds.size > 0) {\n\n      // Create a list of calculation ids for which statistics are fetched. For\n      // calculation groups, the first calculation is included in the\n      // statistics, as it corresponds to the lowest energy calculation.\n      let calcs = [];\n      leafIds.forEach(leafId => {\n        let isGroup = DataStore.isGroup(leafId);\n        if (isGroup) {\n          let groupType = DataStore.getGroupType(leafId);\n          let groupId = DataStore.getGroupId(leafId);\n          let calculations = DataStore.getGroups().get(groupType).get(groupId);\n          // Calculations are sorted by energy, first has lowest energy.\n          calcs.push(DataStore.getCalc(calculations[0]));\n        } else {\n          calcs.push(DataStore.getCalc(leafId));\n        }\n      });\n\n      this.summaryBox.style.visibility = 'visible';\n\n      // Groups calculation by their functional\n      let calcMapByFunctional = util.getCalcMapByFunctional(calcs);\n\n      // Build new summary based on the selection\n      this.summaryByFunctionals.build(calcMapByFunctional);\n\n    // Hide statistics box if no selections are made\n    } else {\n      this.summaryBox.style.visibility = 'hidden';\n    }\n  }\n\n  /**\n   * Called whenever individual calculations are selected in the navigation\n   * tree.\n   */\n  updateMarkedLeaf(leafId) {\n    let isGroup = false;\n    if (leafId !== null){\n\n      // Update leaf component title\n      this.calcSpecificsBox.style.visibility = 'visible';\n      isGroup = DataStore.isGroup(leafId);\n      if (isGroup) {\n        let groupType = DataStore.getGroupType(leafId);\n        let groupId = DataStore.getGroupId(leafId);\n        let calculations;\n        calculations = DataStore.getGroups().get(groupType).get(groupId);\n        this.leafTitle.innerHTML = util.getShortCode(leafId) +\n          ' ('+calculations.length+')';\n      } else {\n        this.leafTitle.innerHTML = util.getShortCode(leafId);\n      }\n    } else {\n      this.calcSpecificsBox.style.visibility = 'hidden';\n    }\n    this.treeLeafViewer.update(leafId, isGroup);\n  }\n}\n\n\nclass TreeLeafViewer {\n  constructor(hostClass) {\n    this.groupCalcs = null;\n    this.element = document.createElement('div');\n    this.element.innerHTML = `\n    <div>\n\n      <div class=\"group-components\" style=\"display: none\">\n        <div style=\"padding: 10px 0 30px 10px; \" class=\"eos-host\">\n        </div>\n\n        <div style=\"padding-top: 10px; \" class=\"calc-selector-host\">\n        </div>\n      </div>\n\n      <div class=\"info-fields\">\n        <div><b>Lattice constants</b></div>\n        <div class=\"latt-constants\"></div>\n        <div class=\"volume-field\"><b><span info-sys-data=\"cell-volume\">Volume</span></b>:\n          <span class=\"volume-value\" ></span>\n        </div>\n        <!-- <div><b>Pressure</b>: <span class=\"\" ></span>  </div>-->\n        <div class=\"density-field\"><b>Density</b>:\n            <div class=\"stats-fields\" >\n              <span info-sys-data=\"mass-density\">Mass density</span> =\n              <span class=\"mass-density-value\" ></span>\n            </div>\n            <div class=\"stats-fields\" >\n              <span info-sys-data=\"atomic-density\">Atomic density</span> =\n              <span class=\"atomic-density-value\" ></span>\n            </div>\n        </div>\n\n        <div class=\"energy-field\"><b><span info-sys-data=\"energies\">Energies</span></b> (code-specific)</div>\n        <div class=\"energy-descomp\"> </div>\n\n        <div class=\"wyckoff-pos-calc-field\" >\n          <b><span info-sys-data=\"free-wyckoff-parameters\">Wyckoff sites</span></b>\n          (fractional coordinates)\n          <div class=\"wyckoff-pos-calc-table\"> </div>\n        </div>\n\n      </div>\n\n    </div>\n    `;\n\n    this.groupComponents = this.element.querySelector('.group-components');\n\n    this.calcSelector = new CalcSelectorBar('calc-selector-bar','60%');\n    this.element.querySelector('.calc-selector-host').\n      appendChild(this.calcSelector.element);\n\n    this.lattConstantsField = this.element.querySelector('.latt-constants');\n    this.volumeField = this.element.querySelector('.volume-field');\n    this.volumeValue = this.element.querySelector('.volume-value');\n    this.densityField = this.element.querySelector('.density-field');\n    this.massDensityValue = this.element.querySelector('.mass-density-value');\n    this.atomicDensityValue = this.element.querySelector('.atomic-density-value');\n\n    this.energyField= this.element.querySelector('.energy-field');\n    this.energyDescompValue= this.element.querySelector('.energy-descomp');\n\n    this.wyckoffPosField = this.element.querySelector('.wyckoff-pos-calc-field');\n    this.wyckoffPosTable = this.element.querySelector('.wyckoff-pos-calc-table');\n\n    this.eosViewer = new EquationOfStateViewer();\n    this.eosViewer.attach(this.element.querySelector('.eos-host'),320, 280);\n\n      this.eosViewer.setClickPointListener( calc => {\n      this.groupCalcUpdate(calc+'');\n    });\n\n    InfoSys.addToInfoSystem(this.element);\n\n    this._events();\n  }\n\n  _events() {\n    this.calcSelector.setPrevListener(e => {\n      if (this.groupIndex > 0){\n        this.groupCalcUpdate(this.groupCalcs[--this.groupIndex]+'');\n        return this.groupIndex === 0; // the first\n      }\n    });\n\n    this.calcSelector.setNextListener( e => {\n      if (this.groupIndex < this.groupCalcs.length-1){\n        this.groupCalcUpdate(this.groupCalcs[++this.groupIndex]+'');\n        return this.groupIndex === this.groupCalcs.length-1; // the last\n      }\n    });\n  }\n\n  /**\n  * Called when a specific calculation or group is selected in the navigation tree.\n  */\n  update(leafId, isGroup) {\n    this.representative = leafId;\n\n    // If a group is selected, the EOS data is fetched and displayed.\n    this.isGroup = isGroup;\n    if (isGroup){\n      let groupType = DataStore.getGroupType(leafId);\n      let groupId = DataStore.getGroupId(leafId);\n      let materialData = DataStore.getMaterialData();\n      let materialId = materialData.material_id;\n      let groupR = util.serverReq(util.getMaterialGroupURL(materialId, groupType, groupId), () => {\n        if (groupR.status === 200) {\n          let groupData = JSON.parse(groupR.response);\n          let volumes = groupData.volumes.map(x => x/1e-30);\n          let energies = groupData.energies.map(x => x/1.602176565e-19);\n          let calculations = groupData.calculations;\n          let eZero = energies[0];\n          this.groupCalcs = calculations;\n          this.groupIndex = 0;\n          this.groupComponents.style.display = 'block';\n          this.eosViewer.clear();\n          this.eosViewer.draw(volumes, energies, this.groupCalcs, eZero);\n          this.groupCalcUpdate(calculations[0]);\n        }\n      });\n    } else {\n      this.groupComponents.style.display = 'none';\n      this.groupCalcUpdate(leafId);\n    }\n  }\n\n  /**\n  * Updates the information that is displayed for a single calculation.\n  */\n  groupCalcUpdate(calcId) {\n    if (calcId !== null){\n\n      // Updates the selected calculation in the Equation of State viewer.\n      if (this.groupCalcs !== null){\n        this.groupIndex = this.groupCalcs.indexOf(calcId);\n        if (this.groupIndex >= 0){\n          let t = util.getShortCode(calcId)+' ('+(this.groupIndex+1)+'/'+this.groupCalcs.length+')';\n          this.calcSelector.setState(t, this.groupIndex === 0, this.groupIndex === this.groupCalcs.length-1);\n          this.eosViewer.selectCalc(calcId);\n        }\n      }\n\n      // Load data that is available already through the pre-fetched material\n      // and calculation data.\n      let materialData = DataStore.getMaterialData();\n      let materialId = materialData.material_id;\n      let is2Dsystem = (materialData.material_type === '2D');\n      let isBulk = (materialData.material_type === 'bulk');\n      let calc = DataStore.getCalc(calcId);\n      let thereIsWyckoffData = DataStore.getMaterialData().has_free_wyckoff_parameters;\n\n      // Make an API call to retrieve larger, calculation specific data.\n      let properties = [\"energies\", \"lattice_parameters\", \"mass_density\", \"atomic_density\", \"cell_volume\"];\n      if (thereIsWyckoffData) {\n        properties.push(\"wyckoff_sets\");\n      };\n      let query = JSON.stringify({properties: properties});\n      let calcR = util.serverReqPOST(util.getMaterialCalcURL(materialId, calcId), query, () => {\n        if (calcR.status === 200) {\n          let response = JSON.parse(calcR.response);\n\n          // Lattice parameters\n          let lattParams = response.lattice_parameters;\n          let lattCFieldHTML = ((is2Dsystem  || isBulk) ?\n            `<div>b = ${util.m2Angstrom(lattParams.b)}</div>` : '');\n          lattCFieldHTML += (isBulk ?\n            `<div>c = ${util.m2Angstrom(lattParams.c)}</div>` : '');\n          let lattBetaGammaFieldHTML = (isBulk ?\n              `<div>&alpha; = ${util.rad2degree(lattParams.alpha)}</div>\n              <div>&beta; = ${util.rad2degree(lattParams.beta)}</div>` : '');\n          lattBetaGammaFieldHTML += ((is2Dsystem  || isBulk) ?\n              `<div>&gamma; = ${util.rad2degree(lattParams.gamma)}</div>` : '');\n          this.lattConstantsField.innerHTML= `\n            <div style=\"float: left; \">\n              <div>a = ${util.m2Angstrom(lattParams.a)}</div>\n              ${lattCFieldHTML}\n            </div>\n            <div style=\"float: left; padding-left: 40px;\">\n              ${lattBetaGammaFieldHTML}\n            </div>\n            <div style=\"clear: both;padding: 0\"></div>\n          `;\n\n          // Volume, densities\n          this.densityField.style.display = (isBulk ? 'block' : 'none');\n          this.volumeField.style.display = (isBulk ? 'block' : 'none');\n          if (isBulk) {\n            this.volumeValue.innerHTML= util.m3ToAngstrom3(response.cell_volume);\n            this.atomicDensityValue.innerHTML= util.toAngstromMinus3(response.atomic_density);\n            this.massDensityValue.innerHTML = response.mass_density.toFixed(1) + ' kg/m<sup>3</sup>';\n          }\n\n          // Energies\n          let energyFound = false;\n          let energies = response.energies;\n          if (energies !== undefined) {\n            let energy_total = energies.energy_total;\n            if (energy_total !== undefined) {\n              energyFound = true;\n              this.energyDescompValue.innerHTML =\n                '<div>Total E = &nbsp; ' + util.J2eV(energy_total) + ' eV</div>';\n            }\n          }\n          this.energyField.style.display = (energyFound ? 'block' : 'none');\n          this.energyDescompValue.style.display = (energyFound ? 'block' : 'none');\n\n          // Wyckoff position parameters\n          this.wyckoffPosField.style.display = (thereIsWyckoffData ? 'block' : 'none');\n\n          if (thereIsWyckoffData) {\n            let wyckoffMap = new Map(); // Map(element, Array of pairArray[w-pos, coor])\n            response.wyckoff_sets.forEach(d => {\n              // Only entries having items in .variables are included\n              let varsHtml = '';\n              let hasVariables = false;\n              let variables = d.variables;\n              if (variables !== undefined) {\n                hasVariables = true;\n                [\"x\", \"y\", \"z\"].forEach(variable => {\n                  if (variable in variables) {\n                    let v = variables[variable];\n                    varsHtml += '' + variable + ' = ' + v.toFixed(2) + '<br>';\n                  }\n                });\n              }\n\n\n              if (hasVariables) {\n                let wyckoffVarsPair = [];\n                wyckoffVarsPair.push(d.wyckoff_letter);\n                wyckoffVarsPair.push(varsHtml);\n\n                if (wyckoffMap.has(d.element)) {\n                  wyckoffMap.get(d.element).push(wyckoffVarsPair);\n                } else {\n                  wyckoffMap.set(d.element, [wyckoffVarsPair]);\n                }\n              }\n\n            });\n\n            // Update Wyckoff information in the GUI\n            let wyckoffHTML= '';\n            wyckoffMap.forEach((posSet, element) => {\n              posSet.sort( (a, b) => {\n                return (a[0] > b[0] ? 1 : -1);\n              });\n              let firstPos = true;\n              wyckoffHTML += '<tr > <td style=\"width: 30%;\">'+element+' </td>';\n              posSet.forEach( pos => {\n                if (firstPos){\n                  firstPos = false;\n                  wyckoffHTML += '<td style=\"width: 30%; \">'+pos[0]+'</td><td style=\"width: 40%;\">'+pos[1]+'</td></tr>';\n                }else\n                  wyckoffHTML += '<tr><td> </td><td>'+pos[0]+'</td><td>'+pos[1]+'</td></tr>';\n              });\n            });\n            this.wyckoffPosTable.innerHTML = '<table id=\"calc-wyckoff\">' + wyckoffHTML+'</table>';\n          }\n        }\n      });\n    }\n  }\n}\n\n\nclass SummaryByFunctionalsComponent {\n\n  constructor(hostElement) {\n    this.calcMapByFunctional = null;\n    this.quantitiesMap = null;\n    this.hostElement = hostElement;\n    this.graphTrigger = null;\n    this.viewType = 'text';\n    this.functional = null;\n    this.nBins = 15;\n    this.hostElement.innerHTML+=`\n      <div style=\"float: left\" >\n        <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"chart-tab\"\n          viewBox=\"0 0 15 15\" width=\"15\" height=\"15\" style=\"fill: #c7c7c7;\">\n            <rect x=\"0\" y=\"0\"  width=\"2\" height=\"15\" />\n            <rect   x=\"3\" y=\"5\"  width=\"1.8\" height=\"7\"  />\n            <rect  x=\"6\" y=\"3\"  width=\"1.8\" height=\"9\"  />\n            <rect   x=\"9\" y=\"6\"  width=\"1.8\" height=\"6\"  />\n            <rect  x=\"12\" y=\"2\"  width=\"1.8\" height=\"10\"  />\n            <rect x=\"2\" y=\"13\"   width=\"13\" height=\"2\" />\n        </svg>\n        <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"text-tab\"\n          viewBox=\"0 0 15 15\" width=\"15\" height=\"15\" style=\"fill: #777;\">\n            <rect x=\"0\" y=\"1\"   width=\"15\" height=\"2.5\" />\n            <rect   x=\"0\" y=\"6\"  width=\"15\" height=\"2.5\"  />\n            <rect  x=\"0\" y=\"11\"  width=\"15\" height=\"2.5\"  />\n        </svg>\n      </div>\n\n      <div class=\"functional-tabs\" style=\"float: right\">\n      </div>\n\n      <div style=\"clear: both;\"></div>\n\n      <div class=\"content-placeholder\" >\n\n        <div style=\"display: block\" class=\"text-panel\" >\n          <div><b>Lattice constants</b>:\n            <div class=\"stats-fields latt-constants-field\" >\n            </div>\n          </div>\n          <div class=\"volume-field\"><b><span info-sys-data=\"cell-volume\">Volume</span></b> (&#197;<sup>3</sup>):\n            <div class=\"stats-fields volume-value\" > </div>\n          </div>\n          <div class=\"density-field\"><b>Density</b> :\n            <div >\n              <div class=\"stats-fields\" >\n                <span info-sys-data=\"mass-density\">Mass density</span> (kg/m<sup>3</sup>) =\n                <span class=\"mass-density-value\" ></span>\n              </div>\n              <div class=\"stats-fields\" >\n                <span info-sys-data=\"atomic-density\">Atomic density</span> (&#197;<sup>-3</sup>) =\n                <span class=\"atomic-density-value\" ></span>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <div style=\"display:none\" class=\"chart-panel\" >\n          <div class=\"charts-placeholder\" > </div>\n          <div class=\"charts-selector\" >\n\n          </div>\n        </div>\n\n      </div>\n    `;\n    this.chartTab = this.hostElement.querySelector('.chart-tab');\n    this.textTab = this.hostElement.querySelector('.text-tab');\n    this.functionalTabs = this.hostElement.querySelector('.functional-tabs');\n    this.chartPanel = this.hostElement.querySelector('.chart-panel');\n    this.textPanel = this.hostElement.querySelector('.text-panel');\n    this.lattConstantsField = this.hostElement.querySelector('.latt-constants-field');\n    this.volumeField = this.hostElement.querySelector('.volume-field');\n    this.volumeFieldValue = this.hostElement.querySelector('.volume-value');\n    this.densityField = this.hostElement.querySelector('.density-field');\n    this.massDensityValue = this.hostElement.querySelector('.mass-density-value');\n    this.atomicDensityValue = this.hostElement.querySelector('.atomic-density-value');\n\n    this.statsViewer = new StatsViewer();\n    let chartsPlaceholder = this.hostElement.querySelector('.charts-placeholder');\n    this.statsViewer.attach(chartsPlaceholder, 350, 200);\n\n    this.chartsSelector = this.hostElement.querySelector('.charts-selector');\n\n    this.chartTab.addEventListener( \"click\", e => {\n      this.chartTab.style.fill = '#777';\n      this.viewType = 'chart';\n      this.textTab.style.fill = '#c7c7c7';\n      this.chartPanel.style.display = 'block';\n      this.textPanel.style.display = 'none';\n    });\n\n    this.textTab.addEventListener( \"click\", e => {\n      this.textTab.style.fill = '#777';\n      this.viewType = 'text';\n      this.chartTab.style.fill = '#c7c7c7';\n      this.textPanel.style.display = 'block';\n      this.chartPanel.style.display = 'none';\n    });\n\n    this.functionalTabs.addEventListener( \"click\", e => {\n      if (e.target.className === 'tab'){\n        this.statsViewer.clear();\n        this.functionalTabs.querySelector('[data-tab=\"'+this.functional+'\"]')\n          .className = 'tab';\n        this.functional = e.target.getAttribute('data-tab');\n        this.functionalTabs.querySelector('[data-tab=\"'+this.functional+'\"]')\n          .className = 'tab-selected';\n        this._setData();\n      }\n    });\n\n    this.chartsSelector.addEventListener( \"click\", e => {\n      if (e.target.className.indexOf('quantity') === 0){\n        this.statsViewer.clear();\n        let quantity = e.target.getAttribute('data-quantity');\n\n        let quantityData = this.quantitiesMap.get(quantity);\n        let label = quantityData.label;\n        let stats = quantityData.stats;\n        this.statsViewer.drawPoints(stats.histogram, label, this.nBins);\n        this.chartsSelector.querySelector('.quantity-selected').className = 'quantity';\n        e.target.className = 'quantity-selected';\n      }\n    });\n\n  }\n\n  /**\n   * Called when a functional is selected.\n   */\n  _setData() {\n    let is2Dsystem = (DataStore.getMaterialData().material_type === '2D');\n    let isBulk = (DataStore.getMaterialData().material_type === 'bulk');\n    let functional = this.functional;\n    let calcs = Array.from(this.calcMapByFunctional.get(this.functional));\n    let matId = DataStore.getMaterialData().material_id;\n    let quantitiesMap = new Map();\n    quantitiesMap.set(\"lattice_a\", {label: 'a (Å)'});\n\n    if (is2Dsystem | isBulk) {\n      quantitiesMap.set(\"lattice_b\", {label: 'b (Å)'});\n      quantitiesMap.set(\"gamma\", {label: '&gamma'});\n    }\n    if (isBulk) {\n      quantitiesMap.set(\"cell_volume\", {label: 'Volume (ų)'});\n      quantitiesMap.set(\"atomic_density\", {label: 'Atomic density (Å⁻³)'});\n      quantitiesMap.set(\"mass_density\", {label: 'Mass density (kg/m³)'});\n      quantitiesMap.set(\"lattice_c\", {label: 'c ()'});\n      quantitiesMap.set(\"alpha\", {label: '&alpha'});\n      quantitiesMap.set(\"beta\", {label: '&beta'});\n    }\n\n    // Query statistics from the API\n    let query = JSON.stringify({\n      calculations: calcs,\n      properties: Array.from(quantitiesMap.keys()),\n      n_histogram_bins: this.nBins,\n    });\n    util.serverReqPOST(util.getMaterialStatsURL(matId), query, e3 => {\n      let results = JSON.parse(e3.target.response);\n\n      // Create formatted string for each stat\n      for (let quantity of quantitiesMap.keys()) {\n\n        let stats = results[quantity];\n\n        // Unit conversions\n        if (quantity == \"cell_volume\") {\n          stats.min *= 1e30;\n          stats.avg *= 1e30;\n          stats.max *= 1e30;\n          stats.histogram.values = stats.histogram.values.map(x => x*1e30);\n        } else if (quantity == \"atomic_density\") {\n          stats.min *= 1e-30;\n          stats.avg *= 1e-30;\n          stats.max *= 1e-30;\n          stats.histogram.values = stats.histogram.values.map(x => x*1e-30);\n        } else if (quantity.startsWith(\"lattice_\")) {\n          stats.min *= 1e10;\n          stats.avg *= 1e10;\n          stats.max *= 1e10;\n          stats.histogram.values = stats.histogram.values.map(x => x*1e10);\n        }\n        let label = quantitiesMap.get(quantity).label;\n        stats.equal = (stats.min === stats.max);\n        let lls = label.split(':');\n        stats.label = lls[0];\n        if (lls.length === 2) {\n          stats.units = lls[1];\n        } else {\n          stats.units = '';\n        }\n        let decimals = 3;\n        if (quantity === 'mass_density') decimals = 1;\n        let html;\n        if (quantity == \"alpha\" || quantity == \"beta\" || quantity == \"gamma\") {\n          html = util.rad2degree(stats.avg.toFixed(decimals));\n        } else {\n          html = stats.avg.toFixed(decimals)+\n            ' &nbsp; <span style=\"font-size: 0.9em\">['+stats.min.toFixed(decimals)\n            +' , '+stats.max.toFixed(decimals)+']</span>';\n        }\n\n        quantitiesMap.get(quantity).html = html;\n        quantitiesMap.get(quantity).stats = stats;\n      };\n\n      let lattCFieldHTML = ((is2Dsystem || isBulk) ?\n            `<div>b (&#197;) = ${quantitiesMap.get('lattice_b').html}</div>` : '');\n\n      lattCFieldHTML += (isBulk ?\n        `<div>c (&#197;) = ${quantitiesMap.get('lattice_c').html}</div>` : '');\n\n      // Construct angle field\n      let lattBetaGammaFieldHTML = (isBulk ?\n          `<div>&alpha; = ${quantitiesMap.get('alpha').html}</div>\n          <div>&beta; = ${quantitiesMap.get('beta').html}</div>` : '');\n      lattBetaGammaFieldHTML += ((is2Dsystem  || isBulk) ?\n          `<div>&gamma; = ${quantitiesMap.get('gamma').html}</div>` : '');\n\n      // Set text data\n      this.lattConstantsField.innerHTML = `\n        <div style=\"float: left; \">\n          <div>a (&#197;) = ${quantitiesMap.get('lattice_a').html}</div>\n          ${lattCFieldHTML}\n        </div>\n      <div style=\"float: left; padding-left: 40px;\">\n        ${lattBetaGammaFieldHTML}\n      </div>\n        <div style=\"clear: both;padding: 0\"></div>\n        `;\n\n      let chartSelectorHTML= `\n      <span class=\"quantity-selected\" data-quantity=\"lattice_a\">a</span>\n      `;\n\n      if (is2Dsystem || isBulk)\n        chartSelectorHTML += `<span class=\"quantity\" data-quantity=\"lattice_b\">b</span>`;\n      this.densityField.style.display = (isBulk ? 'block' : 'none');\n      this.volumeField.style.display = (isBulk ? 'block' : 'none');\n      if (isBulk) { // bulk type\n        this.volumeFieldValue.innerHTML = quantitiesMap.get('cell_volume').html;\n        this.massDensityValue.innerHTML = quantitiesMap.get('mass_density').html;\n        this.atomicDensityValue.innerHTML = quantitiesMap.get('atomic_density').html;\n        chartSelectorHTML += `\n          <span class=\"quantity\" data-quantity=\"lattice_c\">c</span>\n          <span class=\"quantity\" data-quantity=\"cell_volume\">volume</span>\n          <span class=\"quantity\" data-quantity=\"mass_density\">mass density</span>\n          <span class=\"quantity\" data-quantity=\"atomic_density\">atomic density</span>\n        `;\n      }\n\n      this.chartsSelector.innerHTML = chartSelectorHTML;\n      this.quantitiesMap = quantitiesMap;\n\n      // Display histogram\n      let hist = results.lattice_a.histogram;\n      this.statsViewer.drawPoints(hist, quantitiesMap.get(\"lattice_a\").label, this.nBins);\n    });\n  }\n\n  build(calcMapByFunctional) {\n    this.calcMapByFunctional = calcMapByFunctional;\n    this.graphTrigger = null;\n    this.statsViewer.clear();\n    this.unfoldedElement = null;\n    this.functionalQuantityMap = new Map();\n\n    // Create tabs for each functional\n    this.functionalTabs.innerHTML = \"\";\n    this.calcMapByFunctional.forEach( (calcs, functionalName) => {\n      this.functionalTabs.innerHTML +=\n        '<span class=\"tab\" data-tab=\"'+functionalName+'\">'+functionalName+'</span>';\n    });\n\n    // Preselect the first functional\n    let functionals = Array.from(this.calcMapByFunctional.keys());\n    if (this.functional === null || functionals.indexOf(this.functional) < 0)\n      this.functional = functionals[0]; // the first one is selected\n    this._setData();\n    this.functionalTabs.querySelector('[data-tab=\"'+this.functional+'\"]').className = 'tab-selected';\n\n    InfoSys.addToInfoSystem(this.hostElement);\n  }\n\n}\n\n\n// EXPORTS\nmodule.exports = StructureDetails;\n\n\n//# sourceURL=webpack:///./src/material-mod/StructureDetails.view.js?");
 
 /***/ }),
 
@@ -393,7 +393,7 @@ eval("\n/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apac
 /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
 
 "use strict";
-eval("\n\n/**\n * Copyright 2016-2019 Iker Hurtado, Georg Huhs\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n\n /*\n\n */\n\n\n\n\nlet util = __webpack_require__(/*! ../common/util.js */ \"./src/common/util.js\");\nlet InfoSys = __webpack_require__(/*! ../common/InfoSys.js */ \"./src/common/InfoSys.js\");\nlet AutocompleteMultiselectTextfield = __webpack_require__(/*! ./AutocompleteMultiselectTextfield.js */ \"./src/search-mod/AutocompleteMultiselectTextfield.js\");\n\n\nconst NOT_SELECTED_OPACITY = 0.2\n\nclass FilterPanel {\n\n  constructor() {\n    this.element = document.createElement('div');\n    this.element.setAttribute(\"id\",'filter-panel-placeholder');\n\n    this.fields = [];\n\n    let structureGroupBox = this.createPropsGroupBox('Structure')\n    this.element.append(structureGroupBox);\n\n    const systemTypeField = new CheckboxesField('System type', 'material_type', [\n      {value: 'bulk', text: 'Bulk'},\n      {value: '2D', text: '2D'}, \n      {value: '1D', text: '1D'}\n    ]);\n    this.fields.push(systemTypeField)\n    structureGroupBox.append(systemTypeField.element);  /// By looping*****\n\n    const crystalSystemField = new CheckboxesField('Crystal system', 'crystal_system', [\n      {value: 'cubic', text: 'Cubic'},\n      {value: 'hexagonal', text: 'Hexagonal'},\n      {value: 'trigonal', text: 'Trigonal'},\n      {value: 'tetragonal', text: 'Tetragonal'},\n      {value: 'orthorhombic', text: 'Orthorhombic'},\n      {value: 'monoclinic', text: 'Monoclinic'},\n      {value: 'triclinic', text: 'Triclinic'},\n    ]);\n    this.fields.push(crystalSystemField)\n    structureGroupBox.append(crystalSystemField.element); \n\n\n/*  Old version\n    const spaceGroupField = new SpaceGroupField();\n    this.fields.push(spaceGroupField)\n    structureGroupBox.append(spaceGroupField.element); \n    */\n   \n    const spaceGroupField = new TextField('Space group number', 'space_group_number');\n    this.fields.push(spaceGroupField)\n    structureGroupBox.append(spaceGroupField.element); \n\n\n    const structureTypeField = new AutocompleteField('Structure type', 'structure_type');\n    this.fields.push(structureTypeField)\n    structureGroupBox.append(structureTypeField.element);\n\n    // const structureTypeField = new AutocompleteField('Strukturbericht designation', \"strukturbericht\", 'strukturbericht_designation'));\n\n    let propertiesGroupBox = this.createPropsGroupBox('Properties')\n    this.element.append(propertiesGroupBox);\n\n\n    /* The mass density field is disabled for now\n    const massDensityField = new MassDensityField();\n    this.fields.push(massDensityField)\n    propertiesGroupBox.append(massDensityField.element); \n    */\n\n    const boolValueFields = new CheckboxesField('Results containing...', undefined, [\n      {value: 'Band structure', text: 'Band structure', id: 'has_band_structure'},\n      {value: 'DOS', text: 'DOS', id: 'has_dos'}, \n      {value: 'Thermal properties', text: 'Thermal properties', id: 'has_thermal_properties'}, \n    ]);  \n    this.fields.push(boolValueFields)\n    propertiesGroupBox.append(boolValueFields.element);  \n\n    // Method \n    let methodGroupBox = this.createPropsGroupBox('Method')\n    this.element.append(methodGroupBox);\n    const basisSetField = new AutocompleteField('Basis set', 'basis_set');\n    this.fields.push(basisSetField)\n    methodGroupBox.append(basisSetField.element);\n    const functionalTypeField = new AutocompleteField('Functional type', 'functional_type');\n    this.fields.push(functionalTypeField)\n    methodGroupBox.append(functionalTypeField.element);\n    const codeField = new AutocompleteField('Code', 'code_name');\n    this.fields.push(codeField);\n    methodGroupBox.append(codeField.element);\n\n    // Restricted search checkbox: cannot be set as innerHTML\n    const container = document.createElement('div');\n    container.className = \"filter-quantity-box\";\n    const a = document.createElement('div');\n    a.className = \"perm-tooltip search-option restricted-search-option\";\n    const b = document.createElement('input');\n    b.id = \"restricted-search\";\n    b.name = \"restricted-search\";\n    b.type = \"checkbox\";\n    const c = document.createElement('label');\n    c[\"for\"] = \"restricted-search\";\n    c.className = \"perm-tooltip\";\n    c.textContent = \"Restrict to individual calculations\";\n    const d = document.createElement('span');\n    d.className = \"tooltiptext\";\n    d.textContent = \"If selected, the query will return materials that have individual calculations simultaneously matching your methodology and properties criteria.\"\n    a.append(b);\n    a.append(c);\n    a.append(d);\n    container.append(a);\n    this.element.append(container);\n\n    InfoSys.addToInfoSystem(this.element);\n\n    // The value change event in fields is handled at container level (event delegation pattern) \n    this.element.addEventListener('change', e => {\n      if (this.addPropsChangeListener) this.addPropsChangeListener(this.getValues())\n    });\n\n/*  code for the MaxMinSlider component testing\n    this.testSlider = this.element.querySelector('.test-slider');\n    console.log(\"TAB: \",this.testSlider);\n    this.slider = new MaxMinSlider();\n    this.slider.setRange(0,10000);\n    this.testSlider.appendChild(this.slider.element);\n*/\n  }\n\n\n  createPropsGroupBox(title){\n    const element = document.createElement('div');\n    element.className = 'filter-section-box';\n    element.innerHTML = '<div class=\"filter-section-title\"><div>'+title+'</div></div>';\n    return element;\n  }\n\n\n  getValues(){\n\n    let filterMap = new Map();\n\n    this.fields.forEach( field => {\n      const values = field.getValues();\n      if (Array.isArray(values) && values.length > 0){\n        values.forEach( value => filterMap.set(value.fieldId, value.value))\n      } else if (values && values.value && values.value.length > 0) {\n        filterMap.set(values.fieldId, values.value);\n      }\n    });\n    return filterMap;\n  }\n\n\n  setPropsChangeListener(listener) {\n    this.addPropsChangeListener = listener;\n  }\n\n\n  showSelectedProps(show){\n\n    this.fields.forEach( field => {\n      field.highlightSelected(show)\n    })\n    /*\n    let selectedPropBox = this.element.querySelector('.selected-props-view')\n    let values = this.getValues()\n    let html = ''\n    values.forEach( (value, key) => {\n      html += ` <h3>${key}</h3> <p>${value}</p>\n      `\n    } )\n    selectedPropBox.innerHTML = html\n    selectedPropBox.style.display = (show ? '' : 'none') \n    this.element.querySelector('.regular-view').style.display = (show ? 'none' : '') \n    */\n  }\n\n\n}\n\n\nclass CheckboxesField{\n\n  constructor(name, commonId, valuesDesc ){\n\n    this.commonId = commonId;\n    this.element = document.createElement('div');\n    this.element.className = 'filter-quantity-box';\n    this.element.innerHTML = `<div class=\"field-title\">\n        <span info-sys-data=\"${commonId}\">${name}</span>\n      </div>`;\n\n    valuesDesc.forEach( valueDesc => {\n      let fieldId = commonId ? commonId : valueDesc.id; // commonId -> checkboxes related: only one field / no commonId -> every checkbox is and independent field\n      let infoSysValue = commonId ? (fieldId+'.value:'+valueDesc.value) : fieldId;\n      let valueElement = document.createElement('div');\n      valueElement.innerHTML = `\n          <input type=\"checkbox\" class=\"${fieldId}-field\" value=\"${valueDesc.value}\">\n          <span info-sys-data=\"${infoSysValue}\">${valueDesc.text}</span>\n      `;\n      this.element.append(valueElement);\n    });\n\n    this.checkboxes = this.element.querySelectorAll('input');\n  }\n\n  getValues(){\n\n    if (this.commonId){\n      let values = [];\n      this.checkboxes.forEach( checkbox => {\n        if (checkbox.checked)  values.push(checkbox.value);\n      });\n      return {fieldId: this.commonId, value: values};\n    }else{\n      let values = [];\n      this.checkboxes.forEach( checkbox => {\n        if (checkbox.checked) {\n          let s = checkbox.className;\n          values.push({fieldId: s.substring(0, s.indexOf('-field')), value: [true]});\n        }\n      });\n      return values;\n    }\n  }\n\n  highlightSelected(bool){\n\n    this.checkboxes.forEach( checkbox => {\n      if (checkbox.checked){\n        //checkbox.parentElement.style.backgroundColor = 'red'\n        checkbox.parentElement.style.opacity = ''//(bool ? '' : '')\n      }else{\n        checkbox.parentElement.style.opacity = (bool ? NOT_SELECTED_OPACITY : '')\n      } \n    });\n  }\n\n}\n\n\n\nclass TextField{\n\n  constructor(name, id){\n    this.fieldId = id;\n    this.element = document.createElement('div');\n    this.element.className = 'filter-quantity-box';\n    this.element.innerHTML = `\n      <div class=\"field-title\"> <span info-sys-data=\"${id}\">${name}</span></div>\n      <input type=\"text\" class=\"${id}-textfield\" style=\"\">\n    `;\n    this.input = this.element.querySelector('input');\n  }\n\n\n  getValues(){\n    let value = this.input.value;\n    return ( value.trim() === '' ? null : { fieldId: this.fieldId, value: [value] } );\n  }\n\n\n  highlightSelected(bool){\n    if (this.getValues() === null)\n      this.input.style.opacity = (bool ? NOT_SELECTED_OPACITY : '');\n  }\n}\n\n\n/* Not being used temporarily -> simple textfield instead \nclass SpaceGroupField{\n\n  constructor(){\n    this.element = document.createElement('div');\n    this.element.className = 'filter-quantity-box';\n    this.element.innerHTML = `\n      <div class=\"field-title\"> <span info-sys-data=\"space-group\">Space group</span></div>\n      <select id=\"space-group-dropdown-list\" disabled >\n        <option value=\"by-number\">by number</option>\n        <option value=\"by-symbol\">by short symbol</option>\n      </select>\n      <input type=\"text\" class=\"space-group-textfield\" style=\"width: 60px\">\n    `;\n    this.select = this.element.querySelector('select');\n    this.input = this.element.querySelector('input')\n  }\n\n\n  getValues(){\n    \n    let type = this.select.options[this.select.selectedIndex].value;\n    let propName = (type === 'by-number' ? 'space_group_number' \n      : 'space_group_international_short_symbol');\n\n    let value = this.input.value;\n    return ( value.trim() === '' ? null : { fieldId: propName, value: [value] } );\n  }\n\n  highlightSelected(bool){\n    if (this.getValues() === null){\n      this.select.style.opacity = (bool ? NOT_SELECTED_OPACITY : '')\n      this.input.style.opacity = (bool ? NOT_SELECTED_OPACITY : '')\n    }\n    \n  }\n}*/\n\n\nclass AutocompleteField{\n\n  constructor(name, id){\n    this.fieldId = id\n    this.element = document.createElement('div');\n    this.element.className = 'filter-quantity-box';\n    this.element.innerHTML = `<div class=\"field-title\">\n        <span info-sys-data=\"${id}\">${name}</span>\n      </div>`;\n\n\n    this.autocomplete = new AutocompleteMultiselectTextfield(id, 'Search and select options');\n    this.element.append(this.autocomplete.element)\n    \n    let r1 = util.serverReq(util.getSuggestionURL(this.fieldId), (e) => {\n      let names = JSON.parse(r1.response)[this.fieldId];\n      this.autocomplete.setAutocompleteList(names);\n    });\n    \n  }\n\n  getValues(){\n    const values = this.autocomplete.getValues();//getSelected();\n    return ( values.length === 0 ? null : { fieldId: this.fieldId, value: values } );\n  }\n\n  highlightSelected(bool){\n    if (this.getValues() === null) \n      this.autocomplete.element.style.opacity = (bool ? NOT_SELECTED_OPACITY : '')\n  }\n}\n\n\n/* Not being used \nclass MassDensityField{\n\n  constructor(){\n    this.element = document.createElement('div');\n    this.element.className = 'filter-quantity-box';\n    this.element.innerHTML = `\n      <div class=\"field-title\">\n        <span info-sys-data=\"mass-density\">Mass density</span> \n        <span style=\"font-weight: normal;\">(kg/m<sup>3</sup>)</span>\n      </div>\n      <div>\n        Min: <input type=\"text\" class=\"mass-density-min-field\">&nbsp;&nbsp;\n        Max: <input type=\"text\" class=\"mass-density-max-field\">\n      </div>\n    `;\n    this.inputs = this.element.querySelectorAll('input');\n  }\n\n  getValues(){\n    \n    let value = ':';\n    if (this.inputs[0].value.trim() !== ''){ // Min value\n      value = this.inputs[0].value+value;\n    }\n    if (this.inputs[1].value.trim() !== ''){ // Max value\n      value = value+this.inputs[1].value;\n    }\n    return ( value === ':' ? null : { fieldId: 'mass-density', value: value } );\n  }\n\n  highlightSelected(bool){\n    if (this.getValues() === null) \n      this.inputs[0].parentElement.style.opacity = (bool ? NOT_SELECTED_OPACITY : '')\n  }\n} */\n\n// EXPORTS\nmodule.exports = FilterPanel;\n\n\n\n/*  To be implemented in the future\n\nclass MaxMinSlider{\n\n  constructor(){\n\n    this.element = document.createElement('div');\n    this.element.innerHTML = `\n      <svg class=\"maxminslider\" xmlns=\"http://www.w3.org/2000/svg\" width=\"100px\" height=\"40px\"\n        viewBox=\"0 0 100 40\" >\n        <line class=\"slider-bar\" x1=\"10\" x2=\"90\" y1=\"30\" y2=\"30\" stroke=\"blue\"\n        stroke-width=\"4\"/>\n        <circle class=\"min-btn\" cx=\"10\" cy=\"30\" r=\"6\" fill=\"black\"/>\n        <text class=\"min-text maxminslider-text\" x=\"10\" y=\"10\" text-anchor=\"start\"></text>\n        <circle class=\"max-btn\" cx=\"90\" cy=\"30\" r=\"6\" fill=\"black\"/>\n        <text class=\"max-text maxminslider-text\" x=\"90\" y=\"10\" text-anchor=\"end\"></text>\n      </svg>\n    `;\n\n    //this.bar = this.element.querySelector('.slider-bar');\n    this.svg = this.element.querySelector('svg');\n    this.minButton = this.element.querySelector('.min-btn');\n    this.minText = this.element.querySelector('.min-text');\n    this.maxButton = this.element.querySelector('.max-btn');\n    this.maxText = this.element.querySelector('.max-text');\n\n    this.BUTTON_R = 6;\n\n    this.minButtonDown = false;\n    this.minButtonInitX = null;\n\n    this.MIN_BUTTON_INIT_X = 10;\n    this.minX = 0;\n\n    this.maxButtonDown = false;\n    this.maxButtonInitX = null;\n    this.MAX_VALUE = 80;//this.MAX_BUTTON_INIT_X = 90;\n    this.maxX = this.MAX_VALUE;\n\n    console.log('minButton', this.minButton.getBoundingClientRect());\n\n    this._events();\n  }\n\n\n  _events() {\n\n    this.minButton.addEventListener( \"mousedown\", e => this.minButtonDown = true );\n    this.minButton.addEventListener( \"mouseup\", e => this.minButtonDown = false );\n    this.minButton.addEventListener( \"mouseleave\", e => this.minButtonDown = false );\n\n    this.minButton.addEventListener( \"mousemove\", e => {\n      //e.preventDefault();\n      if (this.minButtonInitX === null){\n        //this.minButtonInitX = this.svg.getBoundingClientRect().left;\n        this.minButtonInitX = this.minButton.getBoundingClientRect().left+this.BUTTON_R;//\n        //console.log('left', this.minButtonInitX);\n      }\n\n      if (this.minButtonDown){\n        this.minX  = e.clientX-this.minButtonInitX ;\n        if (this.minX > 0 && this.minX < this.maxX-this.BUTTON_R){\n          this.minButton.setAttribute('cx', this.MIN_BUTTON_INIT_X + this.minX);\n          this.minText.textContent = this.minX*this.factor-250;\n        }\n\n      }\n    });\n\n\n    this.maxButton.addEventListener( \"mousedown\", e => this.maxButtonDown = true );\n    this.maxButton.addEventListener( \"mouseup\", e => this.maxButtonDown = false );\n    this.maxButton.addEventListener( \"mouseleave\", e => this.maxButtonDown = false );\n\n    this.maxButton.addEventListener( \"mousemove\", e => {\n      //e.preventDefault();\n\n      if (this.maxButtonInitX === null)\n        this.maxButtonInitX = this.maxButton.getBoundingClientRect().left+this.BUTTON_R;//\n\n      if (this.maxButtonDown){\n\n        this.maxX  = e.clientX - this.minButtonInitX;\n        //console.log('maxButton', e.clientX, this.maxButtonInitX, this.maxX);\n        if (this.maxX < this.MAX_VALUE  && this.minX+this.BUTTON_R < this.maxX){\n          this.maxButton.setAttribute('cx', this.MIN_BUTTON_INIT_X + this.maxX);\n          this.maxText.textContent = this.maxX*this.factor;\n        }\n\n      }\n\n    });\n\n\n  }\n\n\n  setRange(min, max){\n    this.factor = (max-min)/80;\n  }\n\n}\n\n*/\n\n\n//# sourceURL=webpack:///./src/search-mod/FilterPanel.view.js?");
+eval("/**\n * Copyright 2016-2019 Iker Hurtado, Georg Huhs\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n\n\nlet util = __webpack_require__(/*! ../common/util.js */ \"./src/common/util.js\");\nlet InfoSys = __webpack_require__(/*! ../common/InfoSys.js */ \"./src/common/InfoSys.js\");\nlet AutocompleteMultiselectTextfield = __webpack_require__(/*! ./AutocompleteMultiselectTextfield.js */ \"./src/search-mod/AutocompleteMultiselectTextfield.js\");\n\n\nconst NOT_SELECTED_OPACITY = 0.2\n\nclass FilterPanel {\n\n  constructor() {\n    this.element = document.createElement('div');\n    this.element.setAttribute(\"id\",'filter-panel-placeholder');\n\n    this.fields = [];\n\n    let structureGroupBox = this.createPropsGroupBox('Structure')\n    this.element.append(structureGroupBox);\n\n    const systemTypeField = new CheckboxesField('System type', 'material_type', [\n      {value: 'bulk', text: 'Bulk'},\n      {value: '2D', text: '2D'}, \n      {value: '1D', text: '1D'}\n    ]);\n    this.fields.push(systemTypeField)\n    structureGroupBox.append(systemTypeField.element);  /// By looping*****\n\n    const crystalSystemField = new CheckboxesField('Crystal system', 'crystal_system', [\n      {value: 'cubic', text: 'Cubic'},\n      {value: 'hexagonal', text: 'Hexagonal'},\n      {value: 'trigonal', text: 'Trigonal'},\n      {value: 'tetragonal', text: 'Tetragonal'},\n      {value: 'orthorhombic', text: 'Orthorhombic'},\n      {value: 'monoclinic', text: 'Monoclinic'},\n      {value: 'triclinic', text: 'Triclinic'},\n    ]);\n    this.fields.push(crystalSystemField)\n    structureGroupBox.append(crystalSystemField.element); \n\n\n/*  Old version\n    const spaceGroupField = new SpaceGroupField();\n    this.fields.push(spaceGroupField)\n    structureGroupBox.append(spaceGroupField.element); \n    */\n   \n    const spaceGroupField = new TextField('Space group number', 'space_group_number');\n    this.fields.push(spaceGroupField)\n    structureGroupBox.append(spaceGroupField.element); \n\n\n    const structureTypeField = new AutocompleteField('Structure type', 'structure_type');\n    this.fields.push(structureTypeField)\n    structureGroupBox.append(structureTypeField.element);\n\n    // const structureTypeField = new AutocompleteField('Strukturbericht designation', \"strukturbericht\", 'strukturbericht_designation'));\n\n    let propertiesGroupBox = this.createPropsGroupBox('Properties')\n    this.element.append(propertiesGroupBox);\n\n\n    /* The mass density field is disabled for now\n    const massDensityField = new MassDensityField();\n    this.fields.push(massDensityField)\n    propertiesGroupBox.append(massDensityField.element); \n    */\n\n    const boolValueFields = new CheckboxesField('Results containing...', undefined, [\n      {value: 'Band structure', text: 'Band structure', id: 'has_band_structure'},\n      {value: 'DOS', text: 'DOS', id: 'has_dos'}, \n      {value: 'Thermal properties', text: 'Thermal properties', id: 'has_thermal_properties'}, \n    ]);  \n    this.fields.push(boolValueFields)\n    propertiesGroupBox.append(boolValueFields.element);  \n\n    // Method \n    let methodGroupBox = this.createPropsGroupBox('Method')\n    this.element.append(methodGroupBox);\n    const basisSetField = new AutocompleteField('Basis set', 'basis_set');\n    this.fields.push(basisSetField)\n    methodGroupBox.append(basisSetField.element);\n    const functionalTypeField = new AutocompleteField('Functional type', 'functional_type');\n    this.fields.push(functionalTypeField)\n    methodGroupBox.append(functionalTypeField.element);\n    const codeField = new AutocompleteField('Code', 'code_name');\n    this.fields.push(codeField);\n    methodGroupBox.append(codeField.element);\n\n    // Restricted search checkbox: cannot be set as innerHTML\n    const container = document.createElement('div');\n    container.className = \"filter-quantity-box\";\n    const a = document.createElement('div');\n    a.className = \"perm-tooltip search-option restricted-search-option\";\n    const b = document.createElement('input');\n    b.id = \"restricted-search\";\n    b.name = \"restricted-search\";\n    b.type = \"checkbox\";\n    const c = document.createElement('label');\n    c[\"for\"] = \"restricted-search\";\n    c.className = \"perm-tooltip\";\n    c.textContent = \"Restrict to individual calculations\";\n    const d = document.createElement('span');\n    d.className = \"tooltiptext\";\n    d.textContent = \"If selected, the query will return materials that have individual calculations simultaneously matching your methodology and properties criteria.\"\n    a.append(b);\n    a.append(c);\n    a.append(d);\n    container.append(a);\n    this.element.append(container);\n\n    InfoSys.addToInfoSystem(this.element);\n\n    // The value change event in fields is handled at container level (event delegation pattern) \n    this.element.addEventListener('change', e => {\n      if (this.addPropsChangeListener) this.addPropsChangeListener(this.getValues())\n    });\n\n/*  code for the MaxMinSlider component testing\n    this.testSlider = this.element.querySelector('.test-slider');\n    console.log(\"TAB: \",this.testSlider);\n    this.slider = new MaxMinSlider();\n    this.slider.setRange(0,10000);\n    this.testSlider.appendChild(this.slider.element);\n*/\n  }\n\n\n  createPropsGroupBox(title){\n    const element = document.createElement('div');\n    element.className = 'filter-section-box';\n    element.innerHTML = '<div class=\"filter-section-title\"><div>'+title+'</div></div>';\n    return element;\n  }\n\n\n  getValues(){\n\n    let filterMap = new Map();\n\n    this.fields.forEach( field => {\n      const values = field.getValues();\n      if (Array.isArray(values) && values.length > 0){\n        values.forEach( value => filterMap.set(value.fieldId, value.value))\n      } else if (values && values.value && values.value.length > 0) {\n        filterMap.set(values.fieldId, values.value);\n      }\n    });\n    return filterMap;\n  }\n\n\n  setPropsChangeListener(listener) {\n    this.addPropsChangeListener = listener;\n  }\n\n\n  showSelectedProps(show){\n\n    this.fields.forEach( field => {\n      field.highlightSelected(show)\n    })\n    /*\n    let selectedPropBox = this.element.querySelector('.selected-props-view')\n    let values = this.getValues()\n    let html = ''\n    values.forEach( (value, key) => {\n      html += ` <h3>${key}</h3> <p>${value}</p>\n      `\n    } )\n    selectedPropBox.innerHTML = html\n    selectedPropBox.style.display = (show ? '' : 'none') \n    this.element.querySelector('.regular-view').style.display = (show ? 'none' : '') \n    */\n  }\n\n\n}\n\n\nclass CheckboxesField{\n\n  constructor(name, commonId, valuesDesc ){\n\n    this.commonId = commonId;\n    this.element = document.createElement('div');\n    this.element.className = 'filter-quantity-box';\n    this.element.innerHTML = `<div class=\"field-title\">\n        <span info-sys-data=\"${commonId}\">${name}</span>\n      </div>`;\n\n    valuesDesc.forEach( valueDesc => {\n      let fieldId = commonId ? commonId : valueDesc.id; // commonId -> checkboxes related: only one field / no commonId -> every checkbox is and independent field\n      let infoSysValue = commonId ? (fieldId+'.value:'+valueDesc.value) : fieldId;\n      let valueElement = document.createElement('div');\n      valueElement.innerHTML = `\n          <input type=\"checkbox\" class=\"${fieldId}-field\" value=\"${valueDesc.value}\">\n          <span info-sys-data=\"${infoSysValue}\">${valueDesc.text}</span>\n      `;\n      this.element.append(valueElement);\n    });\n\n    this.checkboxes = this.element.querySelectorAll('input');\n  }\n\n  getValues(){\n\n    if (this.commonId){\n      let values = [];\n      this.checkboxes.forEach( checkbox => {\n        if (checkbox.checked)  values.push(checkbox.value);\n      });\n      return {fieldId: this.commonId, value: values};\n    }else{\n      let values = [];\n      this.checkboxes.forEach( checkbox => {\n        if (checkbox.checked) {\n          let s = checkbox.className;\n          values.push({fieldId: s.substring(0, s.indexOf('-field')), value: [true]});\n        }\n      });\n      return values;\n    }\n  }\n\n  highlightSelected(bool){\n\n    this.checkboxes.forEach( checkbox => {\n      if (checkbox.checked){\n        checkbox.parentElement.style.opacity = '';\n      } else {\n        checkbox.parentElement.style.opacity = (bool ? NOT_SELECTED_OPACITY : '');\n      } \n    });\n  }\n\n}\n\n\n\nclass TextField {\n\n  constructor(name, id){\n    this.fieldId = id;\n    this.element = document.createElement('div');\n    this.element.className = 'filter-quantity-box';\n    this.element.innerHTML = `\n      <div class=\"field-title\"> <span info-sys-data=\"${id}\">${name}</span></div>\n      <input type=\"text\" class=\"${id}-textfield\" style=\"\">\n    `;\n    this.input = this.element.querySelector('input');\n  }\n\n\n  getValues(){\n    let value = this.input.value;\n    return ( value.trim() === '' ? null : { fieldId: this.fieldId, value: [value] } );\n  }\n\n\n  highlightSelected(bool){\n    if (this.getValues() === null)\n      this.input.style.opacity = (bool ? NOT_SELECTED_OPACITY : '');\n  }\n}\n\n\n/* Not being used temporarily -> simple textfield instead \nclass SpaceGroupField{\n\n  constructor(){\n    this.element = document.createElement('div');\n    this.element.className = 'filter-quantity-box';\n    this.element.innerHTML = `\n      <div class=\"field-title\"> <span info-sys-data=\"space-group\">Space group</span></div>\n      <select id=\"space-group-dropdown-list\" disabled >\n        <option value=\"by-number\">by number</option>\n        <option value=\"by-symbol\">by short symbol</option>\n      </select>\n      <input type=\"text\" class=\"space-group-textfield\" style=\"width: 60px\">\n    `;\n    this.select = this.element.querySelector('select');\n    this.input = this.element.querySelector('input')\n  }\n\n\n  getValues(){\n    \n    let type = this.select.options[this.select.selectedIndex].value;\n    let propName = (type === 'by-number' ? 'space_group_number' \n      : 'space_group_international_short_symbol');\n\n    let value = this.input.value;\n    return ( value.trim() === '' ? null : { fieldId: propName, value: [value] } );\n  }\n\n  highlightSelected(bool){\n    if (this.getValues() === null){\n      this.select.style.opacity = (bool ? NOT_SELECTED_OPACITY : '')\n      this.input.style.opacity = (bool ? NOT_SELECTED_OPACITY : '')\n    }\n    \n  }\n}*/\n\n\nclass AutocompleteField{\n\n  constructor(name, id){\n    this.fieldId = id\n    this.element = document.createElement('div');\n    this.element.className = 'filter-quantity-box';\n    this.element.innerHTML = `<div class=\"field-title\">\n        <span info-sys-data=\"${id}\">${name}</span>\n      </div>`;\n\n\n    this.autocomplete = new AutocompleteMultiselectTextfield(id, 'Search and select options');\n    this.element.append(this.autocomplete.element)\n    \n    let r1 = util.serverReq(util.getSuggestionURL(this.fieldId), (e) => {\n      let names = JSON.parse(r1.response)[this.fieldId];\n      this.autocomplete.setAutocompleteList(names);\n    });\n    \n  }\n\n  getValues(){\n    const values = this.autocomplete.getValues();//getSelected();\n    return ( values.length === 0 ? null : { fieldId: this.fieldId, value: values } );\n  }\n\n  highlightSelected(bool){\n    if (this.getValues() === null) \n      this.autocomplete.element.style.opacity = (bool ? NOT_SELECTED_OPACITY : '')\n  }\n}\n\n\n/* Not being used \nclass MassDensityField{\n\n  constructor(){\n    this.element = document.createElement('div');\n    this.element.className = 'filter-quantity-box';\n    this.element.innerHTML = `\n      <div class=\"field-title\">\n        <span info-sys-data=\"mass-density\">Mass density</span> \n        <span style=\"font-weight: normal;\">(kg/m<sup>3</sup>)</span>\n      </div>\n      <div>\n        Min: <input type=\"text\" class=\"mass-density-min-field\">&nbsp;&nbsp;\n        Max: <input type=\"text\" class=\"mass-density-max-field\">\n      </div>\n    `;\n    this.inputs = this.element.querySelectorAll('input');\n  }\n\n  getValues(){\n    \n    let value = ':';\n    if (this.inputs[0].value.trim() !== ''){ // Min value\n      value = this.inputs[0].value+value;\n    }\n    if (this.inputs[1].value.trim() !== ''){ // Max value\n      value = value+this.inputs[1].value;\n    }\n    return ( value === ':' ? null : { fieldId: 'mass-density', value: value } );\n  }\n\n  highlightSelected(bool){\n    if (this.getValues() === null) \n      this.inputs[0].parentElement.style.opacity = (bool ? NOT_SELECTED_OPACITY : '')\n  }\n} */\n\n// EXPORTS\nmodule.exports = FilterPanel;\n\n\n\n/*  To be implemented in the future\n\nclass MaxMinSlider{\n\n  constructor(){\n\n    this.element = document.createElement('div');\n    this.element.innerHTML = `\n      <svg class=\"maxminslider\" xmlns=\"http://www.w3.org/2000/svg\" width=\"100px\" height=\"40px\"\n        viewBox=\"0 0 100 40\" >\n        <line class=\"slider-bar\" x1=\"10\" x2=\"90\" y1=\"30\" y2=\"30\" stroke=\"blue\"\n        stroke-width=\"4\"/>\n        <circle class=\"min-btn\" cx=\"10\" cy=\"30\" r=\"6\" fill=\"black\"/>\n        <text class=\"min-text maxminslider-text\" x=\"10\" y=\"10\" text-anchor=\"start\"></text>\n        <circle class=\"max-btn\" cx=\"90\" cy=\"30\" r=\"6\" fill=\"black\"/>\n        <text class=\"max-text maxminslider-text\" x=\"90\" y=\"10\" text-anchor=\"end\"></text>\n      </svg>\n    `;\n\n    //this.bar = this.element.querySelector('.slider-bar');\n    this.svg = this.element.querySelector('svg');\n    this.minButton = this.element.querySelector('.min-btn');\n    this.minText = this.element.querySelector('.min-text');\n    this.maxButton = this.element.querySelector('.max-btn');\n    this.maxText = this.element.querySelector('.max-text');\n\n    this.BUTTON_R = 6;\n\n    this.minButtonDown = false;\n    this.minButtonInitX = null;\n\n    this.MIN_BUTTON_INIT_X = 10;\n    this.minX = 0;\n\n    this.maxButtonDown = false;\n    this.maxButtonInitX = null;\n    this.MAX_VALUE = 80;//this.MAX_BUTTON_INIT_X = 90;\n    this.maxX = this.MAX_VALUE;\n\n    console.log('minButton', this.minButton.getBoundingClientRect());\n\n    this._events();\n  }\n\n\n  _events() {\n\n    this.minButton.addEventListener( \"mousedown\", e => this.minButtonDown = true );\n    this.minButton.addEventListener( \"mouseup\", e => this.minButtonDown = false );\n    this.minButton.addEventListener( \"mouseleave\", e => this.minButtonDown = false );\n\n    this.minButton.addEventListener( \"mousemove\", e => {\n      //e.preventDefault();\n      if (this.minButtonInitX === null){\n        //this.minButtonInitX = this.svg.getBoundingClientRect().left;\n        this.minButtonInitX = this.minButton.getBoundingClientRect().left+this.BUTTON_R;//\n        //console.log('left', this.minButtonInitX);\n      }\n\n      if (this.minButtonDown){\n        this.minX  = e.clientX-this.minButtonInitX ;\n        if (this.minX > 0 && this.minX < this.maxX-this.BUTTON_R){\n          this.minButton.setAttribute('cx', this.MIN_BUTTON_INIT_X + this.minX);\n          this.minText.textContent = this.minX*this.factor-250;\n        }\n\n      }\n    });\n\n\n    this.maxButton.addEventListener( \"mousedown\", e => this.maxButtonDown = true );\n    this.maxButton.addEventListener( \"mouseup\", e => this.maxButtonDown = false );\n    this.maxButton.addEventListener( \"mouseleave\", e => this.maxButtonDown = false );\n\n    this.maxButton.addEventListener( \"mousemove\", e => {\n      //e.preventDefault();\n\n      if (this.maxButtonInitX === null)\n        this.maxButtonInitX = this.maxButton.getBoundingClientRect().left+this.BUTTON_R;//\n\n      if (this.maxButtonDown){\n\n        this.maxX  = e.clientX - this.minButtonInitX;\n        //console.log('maxButton', e.clientX, this.maxButtonInitX, this.maxX);\n        if (this.maxX < this.MAX_VALUE  && this.minX+this.BUTTON_R < this.maxX){\n          this.maxButton.setAttribute('cx', this.MIN_BUTTON_INIT_X + this.maxX);\n          this.maxText.textContent = this.maxX*this.factor;\n        }\n\n      }\n\n    });\n\n\n  }\n\n  setRange(min, max){\n    this.factor = (max-min)/80;\n  }\n\n}\n\n*/\n\n\n//# sourceURL=webpack:///./src/search-mod/FilterPanel.view.js?");
 
 /***/ }),
 
diff --git a/client/infosys.json b/client/infosys.json
index 08a40fcf..82e0502c 100644
--- a/client/infosys.json
+++ b/client/infosys.json
@@ -22,7 +22,7 @@
         "comment": "not required",
         "text": "Basis functions that are used to solve the Kohn-Sham equation."
     },
-    "basis set type": {
+    "basis_set": {
         "comment": "links to defining pages for every possible entry.",
         "link": "https://en.wikipedia.org/wiki/Basis_set_(chemistry)",
         "text": "Representation of Kohn\u2013Sham states.",
@@ -158,7 +158,7 @@
         "comment": "explaining that this is the volume of the primitive unit cell",
         "text": "Volume of the primitive unit cell."
     },
-    "code name": {
+    "code_name": {
         "comment": "askhl: Program names about which I am not sure about are marked with leading question mark.  Present names are those that are explicitly used e.g. as fixedStartValues in parsers (obtained from grep).",
         "link": "https://en.wikipedia.org/wiki/List_of_quantum_chemistry_and_solid-state_physics_software",
         "text": "Name of scientific software (code) used for the calculation.",
@@ -305,7 +305,7 @@
             }
         }
     },
-    "crystal system": {
+    "crystal_system": {
         "comment": "to explaining page for every crystal system (wikipedia has pages for crystal systems, but hexagonal and trigonal are treated on the same page, so two links go to that page on purpose.  --askhl)",
         "link": "https://en.wikipedia.org/wiki/Crystal_system",
         "values": {
@@ -416,7 +416,7 @@
             "num": "space group"
         }
     },
-    "functional type": {
+    "functional_type": {
         "comment": "general explanation and link to defining or explaining page for every functional type",
         "text": "Type of exchange\u2013correlation functional.",
         "values": {
@@ -474,11 +474,11 @@
             }
         }
     },
-    "has band structure": {
+    "has_band_structure": {
         "comment": "can be shown in the header as general explanation for all calculations",
         "text": "Search for calculations that contain an electronic band structure."
     },
-    "has dos": {
+    "has_dos": {
         "comment": "can be shown in the header as general explanation for all calculations",
         "text": "Search for calculations that contain a density of states."
     },
@@ -486,7 +486,7 @@
         "comment": "can be shown in the header as general explanation for all calculations",
         "text": "Search for calculations that contain a fermi surface."
     },
-    "has thermal properties": {
+    "has_thermal_properties": {
         "comment": "can be shown in the header as general explanation for all calculations",
         "text": "Search for calculations that contain thermal properties."
     },
@@ -604,7 +604,7 @@
         "comment": "",
         "text": "Parameter specifying the shape of the distribution for the given smearing kind."
     },
-    "space group": {
+    "space_group_number": {
         "comment": "general explanation and link to explaining page for every space group.",
         "link": "https://en.wikipedia.org/wiki/Space_group",
         "text": "The space group is defined by the translational symmetry of a crystal, together with its point symmetries.",
@@ -619,11 +619,18 @@
     "specific heat cv": {
         "text": "Temperature dependence of the heat capacity per unit cell at constant volume."
     },
-    "structure type": {
+    "structure_type": {
         "comment": "general explanation and link to explaining pages for every structure type (will fix this once the possible values of this are known.  --askhl)",
         "text": "Classification according to known structure types."
     },
-    "system type": {
+    "structure_prototype": {
+        "text": "Formula for the prototypical material having this structure."
+    },
+    "strukturbericht": {
+        "text": "Classification of the material according to the historically grown 'strukturbericht'.",
+        "link": "https://en.wikipedia.org/wiki/Strukturbericht_designation"
+    },
+    "material_type": {
         "comment": "explain how every structure type is defined in our system (need information about what system type can be.  Also this may not make so much sense while we only have bulk. --askhl)",
         "text": "Classification of materials into different high-level categories, based on their atomic configurations.",
         "values": {
diff --git a/client/src/common/Router.js b/client/src/common/Router.js
index c51e736d..d40f2ccb 100644
--- a/client/src/common/Router.js
+++ b/client/src/common/Router.js
@@ -75,6 +75,8 @@ function route() {
   else command = hashPath;
 
   if (routes.has(command)) {
+    // When entering a new page, reset the spinner.
+    LoadingPopup.reset();
     routes.get(command)(param, subparam);
   }
 };
diff --git a/client/src/material-mod/Overview.view.js b/client/src/material-mod/Overview.view.js
index 834a0f65..254a0667 100644
--- a/client/src/material-mod/Overview.view.js
+++ b/client/src/material-mod/Overview.view.js
@@ -71,11 +71,11 @@ class Overview {
             <span class="material-type-field" ></span>
           </div>
           <div class="space-group-field" style="display: none">
-            <b><span info-sys-data="space-group">Space group</span></b>:
+            <b><span info-sys-data="space_group_number">Space group</span></b>:
             <span class="space-group-value" ></span>
           </div>
           <div class="structure-type-field" style="display: none">
-            <b><span info-sys-data="structure-type">Structure type</span></b>:
+            <b><span info-sys-data="structure_type">Structure type</span></b>:
             <span class="structure-type-value" ></span>
           </div>
         </div>
@@ -109,11 +109,11 @@ class Overview {
           <div class="info-fields-label" > Available calculations </div>
 
           <div style="float: left; width: 45%" >
-            <b><span info-sys-data="functional-type">Functional</span></b>
+            <b><span info-sys-data="functional_type">Functional</span></b>
             <div class="functional-field" > </div>
           </div>
           <div style="float: right; width: 45%" >
-            <b><span info-sys-data="code-name">Code</span></b>
+            <b><span info-sys-data="code_name">Code</span></b>
             <div class="code-field"> </div>
            </div>
            <div style="clear: both;"></div>
@@ -322,7 +322,7 @@ class Overview {
       this.spaceGroupValue.textContent = data.space_group_number+
         ' ('+data.space_group_international_short_symbol+')';
       InfoSys.addElementToInfoSystem(this.spaceGroupValue,
-        'space-group.value:'+data.space_group_number);
+        'space_group_number.value:' + data.space_group_number);
     }
 
     if (this.similarityFinder) {
@@ -426,7 +426,7 @@ class Overview {
     let container = document.createElement("div");
     functionalMap.forEach((number, functional) => {
       let span = document.createElement("span");
-      span.setAttribute("info-sys-data", "functional-type.value:" + util.getDefault(functional));
+      span.setAttribute("info-sys-data", "functional_type.value:" + util.getDefault(functional));
       span.textContent = number + ' ' + util.getDefault(functional);
       container.appendChild(span);
       let linebreak = document.createElement("br");
@@ -440,7 +440,7 @@ class Overview {
     let container2 = document.createElement("div");
     codeMap.forEach((number, codeName) => {
       let span = document.createElement("span");
-      span.setAttribute("info-sys-data", "code-name.value:" + codeName);
+      span.setAttribute("info-sys-data", "code_name.value:" + codeName);
       span.textContent = number + ' ' + codeName;
       container2.appendChild(span);
       let linebreak = document.createElement("br");
diff --git a/client/src/material-mod/StructureDetails.view.js b/client/src/material-mod/StructureDetails.view.js
index 180915cd..60df29fd 100644
--- a/client/src/material-mod/StructureDetails.view.js
+++ b/client/src/material-mod/StructureDetails.view.js
@@ -62,11 +62,11 @@ class StructureDetails extends DetailsViewBase {
                 <span class="struct-field" ></span>
               </div>
               <div class="structure-type-field" style="display: none">
-                <b><span info-sys-data="structure-type">Structure type</span></b>:
+                <b><span info-sys-data="structure_type">Structure type</span></b>:
                 <span class="structure-type-value" ></span>
               </div>
               <div class="structure-prototype-field" style="display: none">
-                <b><span info-sys-data="structure-prototype">Structure prototype</span></b>:
+                <b><span info-sys-data="structure_prototype">Structure prototype</span></b>:
                 <span class="structure-prototype-value" ></span>
               </div>
               <div class="strukturbericht-field" style="display: none">
@@ -81,11 +81,11 @@ class StructureDetails extends DetailsViewBase {
                 style="flex-basis: 70%; border-right: 1px solid #E4E4E4; ">
 
                 <div>
-                  <b><span info-sys-data="crystal-system">Lattice</span></b>:
+                  <b><span info-sys-data="crystal_system">Lattice</span></b>:
                   <span class="lattice-value" ></span>
                 </div>
                 <div>
-                  <b><span info-sys-data="space-group">Space group</span></b>:
+                  <b><span info-sys-data="space_group_number">Space group</span></b>:
                   <span class="space-group-value" ></span>
                 </div>
                 <div>
@@ -248,9 +248,9 @@ class StructureDetails extends DetailsViewBase {
     }
 
     InfoSys.addElementToInfoSystem(this.spaceGroupValue,
-      'space-group.value:'+data.space_group_number);
+      'space_group_number.value:'+data.space_group_number);
     InfoSys.addElementToInfoSystem(this.latticeValue,
-      'crystal-system.value:'+data.crystal_system);
+      'crystal_system.value:'+data.crystal_system);
     InfoSys.addElementToInfoSystem(this.pointGroupValue,
       'point-group.value:'+data.point_group);
     //InfoSys.addElementToInfoSystem(this.wyckoffValue, 'wyckoff-position-population.value:'+);
diff --git a/client/src/search-mod/FilterPanel.view.js b/client/src/search-mod/FilterPanel.view.js
index 74204e46..8f782b80 100644
--- a/client/src/search-mod/FilterPanel.view.js
+++ b/client/src/search-mod/FilterPanel.view.js
@@ -1,5 +1,3 @@
-
-
 /**
  * Copyright 2016-2019 Iker Hurtado, Georg Huhs
  *
@@ -17,12 +15,6 @@
  *
  */
 
-
- /*
-
- */
-
-
 "use strict";
 
 let util = require('../common/util.js');
@@ -252,10 +244,9 @@ class CheckboxesField{
 
     this.checkboxes.forEach( checkbox => {
       if (checkbox.checked){
-        //checkbox.parentElement.style.backgroundColor = 'red'
-        checkbox.parentElement.style.opacity = ''//(bool ? '' : '')
-      }else{
-        checkbox.parentElement.style.opacity = (bool ? NOT_SELECTED_OPACITY : '')
+        checkbox.parentElement.style.opacity = '';
+      } else {
+        checkbox.parentElement.style.opacity = (bool ? NOT_SELECTED_OPACITY : '');
       } 
     });
   }
@@ -264,7 +255,7 @@ class CheckboxesField{
 
 
 
-class TextField{
+class TextField {
 
   constructor(name, id){
     this.fieldId = id;
@@ -501,7 +492,6 @@ class MaxMinSlider{
 
   }
 
-
   setRange(min, max){
     this.factor = (max-min)/80;
   }
-- 
GitLab