BareGit

Can drag assets on to the grid, can save image.

Author: MetroWind <chris.corsair@gmail.com>
Date: Sat Aug 30 15:05:19 2025 -0700
Commit: 71745d48cf310fb853d134b4fae5039ea15e9631

Changes

diff --git a/scripts/main.js b/scripts/main.js
index 7a8b9d4..01301a1 100644
--- a/scripts/main.js
+++ b/scripts/main.js
@@ -1,3 +1,10 @@
+const DEFAULT_APP_STATE = {
+    floor: 1,
+    plan: new Array(GRID_SIZE_X * GRID_SIZE_Y).fill(0),
+    // mouse_state can be “normal”, or “dnd”.
+    mouse_state: "normal",
+};
+
 function genGrid(x_count, y_count, cell_size)
 {
     let lines = [];
@@ -18,22 +25,25 @@ function genGrid(x_count, y_count, cell_size)
     return h("g", {"stroke": "black", "stroke-width": 1}, lines);
 }
 
-function AssetView({asset_index})
+function AssetView({asset_index, on_drag_begin, on_drag_end})
 {
     return h("div", {"class": "Asset", "draggable": true,
-                     "id": `Asset${asset_index}`},
+                     "data-asset-index": asset_index,
+                     "ondragstart": on_drag_begin,
+                     "ondragend": on_drag_end,},
              h("svg", ASSET_SVG_PROPS, ASSET_WHITE_BG,
                TILES[asset_index].inner_svg));
 }
 
-function AssetsView()
+function AssetsView({on_drag_begin, on_drag_end})
 {
     let views = TILES.slice(1).map((t, i) =>
-        h(AssetView, {asset_index: i + 1}));
+        h(AssetView, {asset_index: i + 1, on_drag_begin: on_drag_begin,
+                      on_drag_end: on_drag_end}));
     return h("div", {}, views);
 }
 
-function PlanGridView({content})
+function PlanGridView({content, mouse_state})
 {
     const [mouse_coord, setMouseCoord] = preactHooks.useState(null);
 
@@ -52,7 +62,14 @@ function PlanGridView({content})
     }
 
     let hilight_box = null;
-    if(mouse_coord !== null)
+    console.debug(mouse_coord);
+
+    if(mouse_coord !== null && mouse_state != "dnd")
+    {
+        setMouseCoord(null);
+    }
+
+    if(mouse_coord !== null && mouse_state == "dnd")
     {
         let cell_x = Math.floor(mouse_coord[0] / (CELL_SIZE + 1));
         let cell_y = Math.floor(mouse_coord[1] / (CELL_SIZE + 1));
@@ -62,32 +79,91 @@ function PlanGridView({content})
             "stroke": "#2ed573", "stroke-width": 3, "fill": "transparent"});
     }
     let grid_content = content.map((idx, i) => {
+        if(idx == 0) return null;
         let cell_x = i % GRID_SIZE_X;
         let cell_y = Math.floor(i / GRID_SIZE_Y);
-        return h("g", {"transform": `translate(${cell_x * (CELL_SIZE + 1)} \
-${cell_y * (CELL_SIZE + 1)})`}, TILES[idx]);
+        return h("g", {"transform": `translate(${cell_x * (CELL_SIZE + 1) + 1} \
+${cell_y * (CELL_SIZE + 1) + 1})`}, ASSET_WHITE_BG, TILES[idx].inner_svg);
     });
 
-    return h("svg", {"width": GRID_SIZE_X * (CELL_SIZE + 1) + 1,
-                     "height": GRID_SIZE_Y * (CELL_SIZE + 1) + 1,
+    let img_width = GRID_SIZE_X * (CELL_SIZE + 1) + 1;
+    let img_height = GRID_SIZE_Y * (CELL_SIZE + 1) + 1;
+    return h("svg", {"width": img_width, "height": img_height,
                      "version": "1.1", "ondragover": onDragOver,
-                     "id": "Grid", "ondragleave": onDragLeave},
+                     "id": "Grid", "ondragleave": onDragLeave,},
+             h("rect", {x: 0, y: 0, width: img_width, height: img_height,
+                        fill: "#a4b0be", "stroke-width": 0}),
              grid_content, genGrid(GRID_SIZE_X, GRID_SIZE_Y, CELL_SIZE + 1),
              hilight_box);
 }
 
-function PlanView(props)
+function PlanView({plan, mouse_state})
 {
     return h("div", {},
              h("p", {}, "The plan:"),
-             h(PlanGridView, {}));
+             h(PlanGridView, {content: plan, mouse_state: mouse_state}));
 }
 
-function App(props)
+function App({initial_state})
 {
+    const [state, setState] = preactHooks.useState(initial_state);
+
+    function onDragAssetBegin(e)
+    {
+        let new_state = structuredClone(state);
+        new_state.mouse_state = "dnd";
+        setState(new_state);
+    }
+    function onDragAssetEnd(e)
+    {
+        if(e.dragEffect === "none") return;
+        let grid = document.getElementById("Grid");
+        let b = grid.getBoundingClientRect();
+        let x = e.clientX - b.left;
+        let y = e.clientY - b.top;
+        if(x < 0 || y < 0 || x > b.width || y > b.height) return;
+        let cell_x = Math.floor(x / (CELL_SIZE + 1));
+        let cell_y = Math.floor(y / (CELL_SIZE + 1));
+        let cell_index = cell_y * GRID_SIZE_X + cell_x;
+        let asset_index = parseInt(e.target.getAttribute("data-asset-index"));
+
+        let new_state = structuredClone(state);
+        new_state.plan[cell_index] = asset_index;
+        new_state.mouse_state = "normal";
+        setState(new_state);
+    }
+
+    function onClickSaveImg()
+    {
+        let grid_width = GRID_SIZE_X * (CELL_SIZE + 1) + 1;
+        let grid_height = GRID_SIZE_Y * (CELL_SIZE + 1) + 1;
+        let canvas = document.createElement('canvas');
+        canvas.width = grid_width;
+        canvas.height = grid_height;
+        let context = canvas.getContext("2d");
+        var svg_str = new XMLSerializer().serializeToString(
+            document.getElementById("Grid"));
+        var img = new Image();
+        img.onload = function()
+        {
+            context.drawImage(this, 0, 0);
+            // Open PNG image in new tab.
+            var dataURL = canvas.toDataURL("image/png");
+            var new_tab = window.open('about:blank', 'image from canvas');
+            new_tab.document.write("<img src='" + dataURL + "' alt='from canvas'/>");
+        }
+        img.src = 'data:image/svg+xml; charset=utf8, ' +
+            encodeURIComponent(svg_str);
+    }
+
     return h("div", {},
-             h(AssetsView, {}),
-             h(PlanView, {}));
+             h(AssetsView, {on_drag_begin: onDragAssetBegin,
+                            on_drag_end: onDragAssetEnd}),
+             h(PlanView, {plan: state.plan, mouse_state: state.mouse_state}),
+             h("div", {},
+               h("a", {"href": "javascript:void(0);", onclick: onClickSaveImg},
+                 "Open Image!")));
 }
 
-preact.render(h(App, {}), document.getElementById("Plan"));
+preact.render(h(App, {initial_state: DEFAULT_APP_STATE}),
+              document.getElementById("Plan"));
diff --git a/styles.css b/styles.css
index aca9b9b..73e6899 100644
--- a/styles.css
+++ b/styles.css
@@ -1,6 +1,5 @@
 body
 {
-    background-color: #a4b0be;
 }
 
 *