From 6a6cc2f22e806be895f9fddc9ed6cabab395b6cb Mon Sep 17 00:00:00 2001 From: MetroWind Date: Sat, 30 Aug 2025 16:24:35 -0700 Subject: Add plan serialization --- scripts/lib.js | 30 ++++++++++++++++++++++++++++++ scripts/main.js | 46 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/scripts/lib.js b/scripts/lib.js index 4e4850e..9a5e957 100644 --- a/scripts/lib.js +++ b/scripts/lib.js @@ -2,9 +2,39 @@ const h = preact.h; const CELL_SIZE = 32; const GRID_SIZE_X = 21; const GRID_SIZE_Y = 21; +const FLOOR_COUNT = 15; const ASSET_SVG_PROPS = {"width": CELL_SIZE, "height": CELL_SIZE, "version": "1.1"}; const ASSET_WHITE_BG = h("rect", {"x": 0, "y": 0, "width": CELL_SIZE, "height": CELL_SIZE, "fill": "white", "stroke-width": 0 }); + +// Bytes is a Uint8Array +async function compressBytes(bytes) +{ + let blob = new Blob([bytes]); + const ds = new CompressionStream("deflate"); + const compressed = blob.stream().pipeThrough(ds); + let compressed_blob = await new Response(compressed).blob(); + const reader = new FileReader(); + return new Promise((resolve, _) => { + reader.onloadend = (event) => { + const result = event.target.result; + resolve(result.replace(/^data:.+;base64,/, '') + .replaceAll("/", "-").replaceAll("+", "_")); + } + reader.readAsDataURL(compressed_blob); + }); +} + +// Decompress into Uint8Array +function decompressBytes(s) +{ + const decoded = window.atob(s.replaceAll("_", "+").replaceAll("-", "/")); + const decoded_array = Uint8Array.from(decoded, c => c.charCodeAt(0)); + let blob = new Blob([decoded_array]); + const cs = new DecompressionStream("deflate"); + const decompressed = blob.stream().pipeThrough(cs); + return new Response(decompressed).bytes(); +} diff --git a/scripts/main.js b/scripts/main.js index 01301a1..7347f37 100644 --- a/scripts/main.js +++ b/scripts/main.js @@ -3,8 +3,15 @@ const DEFAULT_APP_STATE = { plan: new Array(GRID_SIZE_X * GRID_SIZE_Y).fill(0), // mouse_state can be “normal”, or “dnd”. mouse_state: "normal", + plan_code: "", }; +async function serializePlan(app_state) +{ + let rest = new Array(GRID_SIZE_X * GRID_SIZE_Y * (FLOOR_COUNT - 1)).fill(0); + return compressBytes(Uint8Array.from(app_state.plan.concat(rest))); +} + function genGrid(x_count, y_count, cell_size) { let lines = []; @@ -62,7 +69,6 @@ function PlanGridView({content, mouse_state}) } let hilight_box = null; - console.debug(mouse_coord); if(mouse_coord !== null && mouse_state != "dnd") { @@ -130,7 +136,13 @@ function App({initial_state}) let new_state = structuredClone(state); new_state.plan[cell_index] = asset_index; new_state.mouse_state = "normal"; - setState(new_state); + serializePlan(new_state).then((s) => { + new_state.plan_code = s; + setState(new_state); + const url = new URL(location); + url.searchParams.set("plan", s); + window.history.pushState({}, "", url); + }); } function onClickSaveImg() @@ -157,13 +169,37 @@ function App({initial_state}) } return h("div", {}, + h("h2", {}, `Floor ${state.floor}`), 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!"))); + "Open Image!")), + h("div", {}, + h("textarea", {readonly: true}, state.plan_code)), + ); } -preact.render(h(App, {initial_state: DEFAULT_APP_STATE}), - document.getElementById("Plan")); +function render(app_state) +{ + preact.render(h(App, {initial_state: app_state}), + document.getElementById("Plan")); +} + +const paramsString = window.location.search; +const searchParams = new URLSearchParams(paramsString); +const encoded_plan = searchParams.get("plan"); +if(encoded_plan === null) +{ + render(DEFAULT_APP_STATE); +} +else +{ + decompressBytes(encoded_plan).then(a => { + let state = structuredClone(DEFAULT_APP_STATE); + state.plan = Array.from(a.subarray(0, GRID_SIZE_X * GRID_SIZE_Y)); + state.plan_code = encoded_plan; + render(state); + }); +} -- cgit v1.2.3-70-g09d2