diff --git a/index.html b/index.html index d6663c2..2afceb9 100644 --- a/index.html +++ b/index.html @@ -18,6 +18,7 @@ + diff --git a/src/main.js b/src/main.js index e772d40..ff91202 100644 --- a/src/main.js +++ b/src/main.js @@ -101,6 +101,34 @@ const clear_visualization = () => { canvas.height = vh - 43; context.clearRect(0, 0, canvas.width, canvas.height); + + draw_grid(); +}; + +const draw_grid = () => { + const canvas = document.getElementById("model_canvas"); + const context = canvas.getContext("2d"); + + const [vw, vh] = get_viewport_dims(); + canvas.width = vw / 2 - 9.5; + canvas.height = vh - 43; + + const square_width = canvas.width / current_state.width; + const square_height = canvas.height / current_state.height; + + // Horizontal lines + for (let y = 1; y < current_state.height; y += 1) { + context.moveTo(0, y * square_height); + context.lineTo(canvas.width, y * square_height); + context.stroke(); + } + + // Vertical lines + for (let x = 1; x < current_state.width; x += 1) { + context.moveTo(x * square_width, 0); + context.lineTo(x * square_width, canvas.height); + context.stroke(); + } }; // @@ -138,6 +166,76 @@ const node_click_view_state = (node, graph) => { // Set up model event-handlers // +let editing = false; +let startpos = null; + +document + .getElementById("model_canvas") + .addEventListener("mousedown", (event) => { + if (model.select(current_state, event.offsetX, event.offsetY) === null) { + startpos = [event.offsetX, event.offsetY]; + } + }); + +document.getElementById("model_canvas").addEventListener("mouseup", (event) => { + if (startpos === null) { + return; + } + + let endpos = [event.offsetX, event.offsetY]; + + const canvas = document.getElementById("model_canvas"); + + const square_width = canvas.width / current_state.width; + const square_height = canvas.height / current_state.height; + + // Coordinates + const startx = Math.floor(startpos[0] / square_width); + const starty = Math.floor(startpos[1] / square_height); + const endx = Math.floor(endpos[0] / square_width); + const endy = Math.floor(endpos[1] / square_height); + + // Check that the block to be added doesn't collide with anything + for (let ix = startx; ix <= endx; ix++) { + for (let iy = starty; iy <= endy; iy++) { + if ( + model.select(current_state, ix * square_width, iy * square_height) !== + null + ) { + startpos = null; + return; + } + } + } + + // Add block + let new_block = model.add_block( + current_state, + Math.min(startx, endx), + Math.min(starty, endy), + Math.max(startx, endx), + Math.max(starty, endy), + ); + + if (new_block === null) { + startpos = null; + return; + } + + // Clear graph + visualize + selected_element = new_block; + clear_visualization(); + model.visualize(current_state); + model.highlight(current_state, selected_element); + + // Generate graph for new state + clear_graph(); + model.generate(states, initial_state, graph, null); + reset_graph_view(graph); + + startpos = null; +}); + document.getElementById("model_canvas").addEventListener("click", (event) => { const element = model.select(current_state, event.offsetX, event.offsetY); @@ -218,6 +316,7 @@ document.getElementById("select_model_button").addEventListener("click", () => { clear_graph(); clear_visualization(); model.visualize(initial_state); + editing = false; document.getElementById("model_name").innerHTML = model.name; document.getElementById("state_name").innerHTML = initial_state.name; }); @@ -232,12 +331,29 @@ document.getElementById("select_state_button").addEventListener("click", () => { states.add(initial_state); clear_graph(); clear_visualization(); - // graph = null; - // graph = generate_graph(data, node_click_view_state); model.visualize(initial_state); + editing = false; document.getElementById("state_name").innerHTML = initial_state.name; }); +document.getElementById("edit_state_button").addEventListener("click", () => { + if (editing === false) { + current_initial_state = 0; + initial_state = model.empty_state; + current_state = initial_state; + selected_element = null; + clear_states(); + states.add(initial_state); + clear_graph(); + clear_visualization(); + model.visualize(initial_state); + editing = true; + document.getElementById("state_name").innerHTML = initial_state.name; + } else { + editing = false; + } +}); + document .getElementById("generate_graph_button") .addEventListener("click", () => { diff --git a/src/simulator/restricted_sliding_blocks/model.js b/src/simulator/restricted_sliding_blocks/model.js index 104ba6b..fe160fc 100644 --- a/src/simulator/restricted_sliding_blocks/model.js +++ b/src/simulator/restricted_sliding_blocks/model.js @@ -183,6 +183,22 @@ const visualize_path = (from_state, to_state) => { // For each state in path: visualize(state) }; +const add_block = (state, x0, y0, x1, y1) => { + let dir; + if (x1 - x0 > y1 - y0) { + dir = HORIZONTAL; + } else if (x1 - x0 < y1 - y0) { + dir = VERTICAL; + } else { + // No square blocks for this model + return null; + } + + let new_block = [state.board.length, dir, x0, y0, x1, y1]; + state.board.push(new_block); + return new_block; +}; + export const restricted_sliding_blocks_model = { name: "Restricted Sliding Blocks", generate, @@ -192,4 +208,11 @@ export const restricted_sliding_blocks_model = { initial_states, select, move, + empty_state: { + name: "Custom", + width: 5, + height: 5, + board: [], + }, + add_block, }; diff --git a/src/simulator/sliding_blocks/model.js b/src/simulator/sliding_blocks/model.js index f018d5f..10bb7b8 100644 --- a/src/simulator/sliding_blocks/model.js +++ b/src/simulator/sliding_blocks/model.js @@ -162,6 +162,12 @@ const visualize_path = (from_state, to_state) => { // For each state in path: visualize(state) }; +const add_block = (state, x0, y0, x1, y1) => { + let new_block = [state.board.length, x0, y0, x1, y1]; + state.board.push(new_block); + return new_block; +}; + export const sliding_blocks_model = { name: "Sliding Blocks", generate, @@ -171,4 +177,11 @@ export const sliding_blocks_model = { initial_states, select, move, + empty_state: { + name: "Custom", + width: 5, + height: 6, + board: [], + }, + add_block, };