UNPKG

@tisoap/react-flow-smart-edge

Version:

Custom React Flow Edge that never intersects with other nodes

1 lines 47.2 kB
{"version":3,"file":"index.mjs","sources":["../src/pathfinding/grid.ts","../src/functions/guaranteeWalkablePath.ts","../src/functions/pointConversion.ts","../src/functions/utils.ts","../src/functions/createGrid.ts","../src/functions/drawSvgPath.ts","../src/pathfinding/aStar.ts","../src/functions/generatePath.ts","../src/functions/getBoundingBoxes.ts","../src/getSmartEdge/index.ts","../src/internal/useSmartEdgeDebug.ts","../src/SmartEdge/index.tsx","../src/SmartBezierEdge/index.tsx","../src/SmartStraightEdge/index.tsx","../src/SmartStepEdge/index.tsx"],"sourcesContent":["// Based on https://github.com/qiao/PathFinding.js\nimport type { DiagonalMovement } from \"./types.ts\";\n\n// A modern, typed, functional replacement for PathFinding.js Grid\n// Provides the same runtime API shape used by finders/utilities:\n// - width, height, nodes[][]\n// - getNodeAt, isWalkableAt, setWalkableAt, getNeighbors, clone\n\nexport interface GridNode {\n x: number;\n y: number;\n walkable: boolean;\n // A* search metadata (set during pathfinding)\n costFromStart?: number;\n heuristicCostToGoal?: number;\n estimatedTotalCost?: number;\n opened?: boolean;\n closed?: boolean;\n parent?: GridNode;\n}\n\nexport interface Grid {\n width: number;\n height: number;\n nodes: GridNode[][]; // nodes[row][col] i.e., nodes[y][x]\n\n getNodeAt: (x: number, y: number) => GridNode;\n isWalkableAt: (x: number, y: number) => boolean;\n setWalkableAt: (x: number, y: number, walkable: boolean) => void;\n getNeighbors: (\n node: GridNode,\n diagonalMovement: DiagonalMovement,\n ) => GridNode[];\n isInside: (x: number, y: number) => boolean;\n clone: () => Grid;\n}\n\nconst createNodes = (\n width: number,\n height: number,\n matrix?: (number | boolean)[][],\n): GridNode[][] => {\n const rows: GridNode[][] = new Array<GridNode[]>(height);\n for (let y = 0; y < height; y++) {\n const row: GridNode[] = new Array<GridNode>(width);\n for (let x = 0; x < width; x++) {\n // PathFinding.js semantics: a truthy matrix cell means non-walkable\n // (e.g., 1 indicates obstacle). Falsy (0) means walkable.\n const cell = matrix ? matrix[y]?.[x] : undefined;\n const isBlocked = !!cell;\n const walkable = matrix ? !isBlocked : true;\n row[x] = { x, y, walkable };\n }\n rows[y] = row;\n }\n return rows;\n};\n\nconst withinBounds = (width: number, height: number, x: number, y: number) =>\n x >= 0 && x < width && y >= 0 && y < height;\n\n/**\n * Create a grid with the given width/height. Optionally accepts a matrix\n * of booleans/numbers indicating obstacles (truthy = blocked, falsy/0 = walkable).\n */\nexport const createGrid = (\n width: number,\n height: number,\n matrix?: (number | boolean)[][],\n): Grid => {\n const nodes = createNodes(width, height, matrix);\n\n const getNodeAt = (x: number, y: number): GridNode => nodes[y][x];\n\n const isWalkableAt = (x: number, y: number): boolean =>\n withinBounds(width, height, x, y) && nodes[y][x].walkable;\n\n const setWalkableAt = (x: number, y: number, walkable: boolean): void => {\n if (!withinBounds(width, height, x, y)) return;\n nodes[y][x].walkable = walkable;\n };\n\n // Diagonal movement policy using string literal union values:\n // \"Always\", \"Never\", \"IfAtMostOneObstacle\", \"OnlyWhenNoObstacles\"\n const getNeighbors = (\n node: GridNode,\n diagonalMovement: import(\"./types.ts\").DiagonalMovement,\n ): GridNode[] => {\n const x = node.x;\n const y = node.y;\n const neighbors: GridNode[] = [];\n\n // ↑, →, ↓, ←\n const s0 = isWalkableAt(x, y - 1);\n const s1 = isWalkableAt(x + 1, y);\n const s2 = isWalkableAt(x, y + 1);\n const s3 = isWalkableAt(x - 1, y);\n\n if (s0) neighbors.push(getNodeAt(x, y - 1));\n if (s1) neighbors.push(getNodeAt(x + 1, y));\n if (s2) neighbors.push(getNodeAt(x, y + 1));\n if (s3) neighbors.push(getNodeAt(x - 1, y));\n\n // Diagonals: ↗, ↘, ↙, ↖\n const d0Walkable = isWalkableAt(x + 1, y - 1);\n const d1Walkable = isWalkableAt(x + 1, y + 1);\n const d2Walkable = isWalkableAt(x - 1, y + 1);\n const d3Walkable = isWalkableAt(x - 1, y - 1);\n\n if (diagonalMovement === \"Never\") {\n return neighbors;\n }\n\n // default: \"Always\"\n if (d0Walkable) neighbors.push(getNodeAt(x + 1, y - 1));\n if (d1Walkable) neighbors.push(getNodeAt(x + 1, y + 1));\n if (d2Walkable) neighbors.push(getNodeAt(x - 1, y + 1));\n if (d3Walkable) neighbors.push(getNodeAt(x - 1, y - 1));\n return neighbors;\n };\n\n const clone = (): Grid => {\n // Recreate the original matrix semantics: truthy = blocked\n const clonedMatrix: number[][] = nodes.map((row) =>\n row.map((node) => (node.walkable ? 0 : 1)),\n );\n return createGrid(width, height, clonedMatrix);\n };\n\n return {\n width,\n height,\n nodes,\n getNodeAt,\n isWalkableAt,\n setWalkableAt,\n getNeighbors,\n isInside: (x: number, y: number) => withinBounds(width, height, x, y),\n clone,\n };\n};\n","import type { Grid } from \"../pathfinding/grid\";\nimport type { Position, XYPosition } from \"@xyflow/react\";\n\ntype Direction = \"top\" | \"bottom\" | \"left\" | \"right\";\n\nexport const getNextPointFromPosition = (\n point: XYPosition,\n position: Direction,\n): XYPosition => {\n switch (position) {\n case \"top\":\n return { x: point.x, y: point.y - 1 };\n case \"bottom\":\n return { x: point.x, y: point.y + 1 };\n case \"left\":\n return { x: point.x - 1, y: point.y };\n case \"right\":\n return { x: point.x + 1, y: point.y };\n }\n};\n\n/**\n * Guarantee that the path is walkable, even if the point is inside a non\n * walkable area, by adding a walkable path in the direction of the point's\n * Position.\n */\nexport const guaranteeWalkablePath = (\n grid: Grid,\n point: XYPosition,\n position: Position,\n) => {\n let node = grid.getNodeAt(point.x, point.y);\n while (!node.walkable) {\n grid.setWalkableAt(node.x, node.y, true);\n const next = getNextPointFromPosition(node, position);\n node = grid.getNodeAt(next.x, next.y);\n }\n};\n","import type { XYPosition } from \"@xyflow/react\";\n\n/**\n * Each bounding box is a collection of X/Y points in a graph, and we\n * need to convert them to \"occupied\" cells in a 2D grid representation.\n *\n * The top most position of the grid (grid[0][0]) needs to be equivalent\n * to the top most point in the graph (the graph.topLeft point).\n *\n * Since the top most point can have X/Y values different than zero,\n * and each cell in a grid represents a 10x10 pixel area in the grid (or a\n * gridRatio area), there's need to be a conversion between a point in a graph\n * to a point in the grid.\n *\n * We do this conversion by dividing a graph point X/Y values by the grid ratio,\n * and \"shifting\" their values up or down, depending on the values of the top\n * most point in the graph. The top most point in the graph will have the\n * smallest values for X and Y.\n *\n * We avoid setting nodes in the border of the grid (x=0 or y=0), so there's\n * always a \"walkable\" area around the grid.\n */\nexport const graphToGridPoint = (\n graphPoint: XYPosition,\n smallestX: number,\n smallestY: number,\n gridRatio: number,\n): XYPosition => {\n // Affine transform: translate by top-left, scale by grid size, then offset border (1 cell)\n const x = (graphPoint.x - smallestX) / gridRatio + 1;\n const y = (graphPoint.y - smallestY) / gridRatio + 1;\n return { x, y };\n};\n\n/**\n * Converts a grid point back to a graph point, using the reverse logic of\n * graphToGridPoint.\n */\nexport const gridToGraphPoint = (\n gridPoint: XYPosition,\n smallestX: number,\n smallestY: number,\n gridRatio: number,\n): XYPosition => {\n // Inverse affine transform: remove border, scale by grid size, then translate by top-left\n const x = (gridPoint.x - 1) * gridRatio + smallestX;\n const y = (gridPoint.y - 1) * gridRatio + smallestY;\n return { x, y };\n};\n","export const round = (x: number, multiple = 10) =>\n Math.round(x / multiple) * multiple;\n\nexport const roundDown = (x: number, multiple = 10) =>\n Math.floor(x / multiple) * multiple;\n\nexport const roundUp = (x: number, multiple = 10) =>\n Math.ceil(x / multiple) * multiple;\n\nexport const toInteger = (value: number, min = 0) => {\n let result = Math.max(Math.round(value), min);\n result = Number.isInteger(result) ? result : min;\n result = result >= min ? result : min;\n return result;\n};\n","import { createGrid as createLocalGrid } from \"../pathfinding/grid\";\nimport type { Grid } from \"../pathfinding/grid\";\nimport {\n guaranteeWalkablePath,\n getNextPointFromPosition,\n} from \"./guaranteeWalkablePath\";\nimport { graphToGridPoint } from \"./pointConversion\";\nimport { round, roundUp } from \"./utils\";\nimport type { NodeBoundingBox, GraphBoundingBox } from \"./getBoundingBoxes\";\nimport type { Position } from \"@xyflow/react\";\n\nexport interface PointInfo {\n x: number;\n y: number;\n position: Position;\n}\n\nexport const createGrid = (\n graph: GraphBoundingBox,\n nodes: NodeBoundingBox[],\n source: PointInfo,\n target: PointInfo,\n gridRatio = 2,\n) => {\n const { xMin, yMin, width, height } = graph;\n\n // Create a grid representation of the graph box, where each cell is\n // equivalent to 10x10 pixels (or the grid ratio) on the graph. We'll use\n // this simplified grid to do pathfinding.\n const mapColumns = roundUp(width, gridRatio) / gridRatio + 1;\n const mapRows = roundUp(height, gridRatio) / gridRatio + 1;\n const grid: Grid = createLocalGrid(mapColumns, mapRows);\n\n // Update the grid representation with the space the nodes take up\n nodes.forEach((node) => {\n const nodeStart = graphToGridPoint(node.topLeft, xMin, yMin, gridRatio);\n const nodeEnd = graphToGridPoint(node.bottomRight, xMin, yMin, gridRatio);\n\n for (let x = nodeStart.x; x < nodeEnd.x; x++) {\n for (let y = nodeStart.y; y < nodeEnd.y; y++) {\n grid.setWalkableAt(x, y, false);\n }\n }\n });\n\n // Convert the starting and ending graph points to grid points\n const startGrid = graphToGridPoint(\n {\n x: round(source.x, gridRatio),\n y: round(source.y, gridRatio),\n },\n xMin,\n yMin,\n gridRatio,\n );\n\n const endGrid = graphToGridPoint(\n {\n x: round(target.x, gridRatio),\n y: round(target.y, gridRatio),\n },\n xMin,\n yMin,\n gridRatio,\n );\n\n // Guarantee a walkable path between the start and end points, even if the\n // source or target where covered by another node or by padding\n const startingNode = grid.getNodeAt(startGrid.x, startGrid.y);\n guaranteeWalkablePath(grid, startingNode, source.position);\n\n const endingNode = grid.getNodeAt(endGrid.x, endGrid.y);\n guaranteeWalkablePath(grid, endingNode, target.position);\n\n // Use the next closest points as the start and end points, so\n // pathfinding does not start too close to the nodes\n const start = getNextPointFromPosition(startingNode, source.position);\n const end = getNextPointFromPosition(endingNode, target.position);\n\n return { grid, start, end };\n};\n","import type { XYPosition } from \"@xyflow/react\";\n\n/**\n * Takes source and target {x, y} points, together with an array of number\n * tuples [x, y] representing the points along the path, and returns a string\n * to be used as the SVG path.\n */\nexport type SVGDrawFunction = (\n source: XYPosition,\n target: XYPosition,\n path: number[][],\n) => string;\n\n/**\n * Draws a SVG path from a list of points, using straight lines.\n */\nexport const svgDrawStraightLinePath: SVGDrawFunction = (\n source,\n target,\n path,\n) => {\n let svgPathString = `M ${String(source.x)}, ${String(source.y)} `;\n\n path.forEach((point) => {\n const [x, y] = point;\n svgPathString += `L ${String(x)}, ${String(y)} `;\n });\n\n svgPathString += `L ${String(target.x)}, ${String(target.y)} `;\n\n return svgPathString;\n};\n\n/**\n * Draws a SVG path from a list of points, using rounded lines.\n */\nexport const svgDrawSmoothLinePath: SVGDrawFunction = (\n source,\n target,\n path,\n) => {\n const points = [[source.x, source.y], ...path, [target.x, target.y]];\n return quadraticBezierCurve(points);\n};\n\nconst quadraticBezierCurve = (points: number[][]) => {\n const X = 0;\n const Y = 1;\n let point = points[0];\n\n const first = points[0];\n let svgPath = `M${String(first[X])},${String(first[Y])}M`;\n\n for (const next of points) {\n const midPoint = getMidPoint(point[X], point[Y], next[X], next[Y]);\n\n svgPath += ` ${String(midPoint[X])},${String(midPoint[Y])}`;\n svgPath += `Q${String(next[X])},${String(next[Y])}`;\n point = next;\n }\n\n const last = points[points.length - 1];\n svgPath += ` ${String(last[0])},${String(last[1])}`;\n\n return svgPath;\n};\n\nconst getMidPoint = (Ax: number, Ay: number, Bx: number, By: number) => {\n const Zx = (Ax - Bx) / 2 + Bx;\n const Zy = (Ay - By) / 2 + By;\n return [Zx, Zy];\n};\n","// Based on https://github.com/qiao/PathFinding.js\n\nimport type { Grid, GridNode } from \"./grid\";\nimport type { DiagonalMovement } from \"./types.ts\";\n\nexport interface AStarOptions {\n diagonalMovement?: DiagonalMovement;\n heuristic?: (dx: number, dy: number) => number;\n weight?: number;\n}\n\nconst manhattan = (dx: number, dy: number): number => dx + dy;\n\nconst octile = (dx: number, dy: number): number => {\n const F = Math.SQRT2 - 1;\n return dx < dy ? F * dx + dy : F * dy + dx;\n};\n\nconst reconstructPath = (endNode: GridNode): number[][] => {\n const path: number[][] = [];\n let node: GridNode | undefined = endNode;\n\n while (node) {\n path.push([node.x, node.y]);\n node = node.parent;\n }\n\n return path.reverse();\n};\n\nconst getHeuristic = (\n diagonalMovement: DiagonalMovement,\n): ((dx: number, dy: number) => number) => {\n if (diagonalMovement === \"Never\") return manhattan;\n return octile;\n};\n\nconst selectNodeWithLowestEstimatedTotalCost = (\n openList: GridNode[],\n): GridNode => {\n let bestIdx = 0;\n\n for (let i = 1; i < openList.length; i++) {\n if (\n (openList[i].estimatedTotalCost ?? Infinity) <\n (openList[bestIdx].estimatedTotalCost ?? Infinity)\n ) {\n bestIdx = i;\n }\n }\n\n return openList.splice(bestIdx, 1)[0];\n};\n\nconst processNeighbor = (\n neighbor: GridNode,\n current: GridNode,\n end: GridNode,\n openList: GridNode[],\n heuristic: (dx: number, dy: number) => number,\n weight: number,\n): void => {\n if (neighbor.closed) return;\n\n const dx = Math.abs(neighbor.x - current.x);\n const dy = Math.abs(neighbor.y - current.y);\n\n const tentativeG =\n (current.costFromStart ?? 0) + (dx === 0 || dy === 0 ? 1 : Math.SQRT2);\n\n if (!neighbor.opened || tentativeG < (neighbor.costFromStart ?? Infinity)) {\n neighbor.costFromStart = tentativeG;\n\n neighbor.heuristicCostToGoal =\n neighbor.heuristicCostToGoal ??\n weight *\n heuristic(Math.abs(neighbor.x - end.x), Math.abs(neighbor.y - end.y));\n\n neighbor.estimatedTotalCost =\n (neighbor.costFromStart ?? 0) + (neighbor.heuristicCostToGoal ?? 0);\n\n neighbor.parent = current;\n\n if (!neighbor.opened) {\n neighbor.opened = true;\n openList.push(neighbor);\n }\n }\n};\n\nexport const createAStarFinder = (opts: AStarOptions = {}) => {\n const diagonalMovement: DiagonalMovement = opts.diagonalMovement ?? \"Never\";\n const heuristic = opts.heuristic ?? getHeuristic(diagonalMovement);\n const weight = opts.weight ?? 1;\n\n const findPath = (\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n grid: Grid,\n ): number[][] => {\n const start = grid.getNodeAt(startX, startY);\n const end = grid.getNodeAt(endX, endY);\n\n // Open list implemented as a simple array with linear min search for clarity\n const openList: GridNode[] = [];\n\n start.costFromStart = 0;\n start.heuristicCostToGoal = 0;\n start.estimatedTotalCost = 0;\n start.opened = true;\n openList.push(start);\n\n while (openList.length > 0) {\n const node = selectNodeWithLowestEstimatedTotalCost(openList);\n node.closed = true;\n\n if (node === end) {\n return reconstructPath(end);\n }\n\n const neighbors = grid.getNeighbors(node, diagonalMovement);\n for (const neighbor of neighbors) {\n processNeighbor(neighbor, node, end, openList, heuristic, weight);\n }\n }\n\n // no path found\n return [];\n };\n\n return { findPath };\n};\n","import { createAStarFinder } from \"../pathfinding/aStar\";\nimport type { Grid } from \"../pathfinding/grid\";\nimport type { XYPosition } from \"@xyflow/react\";\n\n/**\n * Takes source and target {x, y} points, together with an grid representation\n * of the graph, and returns an array of number tuples [x, y], representing\n * the full path from source to target.\n */\nexport type PathFindingFunction = (\n grid: Grid,\n start: XYPosition,\n end: XYPosition,\n) => number[][];\n\nexport const pathfindingAStarDiagonal: PathFindingFunction = (\n grid,\n start,\n end,\n) => {\n try {\n const finder = createAStarFinder({\n diagonalMovement: \"Always\",\n });\n const fullPath = finder.findPath(start.x, start.y, end.x, end.y, grid);\n\n if (fullPath.length === 0) {\n throw new Error(\"No path found\");\n }\n return fullPath;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unknown error: ${String(error)}`);\n }\n};\n\nexport const pathfindingAStarNoDiagonal: PathFindingFunction = (\n grid,\n start,\n end,\n) => {\n try {\n const finder = createAStarFinder({\n diagonalMovement: \"Never\",\n });\n const fullPath = finder.findPath(start.x, start.y, end.x, end.y, grid);\n\n if (fullPath.length === 0) {\n throw new Error(\"No path found\");\n }\n return fullPath;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unknown error: ${String(error)}`);\n }\n};\n","import { roundUp, roundDown } from \"./utils\";\nimport type { Node, XYPosition } from \"@xyflow/react\";\n\nexport interface NodeBoundingBox {\n id: string;\n width: number;\n height: number;\n topLeft: XYPosition;\n bottomLeft: XYPosition;\n topRight: XYPosition;\n bottomRight: XYPosition;\n}\n\nexport interface GraphBoundingBox {\n width: number;\n height: number;\n topLeft: XYPosition;\n bottomLeft: XYPosition;\n topRight: XYPosition;\n bottomRight: XYPosition;\n xMax: number;\n yMax: number;\n xMin: number;\n yMin: number;\n}\n\n/**\n * Get the bounding box of all nodes and the graph itself, as X/Y coordinates\n * of all corner points.\n */\nexport const getBoundingBoxes = (\n nodes: Node[],\n nodePadding = 2,\n roundTo = 2,\n) => {\n let xMax = Number.MIN_SAFE_INTEGER;\n let yMax = Number.MIN_SAFE_INTEGER;\n let xMin = Number.MAX_SAFE_INTEGER;\n let yMin = Number.MAX_SAFE_INTEGER;\n\n const nodeBoxes: NodeBoundingBox[] = nodes.map((node) => {\n const width = Math.max(node.measured?.width ?? 0, 1);\n const height = Math.max(node.measured?.height ?? 0, 1);\n\n const position: XYPosition = {\n x: node.position.x,\n y: node.position.y,\n };\n\n const topLeft: XYPosition = {\n x: position.x - nodePadding,\n y: position.y - nodePadding,\n };\n const bottomLeft: XYPosition = {\n x: position.x - nodePadding,\n y: position.y + height + nodePadding,\n };\n const topRight: XYPosition = {\n x: position.x + width + nodePadding,\n y: position.y - nodePadding,\n };\n const bottomRight: XYPosition = {\n x: position.x + width + nodePadding,\n y: position.y + height + nodePadding,\n };\n\n if (roundTo > 0) {\n topLeft.x = roundDown(topLeft.x, roundTo);\n topLeft.y = roundDown(topLeft.y, roundTo);\n bottomLeft.x = roundDown(bottomLeft.x, roundTo);\n bottomLeft.y = roundUp(bottomLeft.y, roundTo);\n topRight.x = roundUp(topRight.x, roundTo);\n topRight.y = roundDown(topRight.y, roundTo);\n bottomRight.x = roundUp(bottomRight.x, roundTo);\n bottomRight.y = roundUp(bottomRight.y, roundTo);\n }\n\n if (topLeft.y < yMin) yMin = topLeft.y;\n if (topLeft.x < xMin) xMin = topLeft.x;\n if (bottomRight.y > yMax) yMax = bottomRight.y;\n if (bottomRight.x > xMax) xMax = bottomRight.x;\n\n return {\n id: node.id,\n width,\n height,\n topLeft,\n bottomLeft,\n topRight,\n bottomRight,\n };\n });\n\n const graphPadding = nodePadding * 2;\n\n xMax = roundUp(xMax + graphPadding, roundTo);\n yMax = roundUp(yMax + graphPadding, roundTo);\n xMin = roundDown(xMin - graphPadding, roundTo);\n yMin = roundDown(yMin - graphPadding, roundTo);\n\n const topLeft: XYPosition = {\n x: xMin,\n y: yMin,\n };\n\n const bottomLeft: XYPosition = {\n x: xMin,\n y: yMax,\n };\n\n const topRight: XYPosition = {\n x: xMax,\n y: yMin,\n };\n\n const bottomRight: XYPosition = {\n x: xMax,\n y: yMax,\n };\n\n const width = Math.abs(topLeft.x - topRight.x);\n const height = Math.abs(topLeft.y - bottomLeft.y);\n\n const graphBox: GraphBoundingBox = {\n topLeft,\n bottomLeft,\n topRight,\n bottomRight,\n width,\n height,\n xMax,\n yMax,\n xMin,\n yMin,\n };\n\n return { nodeBoxes, graphBox };\n};\n","import {\n createGrid,\n getBoundingBoxes,\n gridToGraphPoint,\n pathfindingAStarDiagonal,\n svgDrawSmoothLinePath,\n toInteger,\n} from \"../functions\";\nimport type {\n PointInfo,\n PathFindingFunction,\n SVGDrawFunction,\n} from \"../functions\";\nimport type { Node, EdgeProps } from \"@xyflow/react\";\n\nexport type EdgeParams = Pick<\n EdgeProps,\n | \"sourceX\"\n | \"sourceY\"\n | \"targetX\"\n | \"targetY\"\n | \"sourcePosition\"\n | \"targetPosition\"\n>;\n\nexport interface GetSmartEdgeOptions {\n gridRatio?: number;\n nodePadding?: number;\n drawEdge?: SVGDrawFunction;\n generatePath?: PathFindingFunction;\n // Internal-only debug hook. Not intended for public consumption.\n debug?: {\n enabled?: boolean;\n setGraphBox?: (box: {\n x: number;\n y: number;\n width: number;\n height: number;\n }) => void;\n };\n}\n\nexport type GetSmartEdgeParams<\n NodeDataType extends Record<string, unknown> = Record<string, unknown>,\n> = EdgeParams & {\n options?: GetSmartEdgeOptions;\n nodes: Node<NodeDataType>[];\n};\n\nexport interface GetSmartEdgeReturn {\n svgPathString: string;\n edgeCenterX: number;\n edgeCenterY: number;\n}\n\nexport const getSmartEdge = <\n NodeDataType extends Record<string, unknown> = Record<string, unknown>,\n>({\n options = {},\n nodes = [],\n sourceX,\n sourceY,\n targetX,\n targetY,\n sourcePosition,\n targetPosition,\n}: GetSmartEdgeParams<NodeDataType>): GetSmartEdgeReturn | Error => {\n try {\n const {\n drawEdge = svgDrawSmoothLinePath,\n generatePath = pathfindingAStarDiagonal,\n } = options;\n\n let { gridRatio = 10, nodePadding = 10 } = options;\n gridRatio = toInteger(gridRatio);\n nodePadding = toInteger(nodePadding);\n\n // We use the node's information to generate bounding boxes for them\n // and the graph\n const { graphBox, nodeBoxes } = getBoundingBoxes(\n nodes,\n nodePadding,\n gridRatio,\n );\n\n // Internal: publish computed bounding box for debugging visualization\n if (options.debug?.enabled && options.debug.setGraphBox) {\n options.debug.setGraphBox({\n x: graphBox.topLeft.x,\n y: graphBox.topLeft.y,\n width: graphBox.width,\n height: graphBox.height,\n });\n }\n\n const source: PointInfo = {\n x: sourceX,\n y: sourceY,\n position: sourcePosition,\n };\n\n const target: PointInfo = {\n x: targetX,\n y: targetY,\n position: targetPosition,\n };\n\n // With this information, we can create a 2D grid representation of\n // our graph, that tells us where in the graph there is a \"free\" space or not\n const { grid, start, end } = createGrid(\n graphBox,\n nodeBoxes,\n source,\n target,\n gridRatio,\n );\n\n // We then can use the grid representation to do pathfinding\n const generatePathResult = generatePath(grid, start, end);\n\n const fullPath = generatePathResult;\n\n // Here we convert the grid path to a sequence of graph coordinates.\n const graphPath = fullPath.map((gridPoint) => {\n const [x, y] = gridPoint;\n const graphPoint = gridToGraphPoint(\n { x, y },\n graphBox.xMin,\n graphBox.yMin,\n gridRatio,\n );\n return [graphPoint.x, graphPoint.y];\n });\n\n // Finally, we can use the graph path to draw the edge\n const svgPathString = drawEdge(source, target, graphPath);\n\n // Compute the edge's middle point using the full path, so users can use\n // it to position their custom labels\n const index = Math.floor(fullPath.length / 2);\n const middlePoint = fullPath[index];\n const [middleX, middleY] = middlePoint;\n const { x: edgeCenterX, y: edgeCenterY } = gridToGraphPoint(\n { x: middleX, y: middleY },\n graphBox.xMin,\n graphBox.yMin,\n gridRatio,\n );\n\n return { svgPathString, edgeCenterX, edgeCenterY };\n } catch (error) {\n if (error instanceof Error) {\n return error;\n } else {\n return new Error(`Unknown error: ${String(error)}`);\n }\n }\n};\n\nexport type GetSmartEdgeFunction = typeof getSmartEdge;\n","import { createContext, useContext } from \"react\";\n\nexport type SmartEdgeGraphBox = {\n x: number;\n y: number;\n width: number;\n height: number;\n} | null;\n\nexport interface SmartEdgeDebugContextValue {\n enabled: boolean;\n graphBox: SmartEdgeGraphBox;\n setGraphBox: (next: SmartEdgeGraphBox) => void;\n}\n\nexport const SmartEdgeDebugContext = createContext<SmartEdgeDebugContextValue>({\n enabled: false,\n graphBox: null,\n setGraphBox: () => {\n // Do nothing\n },\n});\n\nexport const useSmartEdgeDebug = (): SmartEdgeDebugContextValue => {\n return useContext(SmartEdgeDebugContext);\n};\n","import { BezierEdge, BaseEdge } from \"@xyflow/react\";\nimport type { ComponentType } from \"react\";\nimport { getSmartEdge } from \"../getSmartEdge\";\nimport { useSmartEdgeDebug } from \"../internal/useSmartEdgeDebug\";\nimport type { GetSmartEdgeOptions } from \"../getSmartEdge\";\nimport type { EdgeProps, Node, Edge } from \"@xyflow/react\";\n\nexport type SmartEdgeOptions = GetSmartEdgeOptions & {\n fallback?: ComponentType<EdgeProps<Edge>>;\n};\n\nexport interface SmartEdgeProps<\n EdgeType extends Edge = Edge,\n NodeType extends Node = Node,\n> extends EdgeProps<EdgeType> {\n nodes: NodeType[];\n options: SmartEdgeOptions;\n}\n\nexport function SmartEdge<\n EdgeType extends Edge = Edge,\n NodeType extends Node = Node,\n>({\n nodes,\n options,\n ...edgeProps\n}: Readonly<SmartEdgeProps<EdgeType, NodeType>>) {\n const { enabled: isDebugEnabled, setGraphBox } = useSmartEdgeDebug();\n const {\n sourceX,\n sourceY,\n sourcePosition,\n targetX,\n targetY,\n targetPosition,\n style,\n label,\n labelStyle,\n labelShowBg,\n labelBgStyle,\n labelBgPadding,\n labelBgBorderRadius,\n markerEnd,\n markerStart,\n interactionWidth,\n } = edgeProps;\n\n const smartResponse = getSmartEdge({\n sourcePosition,\n targetPosition,\n sourceX,\n sourceY,\n targetX,\n targetY,\n options: {\n ...options,\n debug: { enabled: isDebugEnabled, setGraphBox },\n } as GetSmartEdgeOptions,\n nodes,\n });\n\n const FallbackEdge = options.fallback ?? BezierEdge;\n\n if (smartResponse instanceof Error) {\n if (isDebugEnabled) {\n console.error(smartResponse);\n }\n return <FallbackEdge {...edgeProps} />;\n }\n\n const { edgeCenterX, edgeCenterY, svgPathString } = smartResponse;\n\n return (\n <BaseEdge\n path={svgPathString}\n labelX={edgeCenterX}\n labelY={edgeCenterY}\n label={label}\n labelStyle={labelStyle}\n labelShowBg={labelShowBg}\n labelBgStyle={labelBgStyle}\n labelBgPadding={labelBgPadding}\n labelBgBorderRadius={labelBgBorderRadius}\n style={style}\n markerStart={markerStart}\n markerEnd={markerEnd}\n interactionWidth={interactionWidth}\n />\n );\n}\n\nexport type SmartEdgeFunction = typeof SmartEdge;\n","import { useNodes, BezierEdge } from \"@xyflow/react\";\nimport { SmartEdge } from \"../SmartEdge\";\nimport { svgDrawSmoothLinePath, pathfindingAStarDiagonal } from \"../functions\";\nimport type { SmartEdgeOptions } from \"../SmartEdge\";\nimport type { EdgeProps, Edge, Node } from \"@xyflow/react\";\n\nconst BezierConfiguration: SmartEdgeOptions = {\n drawEdge: svgDrawSmoothLinePath,\n generatePath: pathfindingAStarDiagonal,\n fallback: BezierEdge,\n};\n\nexport function SmartBezierEdge<\n EdgeType extends Edge = Edge,\n NodeType extends Node = Node,\n>(props: EdgeProps<EdgeType>) {\n const nodes = useNodes<NodeType>();\n\n return (\n <SmartEdge<EdgeType, NodeType>\n {...props}\n options={BezierConfiguration}\n nodes={nodes}\n />\n );\n}\n","import { useNodes, StraightEdge } from \"@xyflow/react\";\nimport { SmartEdge } from \"../SmartEdge\";\nimport {\n svgDrawStraightLinePath,\n pathfindingAStarDiagonal,\n} from \"../functions\";\nimport type { SmartEdgeOptions } from \"../SmartEdge\";\nimport type { Edge, EdgeProps, Node } from \"@xyflow/react\";\n\nconst StraightConfiguration: SmartEdgeOptions = {\n drawEdge: svgDrawStraightLinePath,\n generatePath: pathfindingAStarDiagonal,\n fallback: StraightEdge,\n};\n\nexport function SmartStraightEdge<\n EdgeType extends Edge = Edge,\n NodeType extends Node = Node,\n>(props: EdgeProps<EdgeType>) {\n const nodes = useNodes<NodeType>();\n\n return (\n <SmartEdge<EdgeType, NodeType>\n {...props}\n options={StraightConfiguration}\n nodes={nodes}\n />\n );\n}\n","import { useNodes, StepEdge } from \"@xyflow/react\";\nimport { SmartEdge } from \"../SmartEdge\";\nimport {\n svgDrawStraightLinePath,\n pathfindingAStarNoDiagonal,\n} from \"../functions\";\nimport type { SmartEdgeOptions } from \"../SmartEdge\";\nimport type { Edge, EdgeProps, Node } from \"@xyflow/react\";\n\nconst StepConfiguration: SmartEdgeOptions = {\n drawEdge: svgDrawStraightLinePath,\n generatePath: pathfindingAStarNoDiagonal,\n fallback: StepEdge,\n};\n\nexport function SmartStepEdge<\n EdgeType extends Edge = Edge,\n NodeType extends Node = Node,\n>(props: EdgeProps<EdgeType>) {\n const nodes = useNodes<NodeType>();\n\n return (\n <SmartEdge<EdgeType, NodeType>\n {...props}\n options={StepConfiguration}\n nodes={nodes}\n />\n );\n}\n"],"names":["createNodes","width","height","matrix","rows","y","row","x","isBlocked","walkable","withinBounds","createGrid","nodes","getNodeAt","isWalkableAt","node","diagonalMovement","neighbors","s0","s1","s2","s3","d0Walkable","d1Walkable","d2Walkable","d3Walkable","clonedMatrix","getNextPointFromPosition","point","position","guaranteeWalkablePath","grid","next","graphToGridPoint","graphPoint","smallestX","smallestY","gridRatio","gridToGraphPoint","gridPoint","round","multiple","roundDown","roundUp","toInteger","value","min","result","graph","source","target","xMin","yMin","mapColumns","mapRows","createLocalGrid","nodeStart","nodeEnd","startGrid","endGrid","startingNode","endingNode","start","end","svgDrawStraightLinePath","path","svgPathString","svgDrawSmoothLinePath","points","quadraticBezierCurve","first","svgPath","midPoint","getMidPoint","last","Ax","Ay","Bx","By","Zx","Zy","manhattan","dx","dy","octile","F","reconstructPath","endNode","getHeuristic","selectNodeWithLowestEstimatedTotalCost","openList","bestIdx","i","processNeighbor","neighbor","current","heuristic","weight","tentativeG","createAStarFinder","opts","startX","startY","endX","endY","pathfindingAStarDiagonal","fullPath","error","pathfindingAStarNoDiagonal","getBoundingBoxes","nodePadding","roundTo","xMax","yMax","nodeBoxes","topLeft","bottomLeft","topRight","bottomRight","graphPadding","getSmartEdge","options","sourceX","sourceY","targetX","targetY","sourcePosition","targetPosition","drawEdge","generatePath","graphBox","graphPath","index","middlePoint","middleX","middleY","edgeCenterX","edgeCenterY","SmartEdgeDebugContext","createContext","useSmartEdgeDebug","useContext","SmartEdge","edgeProps","isDebugEnabled","setGraphBox","style","label","labelStyle","labelShowBg","labelBgStyle","labelBgPadding","labelBgBorderRadius","markerEnd","markerStart","interactionWidth","smartResponse","FallbackEdge","BezierEdge","jsx","BaseEdge","BezierConfiguration","SmartBezierEdge","props","useNodes","StraightConfiguration","StraightEdge","SmartStraightEdge","StepConfiguration","StepEdge","SmartStepEdge"],"mappings":"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"}