Merge pull request 'Add interactiveness to HTML outputs.' (#4) from feature/interactive-html into master
continuous-integration/drone/push Build is passing Details

Reviewed-on: java/labyrinth-generator#4
This commit is contained in:
Manuel Friedli 2023-04-08 23:48:20 +02:00
commit cc8fe0d536
1 changed files with 107 additions and 5 deletions

View File

@ -5,7 +5,109 @@ import ch.fritteli.labyrinth.generator.renderer.Renderer;
import lombok.NonNull;
public class HTMLRenderer implements Renderer<String> {
private static final String POSTAMBLE = "</body></html>";
private static final String POSTAMBLE = "<script>"
+ "let userPath = [];"
+ "const DIR_UNDEF = -1;"
+ "const DIR_SAME = 0;"
+ "const DIR_UP = 1;"
+ "const DIR_RIGHT = 2;"
+ "const DIR_DOWN = 3;"
+ "const DIR_LEFT = 4;"
+ "function getCoords(cell) {"
+ " return {"
+ " x: cell.cellIndex,"
+ " y: cell.parentElement.rowIndex"
+ " };"
+ "}"
+ "function distance(prev, next) {"
+ " return Math.abs(prev.x - next.x) + Math.abs(prev.y - next.y);"
+ "}"
+ "function direction(prev, next) {"
+ " const dist = distance(prev, next);"
+ " if (dist === 0) {"
+ " return DIR_SAME;"
+ " }"
+ " if (dist !== 1) {"
+ " return DIR_UNDEF;"
+ " }"
+ " if (next.x === prev.x) {"
+ " if (next.y === prev.y + 1) {"
+ " return DIR_DOWN;"
+ " }"
+ " return DIR_UP;"
+ " }"
+ " if (next.x === prev.x + 1) {"
+ " return DIR_RIGHT;"
+ " }"
+ " return DIR_LEFT;"
+ "}"
+ "(function () {"
+ " const labyrinthTable = document.getElementById(\"labyrinth\");"
+ " const labyrinthCells = labyrinthTable.getElementsByTagName(\"td\");"
+ " const start = {x: 0, y: 0};"
+ " const end = {"
+ " x: labyrinthTable.getElementsByTagName(\"tr\")[0].getElementsByTagName(\"td\").length - 1,"
+ " y: labyrinthTable.getElementsByTagName(\"tr\").length - 1"
+ " };"
+ " for (let i = 0; i < labyrinthCells.length; i++) {"
+ " let cell = labyrinthCells.item(i);"
+ " cell.onclick = (event) => {"
+ " let target = event.target;"
+ " const coords = getCoords(target);"
+ " if (coords.x === end.x && coords.y === end.y) {"
+ " alert(\"HOORAY! You did it! Congratulations!\")"
+ " }"
+ " if (userPath.length === 0) {"
+ " if (coords.x === start.x && coords.y === start.y) {"
+ " userPath.push(coords);"
+ " target.classList.toggle(\"user\");"
+ " }"
+ " } else {"
+ " const dir = direction(userPath[userPath.length - 1], coords);"
+ " switch (dir) {"
+ " case DIR_UNDEF:"
+ " return;"
+ " case DIR_SAME:"
+ " userPath.pop();"
+ " target.classList.toggle(\"user\");"
+ " return;"
+ " default:"
+ " if (userPath.find(value => value.x === coords.x && value.y === coords.y)) {"
+ " return;"
+ " } else {"
+ " switch (dir) {"
+ " case DIR_UP:"
+ " if (target.classList.contains(\"bottom\")) {"
+ " return;"
+ " }"
+ " break;"
+ " case DIR_RIGHT:"
+ " if (target.classList.contains(\"left\")) {"
+ " return;"
+ " }"
+ " break;"
+ " case DIR_DOWN:"
+ " if (target.classList.contains(\"top\")) {"
+ " return;"
+ " }"
+ " break;"
+ " case DIR_LEFT:"
+ " if (target.classList.contains(\"right\")) {"
+ " return;"
+ " }"
+ " break;"
+ " }"
+ " userPath.push(coords);"
+ " target.classList.toggle(\"user\");"
+ " return;"
+ " }"
+ " }"
+ " }"
+ " };"
+ " }"
+ "})();"
+ "</script></body></html>";
private HTMLRenderer() {
}
@ -23,7 +125,7 @@ public class HTMLRenderer implements Renderer<String> {
}
final Generator generator = new Generator(labyrinth);
final StringBuilder sb = new StringBuilder(this.getPreamble(labyrinth));
sb.append("<table>");
sb.append("<table id=\"labyrinth\">");
while (generator.hasNext()) {
sb.append(generator.next());
}
@ -39,11 +141,12 @@ public class HTMLRenderer implements Renderer<String> {
"<meta charset=\"utf-8\">" +
"<style>" +
"table{border-collapse:collapse;}" +
"td{border:0 solid black;height:1em;width:1em;}" +
"td{border:0 solid black;height:1em;width:1em;cursor:pointer;}" +
"td.top{border-top-width:1px;}" +
"td.right{border-right-width:1px;}" +
"td.bottom{border-bottom-width:1px;}" +
"td.left{border-left-width:1px;}" +
"td.user{background:hotpink;}" +
"</style>" +
"<script>" +
"let solution = false;" +
@ -59,7 +162,6 @@ public class HTMLRenderer implements Renderer<String> {
"</script>" +
"</head>" +
"<body>" +
"<input type=\"checkbox\" onclick=\"toggleSolution()\">show solution</input>";
"<input id=\"solutionbox\" type=\"checkbox\" onclick=\"toggleSolution()\"/><label for=\"solutionbox\">show solution</label>";
}
}