UNPKG

@tisoap/react-flow-smart-edge

Version:

Custom React Flow Edge that never intersects with other nodes

1 lines 45.9 kB
{"version":3,"file":"index.cjs","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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"}