Add interactiveness to HTML outputs. #4
					 1 changed files with 107 additions and 5 deletions
				
			
		|  | @ -5,7 +5,109 @@ import ch.fritteli.labyrinth.generator.renderer.Renderer; | ||||||
| import lombok.NonNull; | import lombok.NonNull; | ||||||
| 
 | 
 | ||||||
| public class HTMLRenderer implements Renderer<String> { | 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() { |     private HTMLRenderer() { | ||||||
|     } |     } | ||||||
|  | @ -23,7 +125,7 @@ public class HTMLRenderer implements Renderer<String> { | ||||||
|         } |         } | ||||||
|         final Generator generator = new Generator(labyrinth); |         final Generator generator = new Generator(labyrinth); | ||||||
|         final StringBuilder sb = new StringBuilder(this.getPreamble(labyrinth)); |         final StringBuilder sb = new StringBuilder(this.getPreamble(labyrinth)); | ||||||
|         sb.append("<table>"); |         sb.append("<table id=\"labyrinth\">"); | ||||||
|         while (generator.hasNext()) { |         while (generator.hasNext()) { | ||||||
|             sb.append(generator.next()); |             sb.append(generator.next()); | ||||||
|         } |         } | ||||||
|  | @ -39,11 +141,12 @@ public class HTMLRenderer implements Renderer<String> { | ||||||
|                 "<meta charset=\"utf-8\">" + |                 "<meta charset=\"utf-8\">" + | ||||||
|                 "<style>" + |                 "<style>" + | ||||||
|                 "table{border-collapse:collapse;}" + |                 "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.top{border-top-width:1px;}" + | ||||||
|                 "td.right{border-right-width:1px;}" + |                 "td.right{border-right-width:1px;}" + | ||||||
|                 "td.bottom{border-bottom-width:1px;}" + |                 "td.bottom{border-bottom-width:1px;}" + | ||||||
|                 "td.left{border-left-width:1px;}" + |                 "td.left{border-left-width:1px;}" + | ||||||
|  |                 "td.user{background:hotpink;}" + | ||||||
|                 "</style>" + |                 "</style>" + | ||||||
|                 "<script>" + |                 "<script>" + | ||||||
|                 "let solution = false;" + |                 "let solution = false;" + | ||||||
|  | @ -59,7 +162,6 @@ public class HTMLRenderer implements Renderer<String> { | ||||||
|                 "</script>" + |                 "</script>" + | ||||||
|                 "</head>" + |                 "</head>" + | ||||||
|                 "<body>" + |                 "<body>" + | ||||||
|                 "<input type=\"checkbox\" onclick=\"toggleSolution()\">show solution</input>"; |                 "<input id=\"solutionbox\" type=\"checkbox\" onclick=\"toggleSolution()\"/><label for=\"solutionbox\">show solution</label>"; | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue