Pathfinder
How do I make an pathfinder?
Playing with A* agorithm and heuristics(diagonal movement is permitted), using css variables for canvas positioning and opacity. http://caniuse.com/#feat=css-variables. What is a pathfinder? How do you make a pathfinder? This script and codes were developed by Massimo on 08 September 2022, Thursday.
Pathfinder - Script Codes HTML Codes
<!DOCTYPE html>
<html >
<head> <meta charset="UTF-8"> <title>Pathfinder</title> <link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="container"> <label>start <input type="radio" name="status" value="start" checked="checked"/> </label> <label>end <input type="radio" name="status" value="end"/> </label> <label>obstacle <input type="radio" name="status" value="obstacle"/> </label><a href="#" id="run">Run</a><a href="#" id="reset">Reset</a> <div id="msg"></div>
</div>
<canvas id="c"></canvas> <script src="js/index.js"></script>
</body>
</html>
Pathfinder - Script Codes CSS Codes
@import url("https://fonts.googleapis.com/css?family=Fjalla+One");
:root { --c_size: 0; --opacity: 0;
}
.info { color: #252525;
}
.error { color: #E53935;
}
.success { color: #43A047;
}
body { margin: 0; overflow: hidden; background: #ddd; font-size: 14px; font-family: 'Fjalla One', sans-serif;
}
body canvas { position: absolute; left: calc(50% - (var(--c_size))/2); top: calc(50% - (var(--c_size))/2); width: var(--c_size); height: var(--c_size); margin-top: 38px; box-shadow: 0 0 8px #000; opacity: 0; opacity: var(--opacity); cursor: move; cursor: grab; cursor: -moz-grab; cursor: -webkit-grab;
}
body canvas:active { cursor: grabbing; cursor: -moz-grabbing; cursor: -webkit-grabbing;
}
body .container { position: absolute; background: rgba(0, 0, 0, 0.2); left: 0; top: 0; width: 100%; height: 36px; padding: 20px;
}
body .container label { display: inline-block; margin-right: 10px; cursor: pointer; text-transform: uppercase;
}
body .container label:after { content: "|";
}
body .container label > input { cursor: pointer;
}
body .container a { padding: 0 5px;
}
body .container a.disabled { pointer-events: none;
}
body .container #run { color: #43A047;
}
body .container #reset { color: #000;
}
body .container #msg { line-height: 30px;
}
Pathfinder - Script Codes JS Codes
var c_size = 300, c = document.getElementById('c'), ctx = c.getContext('2d'); c.width = c_size; c.height = c_size; c.style.setProperty('--c_size', c_size + 'px'); c.style.setProperty('--opacity', 1);
var cells = [], gridX = 15, gridY = 15, cellSizeX = c_size / gridX, cellSizeY = c_size / gridY, colors = { grid: '#00ACC1', start: '#E53935', end: '#43A047', obstacle: '#546E7A' }, found = false, start = null, end = null, openList = [], closedList = [], pIndex = 0, pathColor = 'white', path = [];
var runBtn = document.getElementById('run'), resetBtn = document.getElementById('reset'), msg = document.getElementById('msg');
function Cell(x, y, i, j, color, status) { this.x = x; this.y = y; this.i = i; this.j = j; this.g = 0; this.h = 0; this.f = 0; this.color = color; this.status = status;
}
function drawCell(cell) { ctx.beginPath(); ctx.fillStyle = cell.color; ctx.rect(cell.x, cell.y, cellSizeX, cellSizeY); ctx.fill(); ctx.stroke();
}
function resetCell(cell) { cell.color = colors.grid; cell.status = 'grid'; drawCell(cell);
}
function findCellByPos(x, y) { for(var i=0; i<gridX; i++) { for(var j=0; j<gridY; j++) { var cell = cells[i][j]; if((cell.x < x && cell.x + cellSizeX > x) && (cell.y < y && cell.y + cellSizeY > y)) { return cell; } } }
}
function findCellByStatus(status) { for(var i=0; i<gridX; i++) { for(var j=0; j<gridY; j++) { if(cells[i][j].status == status) { return cells[i][j]; } } }
}
function heuristic(cell) { var dx = Math.abs(cell.i - end.i); var dy = Math.abs(cell.j - end.j); var D = 1; var D2 = Math.sqrt(2); return D * (dx + dy) + (D2 - 2 * D) * Math.min(dx, dy);
}
function showMsg(message, clsName) { msg.innerHTML = message; if (clsName) { msg.setAttribute("class", clsName); } else { msg.removeAttribute("class"); }
}
function drawPath(cell, color) { if(path.length == 0) { var t = cell; while(t.prev) { if(t.prev.status != 'start') { path.push(t.prev); } t = t.prev; } } var l = path.length; if(pIndex < l) { var el = path[l - pIndex - 1]; el.color = color; drawCell(el); } else { showMsg('Solution has been found', 'success'); found = true; }
}
function find() { var best = 0; for(var i=0; i<openList.length; i++) { if (openList[i].f < openList[best].f) { best = i; } } var current = openList[best]; if(current.status == 'end') { drawPath(current, pathColor); pIndex++; return; } else { var index = openList.indexOf(current); if (index > -1) { openList.splice(index, 1); } closedList.push(current); var i = current.i, j = current.j, neighbours = []; if(j > 0) { neighbours.push(cells[i][j-1]); if(i > 0) neighbours.push(cells[i - 1][j - 1]); if(i < gridY - 1) neighbours.push(cells[i + 1][j - 1]); } if(j < gridX - 1) { neighbours.push(cells[i][j+1]); if(i > 0) neighbours.push(cells[i - 1][j + 1]); if(i < gridY - 1) neighbours.push(cells[i+1][j + 1]); } if(i > 0) { neighbours.push(cells[i-1][j]); } if(i < gridY - 1) { neighbours.push(cells[i+1][j]); } for(var k=0; k<neighbours.length; k++) { var neighbour = neighbours[k]; if(closedList.indexOf(neighbour) < 0 && neighbour.status != 'obstacle') { var tmpG = current.g + 1; var isBetter = false; if(openList.indexOf(neighbour) != -1) { if(tmpG < neighbour.g) { neighbour.g = tmpG; isBetter = true; } } else { neighbour.g = tmpG; isBetter = true; openList.push(neighbour); } if (isBetter) { neighbour.h = heuristic(neighbour); neighbour.f = neighbour.g + neighbour.h; neighbour.prev = current; } } } }
}
function defineCell(cell) { var status = document.querySelector(':checked').value; if (cell) { if(cell.status == status) { resetCell(cell); } else { if(status != 'obstacle') { var startOrEnd = findCellByStatus(status); if(startOrEnd) { resetCell(startOrEnd); } } cell.color = colors[status]; cell.status = status; drawCell(cell); } }
}
function resetGrid() { ctx.clearRect(0, 0, c.width, c.height); start = null; end = null; cells = []; openList = []; closedList = []; path = []; pIndex = 0; runBtn.removeAttribute("class"); showMsg('Set start / end / obstacle(s) and press "Run"', 'info'); for(var i=0; i<gridX; i++) { var tmp = []; for(var j=0; j<gridY; j++) { var x = j*cellSizeX, y = i*cellSizeY, cell = new Cell(x, y, i, j, colors.grid, 'grid'); tmp.push(cell); drawCell(cell); } cells.push(tmp); }
}
resetGrid();
var pressed = false, target = '';
c.addEventListener("mouseup", function () { pressed = false;
});
c.addEventListener("mousedown", function (e) { pressed = true; target = findCellByPos( e.pageX - c.offsetLeft, e.pageY - c.offsetTop ); defineCell(target); c.addEventListener("mousemove", function (e) { var cell = findCellByPos( e.pageX - c.offsetLeft, e.pageY - c.offsetTop ); if(!pressed || !target || !cell || (target.x == cell.x && target.y == cell.y)) { return false; } defineCell(cell); target = cell; });
});
resetBtn.addEventListener("click", function () { resetGrid();
});
runBtn.addEventListener("click", function () { start = findCellByStatus('start'); end = findCellByStatus('end'); if (!start || !end) { showMsg('Set start and end cells!!!', 'error'); return; } runBtn.setAttribute("class", "disabled"); found = false; openList.push(start); start.f = heuristic(start); update();
});
window.requestAnimFrame = (function() { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000/60); };
})();
function update() { if(openList.length > 0) { find(); } else { showMsg('No solution', 'error'); found = true; } if(!found) { window.requestAnimFrame(update); }
}
Developer | Massimo |
Username | _massimo |
Uploaded | September 08, 2022 |
Rating | 4.5 |
Size | 5,360 Kb |
Views | 34,408 |
Find the perfect freelance services for your business! Fiverr's mission is to change how the world works together. Fiverr connects businesses with freelancers offering digital services in 500+ categories. Find Developer!
Name | Size |
ASCII art | 2,756 Kb |
Cat loader | 3,899 Kb |
Svg penguin | 2,990 Kb |
Record button | 4,905 Kb |
Melting ice cream | 3,839 Kb |
Whale pixel art animation | 3,215 Kb |
Css carousel | 2,977 Kb |
Pacman | 2,503 Kb |
Css tabs | 3,169 Kb |
Bernard the polar bear | 4,070 Kb |
Jasper is the AI Content Generator that helps you and your team break through creative blocks to create amazing, original content 10X faster. Discover all the ways the Jasper AI Content Platform can help streamline your creative workflows. Start For Free!
Name | Username | Size |
Navcube | Wbarlow | 4,775 Kb |
NeeilTimer | Neeilan | 2,836 Kb |
Simple Responsive Text | Fbrz | 2,282 Kb |
Monochrome Form | AlienPiglet | 3,096 Kb |
Mesmerizing octopus | Jllodra | 3,549 Kb |
Word Wrap Algorithm for Multiline Canvas Text | Peterhry | 2,349 Kb |
Iron Man SVG Loading Animation | Andythayer | 3,069 Kb |
Rain Landing in a Pond | Edball | 3,009 Kb |
Shopping cart | Andiio | 6,581 Kb |
Experiment | Toddmoy | 2,849 Kb |
Surf anonymously, prevent hackers from acquiring your IP address, send anonymous email, and encrypt your Internet connection. High speed, ultra secure, and easy to use. Instant setup. Hide Your IP Now!