const interfaceWrapper = document.getElementById("interface-wrapper"); const moduleWrapper = document.createElement("div"); moduleWrapper.setAttribute("id", "module-wrapper"); interfaceWrapper.appendChild(moduleWrapper); const isMobile = new RegExp(/Android|webOS|iPhone|iPad|BlackBerry|Windows Phone|Opera Mini|IEMobile|Mobile/).test(navigator.userAgent); const styles = ["light", "medium", "heavy"]; let currentStyle = styles[0]; if (localStorage.style) { currentStyle = styles[localStorage.style]; } else { localStorage.style = "0"; } const modules = []; //GENERAL FUNCTIONS function loadSVG(path, callback) { let xhr = new XMLHttpRequest(); xhr.open("GET", path, true); // Following line is just to be on the safe side; // not needed if your server delivers SVG with correct MIME type xhr.overrideMimeType("image/svg+xml"); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status === 200) { // Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode callback(xhr.responseXML.documentElement); } }; xhr.send(); } function createModule(titleText) { let div = document.createElement("div"); div.classList = ["module module-out"]; let title = document.createElement("h2"); title.innerHTML = titleText; div.appendChild(title); modules.push(div); moduleWrapper.appendChild(div); return div; } //STYLE SPECIFICS GENERATION function createToggleCheckbox(scope, parent, config) { let wrapper = document.createElement("div"); wrapper.classList = "module-row"; let header = document.createElement("h4"); header.style = "width: fit-content;position: absolute;right: 50%;"; header.innerHTML = config.name; let container = document.createElement("label"); container.classList = "checkbox-container"; let checkBox = document.createElement("input"); if (config.default) { checkBox.checked = "checked"; } checkBox.type = "checkbox"; let span = document.createElement("span"); span.classList = "checkmark"; checkBox.addEventListener("input", function () { config.callback(checkBox.checked); }, false); container.appendChild(checkBox); container.appendChild(span); wrapper.appendChild(header); wrapper.appendChild(container); parent.appendChild(wrapper); } function createToggleSwitch(scope, parent, config) { let wrapper = document.createElement("div"); wrapper.classList = "module-row"; let header = document.createElement("h4"); header.innerHTML = config.name; let switchContainer = document.createElement("label"); switchContainer.classList = "switch-container"; let checkbox = document.createElement("input"); checkbox.type = "checkbox"; checkbox.addEventListener("input", function () { config.callback(checkbox.checked); }); checkbox.checked = true //_default; let span = document.createElement("span"); span.classList = "slider"; wrapper.appendChild(header); switchContainer.appendChild(checkbox); switchContainer.appendChild(span); wrapper.appendChild(switchContainer); parent.appendChild(wrapper); } function createToggleTabs(scope, parent, config) { let wrapper = document.createElement("div"); wrapper.classList.add("module-row"); let buttonWrapper = document.createElement("div"); buttonWrapper.classList.add("toggle-wrapper"); let header = document.createElement("h4"); let left = document.createElement("div"); let pL = document.createElement("p"); pL.innerHTML = "An"; left.appendChild(pL); left.classList = "toggle-left"; let right = document.createElement("div"); let pR = document.createElement("p"); pR.innerHTML = "Aus"; right.appendChild(pR); left.classList = "toggle-left"; right.innerHMTL = "Aus"; right.classList = "toggle-right"; left.addEventListener("click", function () { left.classList.add("toggle-active"); right.classList.remove("toggle-active"); config.callback(true); }); right.addEventListener("click", function () { left.classList.remove("toggle-active"); right.classList.add("toggle-active"); config.callback(false); }); //SET THE DEFAULTS if (config.default) { left.classList.add("toggle-active"); } else { right.classList.add("toggle-active"); } header.innerHTML = name; wrapper.appendChild(header); buttonWrapper.appendChild(left); buttonWrapper.appendChild(right); wrapper.appendChild(buttonWrapper); parent.appendChild(wrapper); } //GENERAL INTERFACE GENERATION function createButton(scope, parent, config) { let div = document.createElement("div"); let title = document.createElement("h4"); div.classList.add("button"); title.innerHTML = config.name; div.appendChild(title); parent.appendChild(div); div.addEventListener("click", function () { callback(); }, false); }; function createSlider(scope, parent, config) { let div = document.createElement("div"); div.classList.add("module-row"); let title = document.createElement("h4"); title.innerHTML = config.name + " " + config.default * 100 + " %"; let slider = document.createElement("input"); slider.value = config.default * 100; slider.type = "range"; slider.min = config.min; slider.max = config.max; slider.addEventListener("input", function () { config.callback(slider.value); title.innerHTML = config.name + " " + slider.value + "%"; }); function handleOut() { moduleWrapper.style.transition = "all 0s"; title.style.visibility = "visible"; interfaceWrapper.style.visibility = "hidden"; moduleWrapper.style.visibility = "hidden"; slider.style.visibility = "visible"; scope.rendering = true; } function handleIn() { moduleWrapper.style.transition = ""; interfaceWrapper.style.visibility = ""; title.style.visibility = ""; moduleWrapper.style.visibility = "visible"; slider.style.visibility = ""; scope.rendering = false; } //HIDE THE BACKGROUND ON CHANGE if (config.name === "Render Auflösung") { slider.id = "render-quality-slider"; title.id = "render-quality-title"; if (isMobile) { slider.addEventListener("touchstart", function () { handleOut(); }, false); slider.addEventListener("touchend", function () { handleIn(); }, false); slider.addEventListener("touchcancel", function () { handleIn(); }, false); } else { slider.addEventListener("mousedown", function () { handleOut(); }, false); slider.addEventListener("mouseup", function () { handleIn(); }, false); } } div.appendChild(title); div.appendChild(slider); parent.appendChild(div); } function createToggle(scope, parent, config) { switch (currentStyle) { case "light": createToggleSwitch(scope, parent, config); break; case "medium": createToggleCheckbox(scope, parent, config); break; case "heavy": createToggleTabs(scope, parent, config); break; default: break; } } function createDropdown(scope, parent, config) { let wrapper = document.createElement("div"); wrapper.classList = "module-row"; let header = document.createElement("h4"); header.innerHTML = name; let selectWrapper = document.createElement("div"); selectWrapper.classList = "select-wrapper"; let select = document.createElement("select"); let active; for (let i = 0; i < config.options.length; i++) { let _option = document.createElement("option"); _option.innerHTML = config.options[i]; _option.setAttribute("value", i); if (localStorage.style == styles.indexOf(config.options[i])) { _option.selected = "selected"; active = _option; } select.appendChild(_option); } select.addEventListener("change", function (ev) { header.innerHTML = ev.srcElement.innerHTML; config.callback(this.value); }); wrapper.appendChild(header); selectWrapper.append(select); wrapper.appendChild(selectWrapper); parent.appendChild(wrapper); } //EXPORT CLASS export default class UserInterface { constructor(lights, renderer, controls) { var scope = this; this.rendering = true; this.state = false; this.fullscreenState = false; //SET CURRENT STYLE interfaceWrapper.classList = currentStyle; this.config = [ { name: "Qualität", children: [{ type: "slider", mobileOnly: false, name: "Render Auflösung", default: renderer.getPixelRatio(), min: 20, max: 200, callback: function (val) { renderer.setPixelRatio(val / 100); } }, { type: "toggle", mobileOnly: false, name: "High Quality Lights", default: lights.state, callback: function (val) { if (val) { lights.enable(); } else { lights.disable(); } } } ] }, { name: "Steuerung", children: [{ type: "slider", mobileOnly: false, name: "Geschwindigkeit", default: controls.lookSpeed, min: 0, max: 200, callback: function (val) { controls.lookSpeed = val / 100; localStorage.lookSpeed = controls.lookSpeed; } }, { type: "toggle", mobileOnly: false, name: "Nachziehen", default: controls.drag, callback: function (val) { controls.drag = val; localStorage.drag = controls.drag; } }, { type: "toggle", mobileOnly: false, name: "Automatisch drehen", default: controls.autoRotate, callback: function (val) { controls.autoRotate = val; localStorage.autoRotate = controls.autoRotate; } }, { type: "toggle", mobileOnly: true, name: "Geräte Drehung nutzen", default: controls.deviceorientation, callback: function (val) { controls.deviceorientation = val; localStorage.deviceorientation = controls.deviceorientation; } }, { type: "slider", mobileOnly: true, name: "Geräte Drehung Geschwindigkeit", default: controls.deviceorientationSpeed * 100, min: 10, max: 150, callback: function (val) { controls.deviceorientationSpeed = val / 1000; localStorage.deviceorientationSpeed = controls.deviceorientationSpeed; } }, { type: "button", mobileOnly: false, name: "Kamera zurücksetzen", callback: function () { controls.reset(); } } ] }, { name: "Interface", children: [{ type: "dropdown", mobileOnly: false, name: "Stil", options: [ "light", "medium", "heavy" ], callback: function (val) { scope.setStyle(val); console.log("Setting val " + val); localStorage.style = val; } }] } ]; this.loadConfig(); } loadConfig(callback) { var scope = this; //LOAD THE COGWHEEL OPTIONS loadSVG("./icons/" + currentStyle + "_options.svg", (svg) => { this.cogwheel = svg; this.cogwheel.classList = "cogwheel"; this.cogwheel.addEventListener("click", () => { this.toggle(); }, false); interfaceWrapper.insertBefore(this.cogwheel, interfaceWrapper.firstChild); }); //LOAD THE FULLSCREEN ICON loadSVG("./icons/" + currentStyle + "_fullscreen.svg", (svg) => { this.fullscreen = svg; this.fullscreen.classList = "fullscreen"; this.fullscreen.addEventListener("click", () => { this.toggleFullscreen(); }, false); interfaceWrapper.insertBefore(this.fullscreen, interfaceWrapper.firstChild); }); //CREATE ALL CHILDREN OF THE MODULE for (let i = 0; i < this.config.length; i++) { let _module = createModule(this.config[i].name); for (let j = 0; j < this.config[i].children.length; j++) { let obj = this.config[i].children[j]; if (isMobile === false && obj.mobileOnly === true) { //DONT DO ANYTHING } else { //CREATE HAIR LINES if (currentStyle !== "heavy") { let hr = document.createElement("hr"); _module.appendChild(hr); } switch (obj.type) { case "toggle": createToggle(this, _module, obj); break; case "slider": createSlider(this, _module, obj); break; case "button": createButton(this, _module, obj); break; case "dropdown": createDropdown(this, _module, obj); break; default: break; } } } } if (callback) { callback(); } } toggleFullscreen() { if (this.fullscreenState) { this.fullscreenState = false; if (document.exitFullscreen) { document.exitFullscreen(); } else if (document.mozCancelFullScreen) { document.mozCancelFullScreen(); } else if (document.webkitExitFullscreen) { document.webkitExitFullscreen(); } } else { this.fullscreenState = true; if (document.documentElement.requestFullscreen) { document.documentElement.requestFullscreen(); } else if (document.documentElement.mozRequestFullScreen) { document.documentElement.mozRequestFullScreen(); } else if (document.documentElement.webkitRequestFullscreen) { document.documentElement.webkitRequestFullscreen(); } else if (document.documentElement.msRequestFullscreen) { document.documentElement.msRequestFullscreen(); } } } setStyle(style) { var scope = this; modules.length = 0; currentStyle = styles[style]; interfaceWrapper.classList = currentStyle; //REMOVE ALL CHILDREN while (moduleWrapper.firstChild) { moduleWrapper.removeChild(moduleWrapper.firstChild); } interfaceWrapper.removeChild(this.cogwheel); interfaceWrapper.removeChild(this.fullscreen); this.loadConfig(function () { scope.animIn(); }); } setRenderQuality(val) { document.getElementById("render-quality-slider").value = Math.floor(val * 100); document.getElementById("render-quality-title").innerHTML = "Render Auflösung " + Math.floor(val * 100) + "%"; } animIn() { this.state = true; interfaceWrapper.classList.add("interface-in"); this.cogwheel.classList.add("cogwheel-in"); let i = modules.length - 1; modules[i].classList.remove("module-out"); let int = window.setInterval(function () { i--; if (i >= 0) { modules[i].classList.remove("module-out"); } else { moduleWrapper.style.visibility = "visible"; clearInterval(int); } }, 100); } animOut() { this.state = false; interfaceWrapper.classList.remove("interface-in"); this.cogwheel.classList.remove("cogwheel-in"); let i = modules.length - 1; modules[i].classList.add("module-out"); let int = window.setInterval(function () { i--; if (i >= 0) { modules[i].classList.add("module-out"); } else { moduleWrapper.style.visibility = "hidden"; clearInterval(int); } }, 100); } toggle() { if (this.state) { this.animOut(); this.rendering = true; } else { this.rendering = false; this.animIn(); } } }