A* Pathfinding Algorithm
The `javascript-astar` package provides an efficient implementation of the A* search algorithm in JavaScript for finding the shortest path on a grid. Currently at version 0.4.1, it has been optimized to use a Binary Heap, resulting in significant performance improvements over its original list-based approach. The library supports various graph configurations, including weighted nodes and diagonal movement. A weight of 0 for a node designates it as an impassable obstacle, and specific constraints apply to other weight values. It is primarily designed for browser environments via script tags, exposing global variables, and likely supports CommonJS environments for server-side usage, given its version and use of Grunt for tooling.
Common errors
-
ReferenceError: astar is not defined
cause The `astar` object was not correctly loaded or imported into the current scope. This typically happens if the script tag is missing in the browser or the CommonJS/ESM import is incorrect in Node.js/bundled environments.fixIn browsers, ensure `<script src='astar.js'></script>` is present and loaded before your code. In Node.js, use `const { astar } = require('javascript-astar');` (for CJS) or `import { astar } from 'javascript-astar';` (for ESM). -
TypeError: Graph is not a constructor
cause The `Graph` class was not properly imported or made available. In module environments, this often means it wasn't destructured correctly during the `require` or `import` statement.fixIn module environments, ensure `Graph` is destructured from the package: `const { Graph } = require('javascript-astar');` or `import { Graph } from 'javascript-astar';`. In browsers, verify the `astar.js` script is loaded to expose the global `Graph`. -
Invalid weight value (e.g., 'Weight cannot be negative', 'Weight cannot be between 0 and 1 exclusive')
cause A node in the `Graph` was initialized or modified with a weight value that violates the library's constraints (negative, or a decimal between 0 and 1 exclusively).fixReview the weights defined in your `Graph` grid. Valid weights are `0` (for walls), `1`, or any number `> 1` (including decimals). Adjust any invalid weight values accordingly.
Warnings
- breaking The internal algorithm was fundamentally changed from version 0.0.1 to use a Binary Heap, significantly improving performance over the original list-based approach. While this is a positive change, it represents a breaking change in internal implementation details.
- gotcha Node weights in the graph have specific constraints: a weight of 0 marks a node as an impassable 'wall'. Weights cannot be negative, nor can they be fractional values exclusively between 0 and 1 (e.g., 0.5 is invalid). Decimal values greater than 1 are permitted.
- gotcha When included directly in browser environments via a `<script>` tag, the library exposes `astar` and `Graph` as global variables. This can lead to global namespace pollution, potentially conflicting with other scripts or libraries.
Install
-
npm install javascript-astar -
yarn add javascript-astar -
pnpm add javascript-astar
Imports
- astar
import astar from 'javascript-astar'; // Incorrect for named export const astar = require('javascript-astar'); // This assigns the full module object, not just the 'astar' propertyimport { astar } from 'javascript-astar'; // ESM const { astar } = require('javascript-astar'); // CJS - Graph
new astar.Graph(); // Incorrect, `Graph` is a separate top-level export/global, not a property of `astar`
import { Graph } from 'javascript-astar'; // ESM const { Graph } = require('javascript-astar'); // CJS - astar.heuristics.diagonal
import { diagonal } from 'javascript-astar'; // Heuristics are nested under the `astar` objectimport { astar } from 'javascript-astar'; const diagonalHeuristic = astar.heuristics.diagonal;
Quickstart
const { astar, Graph } = require('javascript-astar'); // For Node.js or bundlers; for browsers, `astar` and `Graph` are globals.
// Basic usage: Find path on a grid without diagonal movement or custom weights.
var graph = new Graph([
[1,1,1,1],
[0,1,1,0],
[0,0,1,1]
]);
var start = graph.grid[0][0];
var end = graph.grid[1][2];
var result = astar.search(graph, start, end);
console.log('Path (no diagonals, no weight):', result.map(node => `(${node.x},${node.y})`).join(' -> '));
// With diagonals: Enable diagonal moves and use the diagonal heuristic.
var graphDiagonal = new Graph([
[1,1,1,1],
[0,1,1,0],
[0,0,1,1]
], { diagonal: true });
var startDiagonal = graphDiagonal.grid[0][0];
var endDiagonal = graphDiagonal.grid[1][2];
var resultWithDiagonals = astar.search(graphDiagonal, startDiagonal, endDiagonal, { heuristic: astar.heuristics.diagonal });
console.log('Path (with diagonals):', resultWithDiagonals.map(node => `(${node.x},${node.y})`).join(' -> '));
// With weights: Define custom movement costs for nodes (0 for walls).
var graphWithWeight = new Graph([
[1,1,2,30],
[0,4,1.3,0],
[0,0,5,1]
]);
var startWithWeight = graphWithWeight.grid[0][0];
var endWithWeight = graphWithWeight.grid[1][2];
var resultWithWeight = astar.search(graphWithWeight, startWithWeight, endWithWeight);
console.log('Path (with weights):', resultWithWeight.map(node => `(${node.x},${node.y})`).join(' -> '));