Implement Live State Editing
This commit is contained in:
@ -18,6 +18,7 @@
|
|||||||
<button disabled id="model_name"></button>
|
<button disabled id="model_name"></button>
|
||||||
<button id="select_state_button">Select State</button>
|
<button id="select_state_button">Select State</button>
|
||||||
<button disabled id="state_name"></button>
|
<button disabled id="state_name"></button>
|
||||||
|
<button id="edit_state_button">Edit State</button>
|
||||||
<button id="up_button">UP</button>
|
<button id="up_button">UP</button>
|
||||||
<button id="down_button">DOWN</button>
|
<button id="down_button">DOWN</button>
|
||||||
<button id="left_button">LEFT</button>
|
<button id="left_button">LEFT</button>
|
||||||
|
120
src/main.js
120
src/main.js
@ -101,6 +101,34 @@ const clear_visualization = () => {
|
|||||||
canvas.height = vh - 43;
|
canvas.height = vh - 43;
|
||||||
|
|
||||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
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
|
// 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) => {
|
document.getElementById("model_canvas").addEventListener("click", (event) => {
|
||||||
const element = model.select(current_state, event.offsetX, event.offsetY);
|
const element = model.select(current_state, event.offsetX, event.offsetY);
|
||||||
|
|
||||||
@ -218,6 +316,7 @@ document.getElementById("select_model_button").addEventListener("click", () => {
|
|||||||
clear_graph();
|
clear_graph();
|
||||||
clear_visualization();
|
clear_visualization();
|
||||||
model.visualize(initial_state);
|
model.visualize(initial_state);
|
||||||
|
editing = false;
|
||||||
document.getElementById("model_name").innerHTML = model.name;
|
document.getElementById("model_name").innerHTML = model.name;
|
||||||
document.getElementById("state_name").innerHTML = initial_state.name;
|
document.getElementById("state_name").innerHTML = initial_state.name;
|
||||||
});
|
});
|
||||||
@ -232,12 +331,29 @@ document.getElementById("select_state_button").addEventListener("click", () => {
|
|||||||
states.add(initial_state);
|
states.add(initial_state);
|
||||||
clear_graph();
|
clear_graph();
|
||||||
clear_visualization();
|
clear_visualization();
|
||||||
// graph = null;
|
|
||||||
// graph = generate_graph(data, node_click_view_state);
|
|
||||||
model.visualize(initial_state);
|
model.visualize(initial_state);
|
||||||
|
editing = false;
|
||||||
document.getElementById("state_name").innerHTML = initial_state.name;
|
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
|
document
|
||||||
.getElementById("generate_graph_button")
|
.getElementById("generate_graph_button")
|
||||||
.addEventListener("click", () => {
|
.addEventListener("click", () => {
|
||||||
|
@ -183,6 +183,22 @@ const visualize_path = (from_state, to_state) => {
|
|||||||
// For each state in path: visualize(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 = {
|
export const restricted_sliding_blocks_model = {
|
||||||
name: "Restricted Sliding Blocks",
|
name: "Restricted Sliding Blocks",
|
||||||
generate,
|
generate,
|
||||||
@ -192,4 +208,11 @@ export const restricted_sliding_blocks_model = {
|
|||||||
initial_states,
|
initial_states,
|
||||||
select,
|
select,
|
||||||
move,
|
move,
|
||||||
|
empty_state: {
|
||||||
|
name: "Custom",
|
||||||
|
width: 5,
|
||||||
|
height: 5,
|
||||||
|
board: [],
|
||||||
|
},
|
||||||
|
add_block,
|
||||||
};
|
};
|
||||||
|
@ -162,6 +162,12 @@ const visualize_path = (from_state, to_state) => {
|
|||||||
// For each state in path: visualize(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 = {
|
export const sliding_blocks_model = {
|
||||||
name: "Sliding Blocks",
|
name: "Sliding Blocks",
|
||||||
generate,
|
generate,
|
||||||
@ -171,4 +177,11 @@ export const sliding_blocks_model = {
|
|||||||
initial_states,
|
initial_states,
|
||||||
select,
|
select,
|
||||||
move,
|
move,
|
||||||
|
empty_state: {
|
||||||
|
name: "Custom",
|
||||||
|
width: 5,
|
||||||
|
height: 6,
|
||||||
|
board: [],
|
||||||
|
},
|
||||||
|
add_block,
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user