Only load ThreeJS if necessary
authorTheSaminator <TheSaminator@users.noreply.github.com>
Sun, 6 Mar 2022 15:48:20 +0000 (10:48 -0500)
committerTheSaminator <TheSaminator@users.noreply.github.com>
Sun, 6 Mar 2022 15:48:20 +0000 (10:48 -0500)
src/jvmMain/kotlin/starshipfights/info/view_tpl.kt
src/jvmMain/resources/static/init.js

index 2d098da9514978ce2b25815be4322b7cc9d5d3bf..cab67c68f072e0df4ba561f0b4057309cbe68fda 100644 (file)
@@ -12,10 +12,6 @@ fun page(pageTitle: String? = null, navBar: List<NavItem>? = null, sidebar: Side
                link(rel = "stylesheet", href = "https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,400;0,700;1,400;1,700&family=Orbitron:wght@500;700;900&display=swap")
                link(rel = "stylesheet", href = "/static/style.css")
                
-               script(src = "/static/game/three.js") {}
-               script(src = "/static/game/three-examples.js") {}
-               script(src = "/static/game/three-extras.js") {}
-               
                title {
                        +"Starship Fights"
                        pageTitle?.let { +" | $it" }
index 18c7e47aebf44ab832808f3019ccb6eb0d1f1a79..cdc004f32026488975065f908df9e6f2d7c5298e 100644 (file)
-window.addEventListener("load", function () {
-       // Load and render OBJ meshes
-       if (!window.sfShipMeshViewer) return;
+(function () {
+       function animationFrame() {
+               return new Promise(resolve => {
+                       window.requestAnimationFrame(resolve);
+               });
+       }
 
-       const canvases = document.getElementsByTagName("canvas");
-       for (let canvas of canvases) {
-               const modelName = canvas.getAttribute("data-model");
-               if (modelName == null) continue;
+       function loadScript(scriptLoc) {
+               return new Promise(resolve => {
+                       const scriptElem = document.createElement("script");
+                       scriptElem.async = true;
+                       scriptElem.src = scriptLoc;
+                       scriptElem.addEventListener("load", resolve);
 
-               let threeData = {};
+                       document.body.append(scriptElem);
+               });
+       }
 
-               threeData.camera = new THREE.PerspectiveCamera(69, 1, 0.01, 1000.0);
+       window.addEventListener("load", async function () {
+               // Load and render OBJ meshes
+               if (!window.sfShipMeshViewer) return;
 
-               threeData.scene = new THREE.Scene();
-               threeData.scene.add(new THREE.AmbientLight("#FFFFFF", 0.35));
+               const canvases = document.getElementsByTagName("canvas");
+               if (canvases.length < 1) return;
 
-               threeData.renderer = new THREE.WebGLRenderer({"canvas": canvas, "antialias": true});
+               for (const scriptLoc of [
+                       "/static/game/three.js",
+                       "/static/game/three-examples.js",
+                       "/static/game/three-extras.js",
+               ]) {
+                       await loadScript(scriptLoc);
+               }
 
-               threeData.controls = new THREE.OrbitControls(threeData.camera, canvas);
+               const canvasLoads = [];
+               for (let canvas of canvases) {
+                       const modelName = canvas.getAttribute("data-model");
+                       if (modelName == null) continue;
 
-               function render() {
-                       threeData.controls.update();
-                       threeData.renderer.render(threeData.scene, threeData.camera);
-                       window.requestAnimationFrame(render);
-               }
+                       const p = (async () => {
+                               let threeData = {};
 
-               window.addEventListener('resize', () => {
-                       const dim = canvas.getBoundingClientRect();
-                       threeData.camera.aspect = dim.width / dim.height;
-                       threeData.camera.updateProjectionMatrix();
-                       threeData.renderer.setSize(dim.width, dim.height);
-               })
-
-               window.requestAnimationFrame(async () => {
-                       const dim = canvas.getBoundingClientRect();
-                       threeData.camera.aspect = dim.width / dim.height;
-                       threeData.camera.updateProjectionMatrix();
-                       threeData.renderer.setSize(dim.width, dim.height);
-
-                       const mtlPath = modelName + ".mtl";
-                       const mtlLib = await (new THREE.MTLLoader()).setPath("/static/game/meshes/").setResourcePath("/static/game/meshes/").loadAsync(mtlPath);
-                       mtlLib.preload();
-
-                       const objPath = modelName + ".obj";
-                       const objMesh = await (new THREE.OBJLoader()).setPath("/static/game/meshes/").setResourcePath("/static/game/meshes/").setMaterials(mtlLib).loadAsync(objPath);
-                       objMesh.scale.setScalar(0.069);
-
-                       threeData.scene.add(objMesh);
-
-                       const bbox = new THREE.Box3().setFromObject(threeData.scene);
-                       bbox.dimensions = {
-                               x: bbox.max.x - bbox.min.x,
-                               y: bbox.max.y - bbox.min.y,
-                               z: bbox.max.z - bbox.min.z
-                       };
-                       objMesh.position.sub(new THREE.Vector3(bbox.min.x + bbox.dimensions.x / 2, bbox.min.y + bbox.dimensions.y / 2, bbox.min.z + bbox.dimensions.z / 2));
+                               threeData.camera = new THREE.PerspectiveCamera(69, 1, 0.01, 1000.0);
 
-                       threeData.camera.position.set(bbox.dimensions.x / 2, bbox.dimensions.y / 2, Math.max(bbox.dimensions.x, bbox.dimensions.y, bbox.dimensions.z));
+                               threeData.scene = new THREE.Scene();
+                               threeData.scene.add(new THREE.AmbientLight("#FFFFFF", 0.35));
 
-                       threeData.light = new THREE.PointLight("#FFFFFF", 0.65);
-                       threeData.scene.add(threeData.camera);
-                       threeData.camera.add(threeData.light);
-                       threeData.light.position.set(0, 0, 0);
+                               threeData.renderer = new THREE.WebGLRenderer({"canvas": canvas, "antialias": true});
 
-                       render();
-               });
-       }
-});
-
-window.addEventListener("load", function () {
-       // Localize dates and times
-       const moments = document.getElementsByClassName("moment");
-       for (let moment of moments) {
-               let date = new Date(Number(moment.innerHTML.trim()));
-               moment.innerHTML = date.toLocaleString();
-               moment.style.display = "inline";
-       }
-});
-
-window.addEventListener("load", function () {
-       // Generate random admiral names
-       if (!window.sfAdmiralNameGen) return;
-
-       const nameBox = document.getElementById("name");
-       const isFemaleButton = document.getElementById("sex-female");
-       const generators = document.getElementsByClassName("generate-admiral-name");
-       for (let generator of generators) {
-               const flavor = generator.getAttribute("data-flavor");
-               generator.onclick = (e) => {
-                       e.preventDefault();
-                       (async () => {
-                               nameBox.value = await (await fetch("/generate-name/" + flavor + "/" + (isFemaleButton.checked ? "female" : "male"))).text();
-                       })();
-               };
-       }
-});
+                               threeData.controls = new THREE.OrbitControls(threeData.camera, canvas);
+
+                               function render() {
+                                       threeData.controls.update();
+                                       threeData.renderer.render(threeData.scene, threeData.camera);
+                                       window.requestAnimationFrame(render);
+                               }
+
+                               window.addEventListener('resize', () => {
+                                       const dim = canvas.getBoundingClientRect();
+                                       threeData.camera.aspect = dim.width / dim.height;
+                                       threeData.camera.updateProjectionMatrix();
+                                       threeData.renderer.setSize(dim.width, dim.height, false);
+                               })
+
+                               await animationFrame();
+
+                               const dim = canvas.getBoundingClientRect();
+                               threeData.camera.aspect = dim.width / dim.height;
+                               threeData.camera.updateProjectionMatrix();
+                               threeData.renderer.setSize(dim.width, dim.height, false);
+
+                               const mtlPath = modelName + ".mtl";
+                               const mtlLib = await (new THREE.MTLLoader()).setPath("/static/game/meshes/").setResourcePath("/static/game/meshes/").loadAsync(mtlPath);
+                               mtlLib.preload();
+
+                               const objPath = modelName + ".obj";
+                               const objMesh = await (new THREE.OBJLoader()).setPath("/static/game/meshes/").setResourcePath("/static/game/meshes/").setMaterials(mtlLib).loadAsync(objPath);
+                               objMesh.scale.setScalar(0.069);
 
-window.addEventListener("load", function () {
-       // Indicate maximum and used length of <textarea>s
-       const textareas = document.getElementsByTagName("textarea");
-       for (let textarea of textareas) {
-               if (!textarea.hasAttribute("maxLength")) continue;
+                               threeData.scene.add(objMesh);
 
-               const maxLengthIndicator = document.createElement("p");
-               maxLengthIndicator.style.fontSize = "0.8em";
-               maxLengthIndicator.style.fontStyle = "italic";
-               maxLengthIndicator.style.color = "#555";
+                               const bbox = new THREE.Box3().setFromObject(threeData.scene);
+                               bbox.dimensions = {
+                                       x: bbox.max.x - bbox.min.x,
+                                       y: bbox.max.y - bbox.min.y,
+                                       z: bbox.max.z - bbox.min.z
+                               };
+                               objMesh.position.sub(new THREE.Vector3(bbox.min.x + bbox.dimensions.x / 2, bbox.min.y + bbox.dimensions.y / 2, bbox.min.z + bbox.dimensions.z / 2));
 
-               textarea.after(maxLengthIndicator);
+                               threeData.camera.position.set(bbox.dimensions.x / 2, bbox.dimensions.y / 2, Math.max(bbox.dimensions.x, bbox.dimensions.y, bbox.dimensions.z));
 
-               function updateIndicator() {
-                       const maxLengthAttr = textarea.getAttribute("maxLength");
-                       if (!maxLengthAttr) return;
-                       const maxLength = Number(maxLengthAttr);
+                               threeData.light = new THREE.PointLight("#FFFFFF", 0.65);
+                               threeData.scene.add(threeData.camera);
+                               threeData.camera.add(threeData.light);
+                               threeData.light.position.set(0, 0, 0);
 
-                       maxLengthIndicator.innerText = "" + textarea.value.length + "/" + maxLength;
+                               render();
+                       })();
+                       canvasLoads.push(p);
                }
 
-               textarea.addEventListener("input", () => {
-                       updateIndicator();
-               });
+               for (const p of canvasLoads) {
+                       await p;
+               }
+       });
+
+       window.addEventListener("load", function () {
+               // Localize dates and times
+               const moments = document.getElementsByClassName("moment");
+               for (let moment of moments) {
+                       let date = new Date(Number(moment.innerHTML.trim()));
+                       moment.innerHTML = date.toLocaleString();
+                       moment.style.display = "inline";
+               }
+       });
+
+       window.addEventListener("load", function () {
+               // Generate random admiral names
+               if (!window.sfAdmiralNameGen) return;
+
+               const nameBox = document.getElementById("name");
+               const isFemaleButton = document.getElementById("sex-female");
+               const generators = document.getElementsByClassName("generate-admiral-name");
+               for (let generator of generators) {
+                       const flavor = generator.getAttribute("data-flavor");
+                       generator.onclick = (e) => {
+                               e.preventDefault();
+                               (async () => {
+                                       nameBox.value = await (await fetch("/generate-name/" + flavor + "/" + (isFemaleButton.checked ? "female" : "male"))).text();
+                               })();
+                       };
+               }
+       });
 
-               updateIndicator();
-       }
-});
-
-window.addEventListener("load", function () {
-       // Allow POSTing with <a>s
-       const anchors = document.getElementsByTagName("a");
-       for (let anchor of anchors) {
-               const method = anchor.getAttribute("data-method");
-               if (method == null) continue;
-
-               anchor.onclick = e => {
-                       e.preventDefault();
-
-                       let form = document.createElement("form");
-                       form.style.display = "none";
-                       form.action = anchor.href;
-                       form.method = method;
-
-                       const csrfToken = anchor.getAttribute("data-csrf-token");
-                       if (csrfToken != null) {
-                               let csrfInput = document.createElement("input");
-                               csrfInput.name = "csrf-token";
-                               csrfInput.type = "hidden";
-                               csrfInput.value = csrfToken;
-                               form.append(csrfInput);
+       window.addEventListener("load", function () {
+               // Indicate maximum and used length of <textarea>s
+               const textareas = document.getElementsByTagName("textarea");
+               for (let textarea of textareas) {
+                       if (!textarea.hasAttribute("maxLength")) continue;
+
+                       const maxLengthIndicator = document.createElement("p");
+                       maxLengthIndicator.style.fontSize = "0.8em";
+                       maxLengthIndicator.style.fontStyle = "italic";
+                       maxLengthIndicator.style.color = "#555";
+
+                       textarea.after(maxLengthIndicator);
+
+                       function updateIndicator() {
+                               const maxLengthAttr = textarea.getAttribute("maxLength");
+                               if (!maxLengthAttr) return;
+                               const maxLength = Number(maxLengthAttr);
+
+                               maxLengthIndicator.innerText = "" + textarea.value.length + "/" + maxLength;
                        }
 
-                       document.body.append(form);
-                       form.submit();
-               };
-       }
-});
+                       textarea.addEventListener("input", () => {
+                               updateIndicator();
+                       });
+
+                       updateIndicator();
+               }
+       });
+
+       window.addEventListener("load", function () {
+               // Allow POSTing with <a>s
+               const anchors = document.getElementsByTagName("a");
+               for (let anchor of anchors) {
+                       const method = anchor.getAttribute("data-method");
+                       if (method == null) continue;
+
+                       anchor.onclick = e => {
+                               e.preventDefault();
+
+                               let form = document.createElement("form");
+                               form.style.display = "none";
+                               form.action = anchor.href;
+                               form.method = method;
+
+                               const csrfToken = anchor.getAttribute("data-csrf-token");
+                               if (csrfToken != null) {
+                                       let csrfInput = document.createElement("input");
+                                       csrfInput.name = "csrf-token";
+                                       csrfInput.type = "hidden";
+                                       csrfInput.value = csrfToken;
+                                       form.append(csrfInput);
+                               }
+
+                               document.body.append(form);
+                               form.submit();
+                       };
+               }
+       });
+})();