瀏覽代碼

Start working on scene.

Cixo Develop 9 月之前
父節點
當前提交
b720806527
共有 10 個文件被更改,包括 287 次插入5 次删除
  1. 22 0
      assets/container.js
  2. 117 0
      assets/coordinates.js
  3. 10 0
      assets/core.js
  4. 14 0
      assets/icons.js
  5. 11 3
      assets/push.js
  6. 78 0
      assets/scene-ui.js
  7. 23 0
      assets/scene.js
  8. 1 1
      index.html
  9. 2 1
      theme/loader.css
  10. 9 0
      theme/scene.css

+ 22 - 0
assets/container.js

@@ -0,0 +1,22 @@
+const container = (name, customisation = null) => {
+    if (typeof(name) !== "string") {
+        throw new TypeError("Name of the container must be string.");
+    }
+
+    if (customisation !== null && typeof(customisation) !== "function") {
+        throw new TypeError("Customisation must be null or function.");
+    }
+
+    const target = document.createElement("div");
+
+    target.classList.add("container");
+    target.id = "container-" + name;
+
+    if (customisation) {
+        customisation(target);
+    }
+
+    return target;
+};
+
+export { container };

+ 117 - 0
assets/coordinates.js

@@ -0,0 +1,117 @@
+class coordinates {
+    #x;
+    #y;
+    #z;
+    #rotate;
+
+    constructor() {
+        this.#x = 0;
+        this.#y = 0;
+        this.#z = 0;
+        this.#rotate = 0;
+    }
+
+    get x() {
+        return this.#x;
+    }
+
+    get y() {
+        return this.#y;
+    }
+
+    get z() {
+        return this.#z;
+    }
+
+    get rotate() {
+        return this.#rotate;
+    }
+
+    set x(target) {
+        if (typeof(target) !== "number") {
+            throw new TypeError("Coordinate must be numer.");
+        }
+
+        this.#x = target;
+    }
+
+    set y(target) {
+        if (typeof(target) !== "number") {
+            throw new TypeError("Coordinate must be numer.");
+        }
+
+        this.#y = target;
+    }
+
+    set z(target) {
+        if (typeof(target) !== "number") {
+            throw new TypeError("Coordinate must be numer.");
+        }
+
+        this.#z = target;
+    }
+
+    set rotate(target) {
+        if (typeof(target) !== "number") {
+            throw new TypeError("Coordinate must be numer.");
+        }
+
+        this.#rotate = target % 360;
+    }
+
+    #radians(change = 0) {
+        return (this.rotate + change) * Math.PI / 180;
+    }
+
+    move_front(target = 1) {
+        if (typeof(target) !== "number") {
+            throw new TypeError("Steps must be number.");
+        }
+    
+        this.#y += Math.sin(this.#radians()) * target;
+        this.#x += Math.cos(this.#radians()) * target;
+    }
+
+    move_back(target = 1) {
+        if (typeof(target) !== "number") {
+            throw new TypeError("Steps must be number.");
+        }
+
+        this.move_front(-target);
+    }
+
+    move_left(target = 1) {
+        if (typeof(target) !== "number") {
+            throw new TypeError("Steps must be number.");
+        }
+        
+        this.#y += Math.sin(this.#radians(-90)) * target;
+        this.#x += Math.cos(this.#radians(-90)) * target;
+    }
+
+    move_right(target = 1) {
+        if (typeof(target) !== "number") {
+            throw new TypeError("Steps must be number.");
+        }
+
+        this.move_left(-target);
+    }
+
+    rotate_clockwise(target = 0) {
+        if (typeof(target) !== "number") {
+            throw new TypeError("Degrees must be number.");
+        }
+
+        this.#rotate -= target;
+    }
+
+    rotate_counterclockwise(target = 0) {
+        if (typeof(target) !== "number") {
+            throw new TypeError("Degrees must be number.");
+        }
+
+        this.#rotate += target;
+    }
+}
+
+export { coordinates };

+ 10 - 0
assets/core.js

@@ -1,12 +1,22 @@
 import { color_mode } from "./color-mode.js";
 import { push } from "./push.js";
+import { material_icon } from "./icons.js";
+import { scene } from "./scene.js";
+import { scene_ui } from "./scene-ui.js"
 
 document.addEventListener("DOMContentLoaded", () => {
     const app = document.querySelector(".app");
     const colors_state = new color_mode(app);
     const colors_changer = push("change-color", () => {
         colors_state.reverse();
+    }, (target) => {
+        target.innerText = "";
+        target.appendChild(material_icon("invert_colors"));
     });
 
+    const space = new scene();
+    const controls = new scene_ui(space);
+
+    app.appendChild(controls.box);
     app.appendChild(colors_changer);
 });

+ 14 - 0
assets/icons.js

@@ -0,0 +1,14 @@
+const material_icon = (name) => {
+    if (typeof(name) !== "string") {
+        throw new TypeError("Name of the icon must be string.");
+    }
+
+    const target = document.createElement("span");
+    
+    target.classList.add("material-symbols-outlined");
+    target.innerText = name;
+
+    return target;
+};
+
+export { material_icon };

+ 11 - 3
assets/push.js

@@ -1,4 +1,4 @@
-const push = (name, action) => {
+const push = (name, action, customisation = null) => {
     if (typeof(action) !== "function") {
         throw new TypeError("Action must be an function.");
     }
@@ -7,13 +7,17 @@ const push = (name, action) => {
         throw new TypeError("Name of the push must be string.");
     }
 
-    const target = document.createElement("input");
+    if (customisation !== null && typeof(customisation) !== "function") {
+        throw new TypeError("Customisation must be null or function");
+    }
+
+    const target = document.createElement("button");
     
     target.type = "button";
     target.name = name;
     target.id = "push-" + name;
     
-    target.value = name
+    target.innerText = name
         .toUpperCase()
         .replaceAll("-", " ")
         .replaceAll("_", " ");
@@ -21,6 +25,10 @@ const push = (name, action) => {
     target.classList.add("push");
     target.addEventListener("click", action);
 
+    if (customisation) {
+        customisation(target);
+    }
+
     return target;
 };
 

+ 78 - 0
assets/scene-ui.js

@@ -0,0 +1,78 @@
+import { scene } from "./scene.js";
+import { push } from "./push.js";
+import { material_icon } from "./icons.js";
+import { container } from "./container.js";
+
+class scene_ui {
+    #box;
+    #worker;
+    #step_left;
+    #step_right;
+    #step_front;
+    #step_back;
+    #rotate_clockwise;
+    #rotate_countclockwise;
+
+    constructor(worker) {
+        if (!(worker instanceof scene)) {
+            throw new TypeError("Worker must be instance of scene.");
+        }
+
+        this.#worker = worker;
+
+        this.#step_front = this.#create_push(
+            "front", "arrow_drop_up", position => { position.move_front(); }
+        );
+        
+        this.#step_back = this.#create_push(
+            "back", "arrow_drop_down", position => { position.move_back(); }
+        );
+
+        this.#step_left = this.#create_push(
+            "left", "arrow_left", position => { position.move_left(); }
+        );
+
+        this.#step_right = this.#create_push(
+            "right", "arrow_right", position => { position.move_right(); }
+        );
+
+        this.#rotate_clockwise = this.#create_push(
+            "clockwise", "rotate_right", 
+            position => { position.rotate_clockwise(); }
+        );
+
+        this.#rotate_countclockwise = this.#create_push(
+            "countclockwise", "rotate_left", 
+            position => { position.rotate_countclockwise(); }
+        );
+
+        this.#box = container("controls", (root) => {
+            root.appendChild(container("top", (top) => {
+                top.appendChild(this.#rotate_countclockwise);
+                top.appendChild(this.#step_front);
+                top.appendChild(this.#rotate_clockwise);
+            }));
+
+            root.appendChild(container("bottom", (bottom) => {
+                bottom.appendChild(this.#step_left);
+                bottom.appendChild(this.#step_back);
+                bottom.appendChild(this.#step_right);
+            }));
+        });
+    }
+
+    get box() {
+        return this.#box;
+    }
+
+    #create_push(name, icon, move) {
+        return push(name, () => {
+            move(this.#worker.position);
+        }, (target) => {
+            target.innerText = "";
+            target.appendChild(material_icon(icon));
+        });
+    }
+}
+
+export { scene_ui };

+ 23 - 0
assets/scene.js

@@ -0,0 +1,23 @@
+import { coordinates } from "./coordinates.js";
+
+class scene {
+    #canvas;
+    #context;
+    #position;
+
+    constructor() {
+        this.#position = new coordinates();
+        this.#canvas = document.createElement("canvas");
+        this.#context = this.#canvas.getContext("webgl");
+
+        if (!this.#context) {
+            throw new TypeError("Browser does not support WebGL.");
+        }
+    }
+
+    get position() {
+        return this.#position;
+    }
+}
+
+export { scene };

+ 1 - 1
index.html

@@ -8,7 +8,7 @@
         <link rel="preconnect" href="https://fonts.googleapis.com">
         <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
         <link href="https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">
-        <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0&icon_names=apps">
+        <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0">
     </head>
 
     <body>

+ 2 - 1
theme/loader.css

@@ -1,4 +1,5 @@
 @import url("./colors.css");
 @import url("./app.css");
 @import url("./font.css");
-@import url("./push.css");
+@import url("./push.css");
+@import url("./scene.css");

+ 9 - 0
theme/scene.css

@@ -0,0 +1,9 @@
+#container-controls {
+    position: fixed;
+    left: 20px;
+    bottom: 20px;
+}
+
+#container-controls .container button {
+    margin: 10px;
+}