aboutsummaryrefslogtreecommitdiff
path: root/scripts/main.js
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/main.js')
-rw-r--r--scripts/main.js256
1 files changed, 0 insertions, 256 deletions
diff --git a/scripts/main.js b/scripts/main.js
deleted file mode 100644
index d6b6787..0000000
--- a/scripts/main.js
+++ /dev/null
@@ -1,256 +0,0 @@
1const DEFAULT_APP_STATE = {
2 floor: 0, // This is 0-based.
3 plan: new Array(FLOOR_COUNT).fill(null).map(() =>
4 new Array(GRID_SIZE_X * GRID_SIZE_Y).fill(0)),
5 // mouse_state can be “normal”, or “dnd”.
6 mouse_state: "normal",
7 dragged_asset_index: null,
8 plan_code: "",
9};
10
11async function serializePlan(app_state)
12{
13 return compressBytes(Uint8Array.from(app_state.plan.flat()));
14}
15
16function genGrid(x_count, y_count, cell_size)
17{
18 let lines = [];
19 for(let x = 0; x < x_count+1; x++)
20 {
21 lines.push(h("line", {
22 "x1": x * cell_size + 0.5, "x2": x * cell_size + 0.5, "y1": 0.5,
23 "y2": y_count * cell_size + 0.5,
24 }));
25 }
26 for(let y = 0; y < y_count+1; y++)
27 {
28 lines.push(h("line", {
29 "y1": y * cell_size + 0.5, "y2": y * cell_size + 0.5, "x1": 0.5,
30 "x2": x_count * cell_size + 0.5,
31 }));
32 }
33 return h("g", {"stroke": "black", "stroke-width": 1}, lines);
34}
35
36function AssetView({asset_index, on_drag_begin, on_drag_end})
37{
38 let bg = ASSET_WHITE_BG;
39 if(TILES[asset_index].bg === null)
40 {
41 bg = null;
42 }
43 return h("div", {"class": "Asset", "draggable": true,
44 "data-asset-index": asset_index,
45 "ondragstart": on_drag_begin,
46 "ondragend": on_drag_end,
47 "title": TILES[asset_index].name,},
48 h("svg", ASSET_SVG_PROPS, bg, TILES[asset_index].inner_svg));
49}
50
51function AssetsView({on_drag_begin, on_drag_end})
52{
53 let views = TILES.map((t, i) =>
54 h(AssetView, {asset_index: i, on_drag_begin: on_drag_begin,
55 on_drag_end: on_drag_end}));
56 return h("div", {}, views);
57}
58
59function PlanGridView({content, mouse_state, on_drop_asset})
60{
61 const [mouse_coord, setMouseCoord] = preactHooks.useState(null);
62
63 function onDragOver(e)
64 {
65 e.preventDefault();
66 let b = e.target.getBoundingClientRect();
67 let x = e.clientX - b.left;
68 let y = e.clientY - b.top;
69 setMouseCoord([x, y]);
70 }
71
72 function onDragLeave(e)
73 {
74 setMouseCoord(null);
75 }
76
77 let hilight_box = null;
78
79 if(mouse_coord !== null && mouse_state != "dnd")
80 {
81 setMouseCoord(null);
82 }
83
84 if(mouse_coord !== null && mouse_state == "dnd")
85 {
86 let cell_x = Math.floor(mouse_coord[0] / (CELL_SIZE + 1));
87 let cell_y = Math.floor(mouse_coord[1] / (CELL_SIZE + 1));
88 hilight_box = h("rect", {
89 "x": cell_x * (CELL_SIZE + 1) + 0.5, "y": cell_y * (CELL_SIZE + 1) + 0.5,
90 "width": CELL_SIZE + 1, "height": CELL_SIZE + 1,
91 "stroke": "#2ed573", "stroke-width": 3, "fill": "transparent"});
92 }
93 let grid_content = content.map((idx, i) => {
94 if(idx == 0) return null;
95 let cell_x = i % GRID_SIZE_X;
96 let cell_y = Math.floor(i / GRID_SIZE_Y);
97 let bg = ASSET_WHITE_BG;
98 if(TILES[idx].bg === null)
99 {
100 bg = null;
101 }
102 return h("g", {"transform": `translate(${cell_x * (CELL_SIZE + 1) + 1} \
103${cell_y * (CELL_SIZE + 1) + 1})`}, bg, TILES[idx].inner_svg);
104 });
105
106 let img_width = GRID_SIZE_X * (CELL_SIZE + 1) + 1;
107 let img_height = GRID_SIZE_Y * (CELL_SIZE + 1) + 1;
108 return h("svg", {"width": img_width, "height": img_height,
109 "version": "1.1", "ondragover": onDragOver,
110 "ondrop": on_drop_asset,
111 "id": "Grid", "ondragleave": onDragLeave,},
112 h("rect", {x: 0, y: 0, width: img_width, height: img_height,
113 fill: "#c0c0c0", "stroke-width": 0}),
114 grid_content, genGrid(GRID_SIZE_X, GRID_SIZE_Y, CELL_SIZE + 1),
115 hilight_box);
116}
117
118function PlanView({plan, mouse_state, on_drop_asset})
119{
120 return h("div", {"id": "PlanView"},
121 h("div", {"id": "EntryIndicator"}, "⬇️"),
122 h(PlanGridView, {content: plan, mouse_state: mouse_state,
123 on_drop_asset: on_drop_asset}));
124}
125
126// on_floor_change takes one argument, which is the 0-based floor number.
127function FloorSelector({floor, on_floor_change})
128{
129 return h("div", {"id": "FloorSelectorWrapper", "class": "ButtonRowLeft"},
130 h("label", {}, "Floor"),
131 h("input", {"id": "InputFloor", "type": "number", "step": 1, "min": 1,
132 "max": 15, "value": floor,
133 onchange: e => on_floor_change(e.target.value - 1),},));
134}
135
136function App({initial_state})
137{
138 const [state, setState] = preactHooks.useState(initial_state);
139
140 // This event is targeted at the dragged asset.
141 function onDragAssetBegin(e)
142 {
143 let new_state = structuredClone(state);
144 new_state.mouse_state = "dnd";
145 new_state.dragged_asset_index =
146 parseInt(e.target.getAttribute("data-asset-index"));
147 setState(new_state);
148 }
149
150 // This event is targeted at the grid.
151 function onDropAssetOnGrid(e)
152 {
153 if(e.dragEffect === "none") return;
154 let grid = document.getElementById("Grid");
155 let b = grid.getBoundingClientRect();
156 let x = e.clientX - b.left;
157 let y = e.clientY - b.top;
158 let cell_x = Math.floor(x / (CELL_SIZE + 1));
159 let cell_y = Math.floor(y / (CELL_SIZE + 1));
160 let cell_index = cell_y * GRID_SIZE_X + cell_x;
161 let new_state = structuredClone(state);
162 new_state.plan[new_state.floor][cell_index] = state.dragged_asset_index;
163 new_state.mouse_state = "normal";
164 new_state.dragged_asset_index = null;
165 serializePlan(new_state).then((s) => {
166 new_state.plan_code = s;
167 setState(new_state);
168 const url = new URL(location);
169 url.searchParams.set("plan", s);
170 window.history.pushState({}, "", url);
171 });
172 }
173
174 function onClickSaveImg()
175 {
176 let grid_width = GRID_SIZE_X * (CELL_SIZE + 1) + 1;
177 let grid_height = GRID_SIZE_Y * (CELL_SIZE + 1) + 1;
178 let canvas = document.createElement('canvas');
179 canvas.width = grid_width;
180 canvas.height = grid_height;
181 let context = canvas.getContext("2d");
182 var svg_str = new XMLSerializer().serializeToString(
183 document.getElementById("Grid"));
184 var img = new Image();
185 img.onload = function()
186 {
187 context.drawImage(this, 0, 0);
188 // Open PNG image in new tab.
189 var dataURL = canvas.toDataURL("image/png");
190 var new_tab = window.open('about:blank', 'image from canvas');
191 new_tab.document.write("<img src='" + dataURL + "' alt='from canvas'/>");
192 }
193 img.src = 'data:image/svg+xml; charset=utf8, ' +
194 encodeURIComponent(svg_str);
195 }
196
197 // new_floor is 0-based.
198 function onFloorChange(new_floor)
199 {
200 let new_state = structuredClone(state);
201 new_state.floor = new_floor;
202 setState(new_state);
203 }
204
205 return h("div", {},
206 h("div", {"class": "MainWrapper"},
207 h("aside", {},
208 h(FloorSelector, {floor: state.floor + 1,
209 on_floor_change: onFloorChange}),
210 h("div", {"class": "LabeledPanel"},
211 h("h2", {}, "Rooms"),
212 h(AssetsView, {on_drag_begin: onDragAssetBegin,}))),
213 h(PlanView, {plan: state.plan[state.floor],
214 mouse_state: state.mouse_state,
215 on_drop_asset: onDropAssetOnGrid,})),
216 h("hr", {}),
217 h("div", {},
218 h("textarea", {readonly: true}, state.plan_code)),
219 h("div", {"class": "ButtonRow"},
220 h("button", {onclick: onClickSaveImg, type: "button"},
221 "Open as Image!")),
222 );
223}
224
225function render(app_state)
226{
227 preact.render(h(App, {initial_state: app_state}),
228 document.getElementById("Plan"));
229}
230
231const paramsString = window.location.search;
232const searchParams = new URLSearchParams(paramsString);
233const encoded_plan = searchParams.get("plan");
234if(encoded_plan === null)
235{
236 render(DEFAULT_APP_STATE);
237}
238else
239{
240 decompressBytes(encoded_plan).then(a => {
241 let state = structuredClone(DEFAULT_APP_STATE);
242 let concated_plan = Array.from(a);
243 console.debug(concated_plan);
244 state.plan = [];
245 for(let i = 0; i < GRID_SIZE_X * GRID_SIZE_Y * FLOOR_COUNT;
246 i += GRID_SIZE_X * GRID_SIZE_Y)
247 {
248 let floor_slice =
249 concated_plan.slice(i, i + GRID_SIZE_X * GRID_SIZE_Y);
250 console.debug(floor_slice);
251 state.plan.push(floor_slice);
252 }
253 state.plan_code = encoded_plan;
254 render(state);
255 });
256}