From 71745d48cf310fb853d134b4fae5039ea15e9631 Mon Sep 17 00:00:00 2001 From: MetroWind Date: Sat, 30 Aug 2025 15:05:19 -0700 Subject: Can drag assets on to the grid, can save image. --- scripts/main.js | 110 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 17 deletions(-) (limited to 'scripts') 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("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")); -- cgit v1.2.3-70-g09d2