我为什么要做这个?
无意间接触到了各种排序算法可视化的网页,想用以前学过的算法自己也弄一个可视化网页,那就从最简单的BFS开始好了前言
这个网页还有很多bug没有解决目前也想不到好的方法,不过大致的功能已经差不多实现了
以下是本篇文章正文内容
一、网页大致样式
二、使用步骤
1.首先在白色边匡中选一个起点,以及一个终点,然后点击左上角的star就可以演示了
灰色背景是障碍物
2.演示
思路
1、js代码变量含义,
let box = document.getElementsByClassName("box")[0]; //获取根节点
let p = document.getElementsByTagName("p"); //获取提示
let btn = document.getElementsByTagName("button"); //获取按钮
let itemArray = new Array(); //每个坐标是不是障碍
let boxArray = new Array(); //获取每个坐标里的div
let r = 25; //初始化行
let l = 25; //初始化列
let vis = []; //每个点是否被访问过
let count = 0; //选择起点为1,选择终点为2
let point = new Object(); //保存起点终点
let step = []; //记录上一步的方向
let mov = [ //方向数组
[0, 1],
[1, 0],
[-1, 0],
[0, -1],
/* [1, 1],
[1, -1],
[-1, 1],
[-1, -1] */
];
2、首先绘制一个宽800px的大盒子,里面的单元格宽高为30px,
<body>
<div class="box">
</div>
<div style="position: absolute;top: 100px;">
<p>选择起点:</p>
<p>选择终点:</p>
<p>最少步数:</p>
</div>
<div style="position: absolute;top: 0px;">
<button type="button">star</button>
</div>
</body>
*{
padding: 0;
margin: 0;
}
.box{
width: 800px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin: 0 auto;
}
.item{
font-size: 12px;
text-align: center;
color: #fff;
width: 30px;
height: 30px;
border: 1px solid black;
transition: all 2s;
}
button{
width: 100px;
height: 50px;
display: block;
top: 0;
}
3、实现createItem方法创造子元素
/**
* @param {sting} str div背景颜色
* @return {Object} 返回一个div
*/
function createItem(str = "#fff") {
let div = document.createElement("div");
div.className = "item";
div.style.backgroundColor = str;
box.appendChild(div)
return div;
}
4、实现createBranch方法创造25*25的地图
/**
* @param {number} row 行
* @param {number} column 列
* 创建矩阵
*/
function createBranch(row, column) {
for (let i = 0; i < row; i++) {
let lsArray = [];
boxArray[i] = [];
vis[i] = [];
for (let j = 0; j < column; j++) {
let xx = parseInt(Math.random() * row)
let yy = parseInt(Math.random() * column)
if (Math.abs(i * j - xx * yy) <= 40) { //随机障碍物
boxArray[i].push(createItem("gray"))
lsArray.push(1)
} else {
boxArray[i].push(createItem())
lsArray.push(0)
}
vis[i].push(0)
}
itemArray.push(lsArray)
}
}
5、实现addDivListen方法为每个非障碍物单元格添加点击事件选择起始点
/**
* @param {number} row
* @param {number} column
* 为每个格子添加事件
*/
function addDivListen(row, column) {
for (let i = 0; i < row; i++) {
for (let j = 0; j < column; j++) {
if (!itemArray[i][j]) {
//console.log(boxArray[i][j]);
boxArray[i][j].addEventListener("click", () => {
if (count == 0) { //如果count为0选择起点
boxArray[i][j].style.backgroundColor = "red";
p[0].innerHTML += `row:${i}--column:${j}`
point.star = i;
point.estar = j;
count++;
} else if (count == 1) { //如果count为1选择终点
boxArray[i][j].style.backgroundColor = "green";
p[1].innerHTML += `row:${i}--column:${j}`
point.send = i;
point.end = j;
count++;
} else console.log(point); //输出起始点
})
}
}
}
}
6、核心代码BFS,实现bfs思路很简单,难的是如何边寻路边修改dom元素,
参考:https://blog.csdn.net/qq_39542027/article/details/78893873
1,js是同步加载的
2,浏览器执行js程序,高于页面渲染
所以同步代码不能实现实时刷新dom元素
如何解决?使用定时器,直接看代码吧
function BFS(row, column) {
let step = 0; //最短步数
let proxy = new Object(); //存起始点
let queue = []; //申请队列 使用unshift和pop实现出队入队
proxy.x = point.star;
proxy.y = point.estar;
proxy.k = 0;
queue.push(proxy)
vis[proxy.x][proxy.y] = 1;
let f = true;
return new Promise(resolve =>{ //使用异步函数就可以实现每寻路一次渲染一次dom
setInterval(() => {
while (queue.length > 0) {
let p = queue[queue.length - 1];
queue.pop();
if (p.x == point.send && p.y == point.end) {
boxArray[p.x][p.y].innerHTML = "终点";
boxArray[p.x][p.y].style.backgroundColor = "black"
step = p.k
f = false;
resolve(step)
} else {
if (!f) return;
else {
setTimeout(() => {
for (let i = 0; i < 4; i++) {
let xx = p.x + mov[i][0]
let yy = p.y + mov[i][1] //判断下一个点是否越界,或者是否障碍物,或者是否被访问过
if (xx >= 0 && yy >= 0 && xx < row && yy < column && (!vis[xx][yy]) && (!itemArray[xx][yy])) {
boxArray[xx][yy].style.backgroundColor = "yellow" //将这个点渲染黄色表示已经访问过
vis[xx][yy] = 1;
let pp = {};
pp.x = xx;
pp.y = yy;
pp.k = p.k + 1;
queue.unshift(pp)
}
}
}, 300)
}
}
}
}, 1000)
})
}
我也是刚学习异步函数的一些知识所以很多问题也不知道怎么解决,比如如果起点无法到达终点将没有提示