Skip to content

Commit 2217b4b

Browse files
committed
DOM show grid done
1 parent 24ecbad commit 2217b4b

5 files changed

Lines changed: 462 additions & 452 deletions

File tree

js/domdriver.js

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
class DOMDriver {
2+
constructor(grid, algorithms, stepHistory, targetDOMElement) {
3+
this.Grid = grid
4+
this.Algorithms = algorithms
5+
this.StepHistory = stepHistory
6+
this.DOMElementRoot = targetDOMElement
7+
this.CellReferences = {}
8+
this.preLoadImages()
9+
return this.constructVisuals()
10+
}
11+
// Visualise result
12+
constructVisuals() {
13+
// Find largest steps
14+
for (const algorithm of this.Algorithms) {
15+
const algorithmStep = this.StepHistory[algorithm].history.length
16+
MaxStep = algorithmStep > MaxStep ? algorithmStep : MaxStep
17+
}
18+
let visualResult = `<a style="color: orange">WARNING: WebGPU or the full functionality of WebGPU is not supported in this browser!</a><br>Performance will be drastically reduced!<br>Please use Chrome/Edge 113+, Safari Technology Preview, Opera 99+, Chrome for Android 138+, Samsung Internet 24+, Opera Mobile 80+ <br>Or enable WebGPU flag on Safari or Firefox.<br><br>`
19+
20+
// Add visual for each algorithm
21+
for (const algorithm of Algorithms) {
22+
// Statistics
23+
visualResult += `${algorithm}: ${this.StepHistory[algorithm].history.length} steps found path with length ${this.StepHistory[algorithm].steps.length - 1} in ${Math.round(this.StepHistory[algorithm].time)}ms.`
24+
25+
// Draw initial grid
26+
visualResult += `<table class="board ${algorithm}">\n<tbody>\n`
27+
for (let y = 0; y < Grid.height; y++) {
28+
visualResult += `<tr id="row ${y}">\n`
29+
for (let x = 0; x < Grid.width; x++) {
30+
let style = ""
31+
if (Grid.getCell([x, y]) === "start")
32+
style += " style='filter: invert(33%) sepia(71%) saturate(4592%) hue-rotate(6deg) brightness(106%) contrast(106%);'"
33+
34+
visualResult += `<td id="${x}-${y}" role="cell" class="${Grid.getCell([x, y])}"${style}></td>\n`
35+
}
36+
visualResult += `</tr>\n`
37+
}
38+
visualResult += `</tbody>\n</table>\n`
39+
}
40+
41+
document.getElementById(this.DOMElementRoot).innerHTML = visualResult
42+
43+
this.saveReferences()
44+
}
45+
46+
preLoadImages() {
47+
var image = new Image();
48+
image.src = "./icons/arrow-down-square-fill.svg"
49+
image.src = "./icons/arrow-up-square-fill.svg"
50+
image.src = "./icons/arrow-left-square-fill.svg"
51+
image.src = "./icons/door-open-fill.svg"
52+
}
53+
54+
// Save cell references
55+
saveReferences() {
56+
for (const algorithm of this.Algorithms) {
57+
this.CellReferences[algorithm] = []
58+
const table = document.querySelector(`table.board.${algorithm}`)
59+
for (let y = 0; y < this.Grid.height; y++) {
60+
const row = table.rows[y]
61+
for (let x = 0; x < this.Grid.width; x++) {
62+
this.CellReferences[algorithm][y * this.Grid.width + x] = row.cells[x]
63+
}
64+
}
65+
}
66+
}
67+
68+
// Update algorithm results
69+
updateVisuals() {
70+
for (const algorithm of this.Algorithms) {
71+
const { history, steps, directions } = this.StepHistory[algorithm]
72+
const algorithmSteps = history.length
73+
74+
const queue = QueueHistory[algorithm]
75+
76+
// Calculate render range
77+
const startStep = LastRenderedStep
78+
const endStep = CurrentStep
79+
const isForward = endStep > startStep
80+
81+
CellReferences[algorithm].forEach(cell => cell.removeAttribute("style"))
82+
CellReferences[algorithm].forEach(cell => cell.innerHTML = "")
83+
const starts = document.getElementsByClassName("start")
84+
Array.prototype.forEach.call(starts, function (start) {
85+
start.innerHTML = ""
86+
})
87+
88+
// Show which cell is being searched and which cells are in the queue/stack
89+
const searchingStep = CurrentStep <= algorithmSteps ? CurrentStep : -1
90+
if (searchingStep != -1 && CurrentStep < algorithmSteps) {
91+
const [searchingX, searchingY] = Object.keys(history[searchingStep])[0].split("-").map(function (item) {
92+
return parseInt(item);
93+
})
94+
95+
// Queue might be array or objects, convert array into objects and rename different markings to score
96+
// Did not convert to maintain accuracy of benchmark
97+
// e.g. [{pos: [2, 5], score: 1}, {pos: [2, 7], score: 1}]
98+
const currentStepQueue = queue[searchingStep]
99+
const formattedCurrentStepQueue = []
100+
if (Array.isArray(currentStepQueue[0])) {
101+
currentStepQueue.forEach(queueItem => {
102+
formattedCurrentStepQueue.push({ pos: queueItem, score: -1 })
103+
})
104+
} else {
105+
// Get score name/key
106+
const scoreKey = Object.keys(currentStepQueue[0])[1]
107+
currentStepQueue.forEach(queueItem => {
108+
formattedCurrentStepQueue.push({ pos: queueItem.pos, score: queueItem[scoreKey] })
109+
})
110+
}
111+
112+
// Add score to visited
113+
formattedCurrentStepQueue.forEach(queueCell => {
114+
const pos = queueCell.pos
115+
const score = queueCell.score
116+
if (score != -1)
117+
CellReferences[algorithm][pos[1] * Grid.width + pos[0]].innerHTML = score
118+
else
119+
CellReferences[algorithm][pos[1] * Grid.width + pos[0]].innerHTML = "0"
120+
})
121+
122+
// Set searching cell to #FFFF00, filter generated by: https://codepen.io/sosuke/pen/Pjoqqp
123+
CellReferences[algorithm][searchingY * Grid.width + searchingX].setAttribute("style", "filter: invert(33%) sepia(71%) saturate(4592%) hue-rotate(6deg) brightness(106%) contrast(106%);")
124+
}
125+
126+
// Reverse
127+
if (!isForward) {
128+
for (let step = startStep; step >= endStep; step--) {
129+
if (step >= algorithmSteps) continue
130+
const cells = Object.values(history[step]).flat()
131+
cells.forEach(([x, y]) => {
132+
const index = y * Grid.width + x
133+
if (CellReferences[algorithm][index].className !== "start" &&
134+
CellReferences[algorithm][index].className !== "target") {
135+
CellReferences[algorithm][index].className = "unvisited"
136+
}
137+
})
138+
}
139+
// Forward
140+
} else {
141+
for (let step = startStep; step < endStep; step++) {
142+
if (step >= algorithmSteps) continue
143+
const cells = Object.values(history[step]).flat()
144+
cells.forEach(([x, y]) => {
145+
const index = y * Grid.width + x
146+
if (CellReferences[algorithm][index].className !== "start" &&
147+
CellReferences[algorithm][index].className !== "target") {
148+
CellReferences[algorithm][index].className = "visited"
149+
}
150+
})
151+
}
152+
}
153+
154+
// Draw and un-draw path
155+
const isFinalStep = CurrentStep >= algorithmSteps
156+
const wasFinalStep = LastRenderedStep >= algorithmSteps
157+
158+
if (wasFinalStep && !isFinalStep) {
159+
drawPath(algorithm, false)
160+
}
161+
162+
if (isFinalStep && steps.length > 0) {
163+
drawPath(algorithm, true)
164+
}
165+
}
166+
167+
LastRenderedStep = CurrentStep
168+
}
169+
170+
drawPath(algorithm, draw) {
171+
const { steps, directions } = StepHistory[algorithm]
172+
for (let pathStep = 1; pathStep < StepHistory[algorithm].steps.length; pathStep++) {
173+
const [x, y] = steps[pathStep]
174+
if (draw) {
175+
CellReferences[algorithm][y * Grid.width + x].className = directions[pathStep]
176+
} else {
177+
CellReferences[algorithm][y * Grid.width + x].className = CurrentStep == 0 ? "unvisited" : "visited"
178+
}
179+
}
180+
// Update target cell
181+
const [targetX, targetY] = Grid.getTargetPos()
182+
CellReferences[algorithm][targetY * Grid.width + targetX].className = draw ? "targetReached" : "target"
183+
}
184+
}

0 commit comments

Comments
 (0)