@joshrp/react-flow-smart-edge 4.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Tiso Alvarez Puccinelli
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,355 @@
1
+ # React Flow Smart Edge
2
+
3
+ Custom Edges for React Flow that never intersect with other nodes, using pathfinding.
4
+
5
+ ![TypeScript](https://shields.io/badge/TypeScript-3178C6?logo=TypeScript&logoColor=white)
6
+ ![Storybook](https://img.shields.io/badge/Storybook-FF4785?logo=storybook&logoColor=white)
7
+ ![ESLint](https://img.shields.io/badge/ESLint-3A33D1?logo=eslint&logoColor=white)
8
+
9
+ ![Smart Edge](./.github/images/example-image.gif)
10
+
11
+ ## Install
12
+
13
+ With `npm`:
14
+
15
+ ```bash
16
+ npm install @tisoap/react-flow-smart-edge
17
+ ```
18
+
19
+ With `yarn`:
20
+
21
+ ```bash
22
+ yarn add @tisoap/react-flow-smart-edge
23
+ ```
24
+
25
+ This package is only compatible with [**version 12** of React Flow Edge](https://reactflow.dev/learn/troubleshooting/migrate-to-v12).
26
+
27
+ ## Support
28
+
29
+ Like this project and want to show your support? Buy me a coffee:
30
+
31
+ [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/J3J472RAJ)
32
+
33
+ _Really_ like this project? Sponsor me on GitHub:
34
+
35
+ [![GitHub Sponsors](https://img.shields.io/static/v1?label=Sponsor%20Me&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/tisoap)
36
+
37
+ ## Usage
38
+
39
+ This package ships with the following Smart Edges components:
40
+
41
+ - `SmartBezierEdge`: A smart equivalent to React Flow's [BezierEdge](https://reactflow.dev/docs/api/edges/edge-types/)
42
+ - `SmartStraightEdge`: A smart equivalent to React Flow's [StraightEdge](https://reactflow.dev/docs/api/edges/edge-types/)
43
+ - `SmartStepEdge`: A smart equivalent to React Flow's [StepEdge](https://reactflow.dev/docs/api/edges/edge-types/)
44
+
45
+ Each one can be imported individually as a named export.
46
+
47
+ ### Example
48
+
49
+ ```jsx
50
+ import React from "react";
51
+ import { ReactFlow } from "reactflow";
52
+ import { SmartBezierEdge } from "@tisoap/react-flow-smart-edge";
53
+ import "@xyflow/react/dist/style.css";
54
+
55
+ const nodes = [
56
+ {
57
+ id: "1",
58
+ data: { label: "Node 1" },
59
+ position: { x: 300, y: 100 },
60
+ },
61
+ {
62
+ id: "2",
63
+ data: { label: "Node 2" },
64
+ position: { x: 300, y: 200 },
65
+ },
66
+ ];
67
+
68
+ const edges = [
69
+ {
70
+ id: "e21",
71
+ source: "2",
72
+ target: "1",
73
+ type: "smart",
74
+ },
75
+ ];
76
+
77
+ // You can give any name to your edge types
78
+ // https://reactflow.dev/docs/api/edges/custom-edges/
79
+ const edgeTypes = {
80
+ smart: SmartBezierEdge,
81
+ };
82
+
83
+ export const Graph = (props) => {
84
+ const { children, ...rest } = props;
85
+
86
+ return (
87
+ <ReactFlow
88
+ defaultNodes={nodes}
89
+ defaultEdges={edges}
90
+ edgeTypes={edgeTypes}
91
+ {...rest}
92
+ >
93
+ {children}
94
+ </ReactFlow>
95
+ );
96
+ };
97
+ ```
98
+
99
+ ## Edge Options
100
+
101
+ All smart edges will take the exact same options as a [React Flow Edge](https://reactflow.dev/docs/api/edges/edge-options/).
102
+
103
+ ## Custom Smart Edges
104
+
105
+ You can have more control over how the edge is rerendered by creating a [custom edge](https://reactflow.dev/docs/api/edges/custom-edges/) and using the provided `getSmartEdge` function. It takes an object with the following keys:
106
+
107
+ - `sourcePosition`, `targetPosition`, `sourceX`, `sourceY`, `targetX` and `targetY`: The same values your [custom edge](https://reactflow.dev/docs/examples/edges/custom-edge/) will take as props
108
+ - `nodes`: An array containing all graph nodes, you can get it from the [`useNodes` hook](https://reactflow.dev/docs/api/hooks/use-nodes/)
109
+
110
+ ### Example
111
+
112
+ Just like you can use `getBezierPath` from `reactflow` to create a [custom edge with a button](https://reactflow.dev/docs/examples/edges/edge-with-button/), you can do the same with `getSmartEdge`:
113
+
114
+ ```jsx
115
+ import React from "react";
116
+ import { useNodes, BezierEdge } from "@xyflow/react";
117
+ import { getSmartEdge } from "@tisoap/react-flow-smart-edge";
118
+
119
+ const foreignObjectSize = 200;
120
+
121
+ export function SmartEdgeWithButtonLabel(props) {
122
+ const {
123
+ id,
124
+ sourcePosition,
125
+ targetPosition,
126
+ sourceX,
127
+ sourceY,
128
+ targetX,
129
+ targetY,
130
+ style,
131
+ markerStart,
132
+ markerEnd,
133
+ } = props;
134
+
135
+ const nodes = useNodes();
136
+
137
+ const getSmartEdgeResponse = getSmartEdge({
138
+ sourcePosition,
139
+ targetPosition,
140
+ sourceX,
141
+ sourceY,
142
+ targetX,
143
+ targetY,
144
+ nodes,
145
+ });
146
+
147
+ // If the value returned is an Error, it means "getSmartEdge" was unable
148
+ // to find a valid path, and you should do something else instead
149
+ if (smartResponse instanceof Error) {
150
+ return <BezierEdge {...props} />;
151
+ }
152
+
153
+ const { edgeCenterX, edgeCenterY, svgPathString } = getSmartEdgeResponse;
154
+
155
+ return (
156
+ <>
157
+ <path
158
+ style={style}
159
+ className="react-flow__edge-path"
160
+ d={svgPathString}
161
+ markerEnd={markerEnd}
162
+ markerStart={markerStart}
163
+ />
164
+ <foreignObject
165
+ width={foreignObjectSize}
166
+ height={foreignObjectSize}
167
+ x={edgeCenterX - foreignObjectSize / 2}
168
+ y={edgeCenterY - foreignObjectSize / 2}
169
+ requiredExtensions="http://www.w3.org/1999/xhtml"
170
+ >
171
+ <button
172
+ onClick={(event) => {
173
+ event.stopPropagation();
174
+ alert(`remove ${id}`);
175
+ }}
176
+ >
177
+ X
178
+ </button>
179
+ </foreignObject>
180
+ </>
181
+ );
182
+ }
183
+ ```
184
+
185
+ ## Advanced Custom Smart Edges
186
+
187
+ The `getSmartEdge` function also accepts an optional object `options`, which allows you to configure aspects of the path-finding algorithm. You may use it like so:
188
+
189
+ ```js
190
+ const myOptions = {
191
+ // your configuration goes here
192
+ nodePadding: 20,
193
+ gridRatio: 15,
194
+ };
195
+
196
+ // ...
197
+
198
+ const getSmartEdgeResponse = getSmartEdge({
199
+ sourcePosition,
200
+ targetPosition,
201
+ sourceX,
202
+ sourceY,
203
+ targetX,
204
+ targetY,
205
+ nodes,
206
+ // Pass down options in the getSmartEdge object
207
+ options: myOptions,
208
+ });
209
+ ```
210
+
211
+ The `options` object accepts the following keys (they're all optional):
212
+
213
+ - `nodePadding`: How many pixels of padding are added around nodes, or by how much should the edge avoid the walls of a node. Default `10`, minimum `2`.
214
+ - `gridRatio`: The size in pixels of each square grid cell used for path-finding. Smaller values for a more accurate path, bigger for faster path-finding. Default `10`, minimum `2`.
215
+ - `drawEdge`: Allows you to change the function responsible to draw the SVG line, by default it's the same used by `SmartBezierEdge` ([more below](#drawedge))
216
+ - `generatePath`: Allows you to change the function for the path-finding, by default it's the same used by `SmartBezierEdge` ([more below](#generatepath))
217
+
218
+ ### `drawEdge`
219
+
220
+ With the `drawEdge` option, you can change the function used to generate the final [SVG path string](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths), used to draw the line. By default it's the `svgDrawSmoothLinePath` function (same as used by the `SmartBezierEdge`), but the package also includes `svgDrawStraightLinePath` (same as used by the `SmartStraightEdge` and `SmartStepEdge`), or you can provide your own.
221
+
222
+ ```jsx
223
+ import {
224
+ getSmartEdge,
225
+ // Available built-in SVG draw functions
226
+ svgDrawSmoothLinePath,
227
+ svgDrawStraightLinePath,
228
+ } from "@tisoap/react-flow-smart-edge";
229
+
230
+ // Using provided SVG draw functions:
231
+ const result = getSmartEdge({
232
+ // ...
233
+ options: {
234
+ drawEdge: svgDrawSmoothLinePath,
235
+ },
236
+ });
237
+
238
+ // ...or using your own custom function
239
+ const result = getSmartEdge({
240
+ // ...
241
+ options: {
242
+ drawEdge: (source, target, path) => {
243
+ // your code goes here
244
+ // ...
245
+ return svgPath;
246
+ },
247
+ },
248
+ });
249
+ ```
250
+
251
+ The function you provided must comply with this signature:
252
+
253
+ ```ts
254
+ type SVGDrawFunction = (
255
+ source: XYPosition, // The starting {x, y} point
256
+ target: XYPosition, // The ending {x, y} point
257
+ path: number[][], // The sequence of points [x, y] the line must follow
258
+ ) => string; // A string to be used in the "d" property of the SVG line
259
+ ```
260
+
261
+ For inspiration on how to implement your own, you can check the [`drawSvgPath.ts` source code](https://github.com/tisoap/react-flow-smart-edge/blob/main/src/functions/drawSvgPath.ts).
262
+
263
+ ### `generatePath`
264
+
265
+ With the `generatePath` option, you can change the function used to do [Pathfinding](https://en.wikipedia.org/wiki/Pathfinding). By default, it's the `pathfindingAStarDiagonal` function (same as used by the `SmartBezierEdge`), but the package also includes `pathfindingAStarNoDiagonal` (used by `SmartStraightEdge` and `SmartStepEdge`), or your can provide your own.
266
+
267
+ ```jsx
268
+ import {
269
+ getSmartEdge,
270
+ // Available built-in pathfinding functions
271
+ pathfindingAStarDiagonal,
272
+ pathfindingAStarNoDiagonal,
273
+ } from "@tisoap/react-flow-smart-edge";
274
+
275
+ // Using provided pathfinding functions:
276
+ const result = getSmartEdge({
277
+ // ...
278
+ options: {
279
+ generatePath: pathfindingAStarDiagonal,
280
+ },
281
+ });
282
+
283
+ // ...or using your own custom function
284
+ const result = getSmartEdge({
285
+ // ...
286
+ options: {
287
+ generatePath: (grid, start, end) => {
288
+ // your code goes here
289
+ // ...
290
+ return { fullPath, smoothedPath };
291
+ },
292
+ },
293
+ });
294
+ ```
295
+
296
+ The function you provide must comply with this signature:
297
+
298
+ ```ts
299
+ type PathFindingFunction = (
300
+ grid: Grid, // Grid representation of the graph
301
+ start: XYPosition, // The starting {x, y} point
302
+ end: XYPosition, // The ending {x, y} point
303
+ ) => number[][]; // Array of points [x, y] representing the full path with all points
304
+ ```
305
+
306
+ For inspiration on how to implement your own, you can check the [`generatePath.ts` source code](https://github.com/tisoap/react-flow-smart-edge/blob/main/src/functions/generatePath.ts).
307
+
308
+ ### Advanced Examples
309
+
310
+ ```jsx
311
+ import {
312
+ getSmartEdge,
313
+ svgDrawSmoothLinePath,
314
+ svgDrawStraightLinePath
315
+ pathfindingAStarDiagonal,
316
+ pathfindingAStarNoDiagonal,
317
+ } from '@tisoap/react-flow-smart-edge'
318
+
319
+ // ...
320
+
321
+ // Same as importing "SmartBezierEdge" directly
322
+ const bezierResult = getSmartEdge({
323
+ // ...
324
+ options: {
325
+ drawEdge: svgDrawSmoothLinePath,
326
+ generatePath: pathfindingAStarDiagonal,
327
+ }
328
+ })
329
+
330
+ // Same as importing "SmartStepEdge" directly
331
+ const stepResult = getSmartEdge({
332
+ // ...
333
+ options: {
334
+ drawEdge: svgDrawStraightLinePath,
335
+ generatePath: pathfindingAStarNoDiagonal,
336
+ }
337
+ })
338
+
339
+ // Same as importing "SmartStraightEdge" directly
340
+ const straightResult = getSmartEdge({
341
+ // ...
342
+ options: {
343
+ drawEdge: svgDrawStraightLinePath,
344
+ generatePath: pathfindingAStarNoDiagonal,
345
+ }
346
+ })
347
+ ```
348
+
349
+ ## Storybook
350
+
351
+ You can see live Storybook examples by visiting [this page](https://tisoap.github.io/react-flow-smart-edge/), and see their source code [here](https://github.com/tisoap/react-flow-smart-edge/blob/main/src/stories/SmartEdge.stories.tsx).
352
+
353
+ ## License
354
+
355
+ This project is [MIT](https://github.com/tisoap/react-flow-smart-edge/blob/main/LICENSE) licensed.
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const A=require("react/jsx-runtime"),P=require("@xyflow/react"),R=require("react"),V=(t,e,n)=>{const o=new Array(e);for(let s=0;s<e;s++){const r=new Array(t);for(let l=0;l<t;l++){const g=!!(n?n[s]?.[l]:void 0),h=n?!g:!0;r[l]={x:l,y:s,walkable:h}}o[s]=r}return o},L=(t,e,n,o)=>n>=0&&n<t&&o>=0&&o<e,z=(t,e,n)=>{const o=V(t,e,n),s=(h,i)=>o[i][h],r=(h,i)=>L(t,e,h,i)&&o[i][h].walkable;return{width:t,height:e,nodes:o,getNodeAt:s,isWalkableAt:r,setWalkableAt:(h,i,a)=>{L(t,e,h,i)&&(o[i][h].walkable=a)},getNeighbors:(h,i)=>{const a=h.x,c=h.y,x=[],S=r(a,c-1),E=r(a+1,c),m=r(a,c+1),M=r(a-1,c);S&&x.push(s(a,c-1)),E&&x.push(s(a+1,c)),m&&x.push(s(a,c+1)),M&&x.push(s(a-1,c));const w=r(a+1,c-1),d=r(a+1,c+1),u=r(a-1,c+1),f=r(a-1,c-1);return i==="Never"||(w&&x.push(s(a+1,c-1)),d&&x.push(s(a+1,c+1)),u&&x.push(s(a-1,c+1)),f&&x.push(s(a-1,c-1))),x},isInside:(h,i)=>L(t,e,h,i),clone:()=>{const h=o.map(i=>i.map(a=>a.walkable?0:1));return z(t,e,h)}}},X=(t,e)=>{switch(e){case"top":return{x:t.x,y:t.y-1};case"bottom":return{x:t.x,y:t.y+1};case"left":return{x:t.x-1,y:t.y};case"right":return{x:t.x+1,y:t.y}}},Y=(t,e,n)=>{let o=t.getNodeAt(e.x,e.y);for(;!o.walkable;){t.setWalkableAt(o.x,o.y,!0);const s=X(o,n);o=t.getNodeAt(s.x,s.y)}},B=(t,e,n,o)=>{const s=(t.x-e)/o+1,r=(t.y-n)/o+1;return{x:s,y:r}},_=(t,e,n,o)=>{const s=(t.x-1)*o+e,r=(t.y-1)*o+n;return{x:s,y:r}},v=(t,e=10)=>Math.round(t/e)*e,k=(t,e=10)=>Math.floor(t/e)*e,N=(t,e=10)=>Math.ceil(t/e)*e,j=(t,e=0)=>{let n=Math.max(Math.round(t),e);return n=Number.isInteger(n)?n:e,n=n>=e?n:e,n},tt=(t,e,n,o,s=2)=>{const{xMin:r,yMin:l,width:y,height:g}=t,h=N(y,s)/s+1,i=N(g,s)/s+1,a=z(h,i);e.forEach(w=>{const d=B(w.topLeft,r,l,s),u=B(w.bottomRight,r,l,s);for(let f=d.x;f<u.x;f++)for(let b=d.y;b<u.y;b++)a.setWalkableAt(f,b,!1)});const c=B({x:v(n.x,s),y:v(n.y,s)},r,l,s),x=B({x:v(o.x,s),y:v(o.y,s)},r,l,s),S=a.getNodeAt(c.x,c.y);Y(a,S,n.position);const E=a.getNodeAt(x.x,x.y);Y(a,E,o.position);const m=X(S,n.position),M=X(E,o.position);return{grid:a,start:m,end:M}},F=(t,e,n)=>{let o=`M ${String(t.x)}, ${String(t.y)} `;return n.forEach(s=>{const[r,l]=s;o+=`L ${String(r)}, ${String(l)} `}),o+=`L ${String(e.x)}, ${String(e.y)} `,o},I=(t,e,n)=>{const o=[[t.x,t.y],...n,[e.x,e.y]];return et(o)},et=t=>{let o=t[0];const s=t[0];let r=`M${String(s[0])},${String(s[1])}M`;for(const y of t){const g=nt(o[0],o[1],y[0],y[1]);r+=` ${String(g[0])},${String(g[1])}`,r+=`Q${String(y[0])},${String(y[1])}`,o=y}const l=t[t.length-1];return r+=` ${String(l[0])},${String(l[1])}`,r},nt=(t,e,n,o)=>{const s=(t-n)/2+n,r=(e-o)/2+o;return[s,r]},ot=(t,e)=>t+e,st=(t,e)=>{const n=Math.SQRT2-1;return t<e?n*t+e:n*e+t},rt=t=>{const e=[];let n=t;for(;n;)e.push([n.x,n.y]),n=n.parent;return e.reverse()},at=t=>t==="Never"?ot:st,ct=t=>{let e=0;for(let n=1;n<t.length;n++)(t[n].estimatedTotalCost??1/0)<(t[e].estimatedTotalCost??1/0)&&(e=n);return t.splice(e,1)[0]},it=(t,e,n,o,s,r)=>{if(t.closed)return;const l=Math.abs(t.x-e.x),y=Math.abs(t.y-e.y),g=(e.costFromStart??0)+(l===0||y===0?1:Math.SQRT2);(!t.opened||g<(t.costFromStart??1/0))&&(t.costFromStart=g,t.heuristicCostToGoal=t.heuristicCostToGoal??r*s(Math.abs(t.x-n.x),Math.abs(t.y-n.y)),t.estimatedTotalCost=(t.costFromStart??0)+(t.heuristicCostToGoal??0),t.parent=e,t.opened||(t.opened=!0,o.push(t)))},T=(t={})=>{const e=t.diagonalMovement??"Never",n=t.heuristic??at(e),o=t.weight??1;return{findPath:(r,l,y,g,h)=>{const i=h.getNodeAt(r,l),a=h.getNodeAt(y,g),c=[];for(i.costFromStart=0,i.heuristicCostToGoal=0,i.estimatedTotalCost=0,i.opened=!0,c.push(i);c.length>0;){const x=ct(c);if(x.closed=!0,x===a)return rt(a);const S=h.getNeighbors(x,e);for(const E of S)it(E,x,a,c,n,o)}return[]}}},C=(t,e,n)=>{try{const s=T({diagonalMovement:"Always"}).findPath(e.x,e.y,n.x,n.y,t);if(s.length===0)throw new Error("No path found");return s}catch(o){throw o instanceof Error?o:new Error(`Unknown error: ${String(o)}`)}},q=(t,e,n)=>{try{const s=T({diagonalMovement:"Never"}).findPath(e.x,e.y,n.x,n.y,t);if(s.length===0)throw new Error("No path found");return s}catch(o){throw o instanceof Error?o:new Error(`Unknown error: ${String(o)}`)}},lt=(t,e=2,n=2)=>{let o=Number.MIN_SAFE_INTEGER,s=Number.MIN_SAFE_INTEGER,r=Number.MAX_SAFE_INTEGER,l=Number.MAX_SAFE_INTEGER;const y=t.map(m=>{const M=Math.max(m.measured?.width??0,1),w=Math.max(m.measured?.height??0,1),d={x:m.position.x,y:m.position.y},u={x:d.x-e,y:d.y-e},f={x:d.x-e,y:d.y+w+e},b={x:d.x+M+e,y:d.y-e},p={x:d.x+M+e,y:d.y+w+e};return n>0&&(u.x=k(u.x,n),u.y=k(u.y,n),f.x=k(f.x,n),f.y=N(f.y,n),b.x=N(b.x,n),b.y=k(b.y,n),p.x=N(p.x,n),p.y=N(p.y,n)),u.y<l&&(l=u.y),u.x<r&&(r=u.x),p.y>s&&(s=p.y),p.x>o&&(o=p.x),{id:m.id,width:M,height:w,topLeft:u,bottomLeft:f,topRight:b,bottomRight:p}}),g=e*2;o=N(o+g,n),s=N(s+g,n),r=k(r-g,n),l=k(l-g,n);const h={x:r,y:l},i={x:r,y:s},a={x:o,y:l},c={x:o,y:s},x=Math.abs(h.x-a.x),S=Math.abs(h.y-i.y);return{nodeBoxes:y,graphBox:{topLeft:h,bottomLeft:i,topRight:a,bottomRight:c,width:x,height:S,xMax:o,yMax:s,xMin:r,yMin:l}}},U=({options:t={},nodes:e=[],sourceX:n,sourceY:o,targetX:s,targetY:r,sourcePosition:l,targetPosition:y})=>{try{const{drawEdge:g=I,generatePath:h=C}=t;let{gridRatio:i=10,nodePadding:a=10}=t;i=j(i),a=j(a);const{graphBox:c,nodeBoxes:x}=lt(e,a,i);t.debug?.enabled&&t.debug.setGraphBox&&t.debug.setGraphBox({x:c.topLeft.x,y:c.topLeft.y,width:c.width,height:c.height});const S={x:n,y:o,position:l},E={x:s,y:r,position:y},{grid:m,start:M,end:w}=tt(c,x,S,E,i),u=h(m,M,w),f=u.map(O=>{const[J,K]=O,W=_({x:J,y:K},c.xMin,c.yMin,i);return[W.x,W.y]}),b=g(S,E,f),p=Math.floor(u.length/2),G=u[p],[$,Q]=G,{x:Z,y:H}=_({x:$,y:Q},c.xMin,c.yMin,i);return{svgPathString:b,edgeCenterX:Z,edgeCenterY:H}}catch(g){return g instanceof Error?g:new Error(`Unknown error: ${String(g)}`)}},ht=R.createContext({enabled:!1,graphBox:null,setGraphBox:()=>{}}),gt=()=>R.useContext(ht);function D({nodes:t,options:e,...n}){const{enabled:o,setGraphBox:s}=gt(),{sourceX:r,sourceY:l,sourcePosition:y,targetX:g,targetY:h,targetPosition:i,style:a,label:c,labelStyle:x,labelShowBg:S,labelBgStyle:E,labelBgPadding:m,labelBgBorderRadius:M,markerEnd:w,markerStart:d,interactionWidth:u}=n,f=U({sourcePosition:y,targetPosition:i,sourceX:r,sourceY:l,targetX:g,targetY:h,options:{...e,debug:{enabled:o,setGraphBox:s}},nodes:t}),b=e.fallback??P.BezierEdge;if(f instanceof Error)return o&&console.error(f),A.jsx(b,{...n});const{edgeCenterX:p,edgeCenterY:G,svgPathString:$}=f;return A.jsx(P.BaseEdge,{path:$,labelX:p,labelY:G,label:c,labelStyle:x,labelShowBg:S,labelBgStyle:E,labelBgPadding:m,labelBgBorderRadius:M,style:a,markerStart:d,markerEnd:w,interactionWidth:u})}const xt={drawEdge:I,generatePath:C,fallback:P.BezierEdge};function ut(t){const e=P.useNodes();return A.jsx(D,{...t,options:xt,nodes:e})}const yt={drawEdge:F,generatePath:C,fallback:P.StraightEdge};function ft(t){const e=P.useNodes();return A.jsx(D,{...t,options:yt,nodes:e})}const dt={drawEdge:F,generatePath:q,fallback:P.StepEdge};function St(t){const e=P.useNodes();return A.jsx(D,{...t,options:dt,nodes:e})}exports.SmartBezierEdge=ut;exports.SmartStepEdge=St;exports.SmartStraightEdge=ft;exports.getSmartEdge=U;exports.pathfindingAStarDiagonal=C;exports.pathfindingAStarNoDiagonal=q;exports.svgDrawSmoothLinePath=I;exports.svgDrawStraightLinePath=F;
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"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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"}
@@ -0,0 +1,100 @@
1
+ import { Edge } from '@xyflow/react';
2
+ import { EdgeProps } from '@xyflow/react';
3
+ import { JSX } from 'react/jsx-runtime';
4
+ import { Node as Node_2 } from '@xyflow/react';
5
+ import { XYPosition } from '@xyflow/react';
6
+
7
+ declare type DiagonalMovement = "Always" | "Never";
8
+
9
+ declare type EdgeParams = Pick<EdgeProps, "sourceX" | "sourceY" | "targetX" | "targetY" | "sourcePosition" | "targetPosition">;
10
+
11
+ export declare const getSmartEdge: <NodeDataType extends Record<string, unknown> = Record<string, unknown>>({ options, nodes, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, }: GetSmartEdgeParams<NodeDataType>) => GetSmartEdgeReturn | Error;
12
+
13
+ export declare interface GetSmartEdgeOptions {
14
+ gridRatio?: number;
15
+ nodePadding?: number;
16
+ drawEdge?: SVGDrawFunction;
17
+ generatePath?: PathFindingFunction;
18
+ debug?: {
19
+ enabled?: boolean;
20
+ setGraphBox?: (box: {
21
+ x: number;
22
+ y: number;
23
+ width: number;
24
+ height: number;
25
+ }) => void;
26
+ };
27
+ }
28
+
29
+ declare type GetSmartEdgeParams<NodeDataType extends Record<string, unknown> = Record<string, unknown>> = EdgeParams & {
30
+ options?: GetSmartEdgeOptions;
31
+ nodes: Node_2<NodeDataType>[];
32
+ };
33
+
34
+ declare interface GetSmartEdgeReturn {
35
+ svgPathString: string;
36
+ edgeCenterX: number;
37
+ edgeCenterY: number;
38
+ }
39
+
40
+ export declare interface Grid {
41
+ width: number;
42
+ height: number;
43
+ nodes: GridNode[][];
44
+ getNodeAt: (x: number, y: number) => GridNode;
45
+ isWalkableAt: (x: number, y: number) => boolean;
46
+ setWalkableAt: (x: number, y: number, walkable: boolean) => void;
47
+ getNeighbors: (node: GridNode, diagonalMovement: DiagonalMovement) => GridNode[];
48
+ isInside: (x: number, y: number) => boolean;
49
+ clone: () => Grid;
50
+ }
51
+
52
+ export declare interface GridNode {
53
+ x: number;
54
+ y: number;
55
+ walkable: boolean;
56
+ costFromStart?: number;
57
+ heuristicCostToGoal?: number;
58
+ estimatedTotalCost?: number;
59
+ opened?: boolean;
60
+ closed?: boolean;
61
+ parent?: GridNode;
62
+ }
63
+
64
+ export declare const pathfindingAStarDiagonal: PathFindingFunction;
65
+
66
+ export declare const pathfindingAStarNoDiagonal: PathFindingFunction;
67
+
68
+ /**
69
+ * Takes source and target {x, y} points, together with an grid representation
70
+ * of the graph, and returns an array of number tuples [x, y], representing
71
+ * the full path from source to target.
72
+ */
73
+ export declare type PathFindingFunction = (grid: Grid, start: XYPosition, end: XYPosition) => number[][];
74
+
75
+ export declare function SmartBezierEdge<EdgeType extends Edge = Edge, NodeType extends Node_2 = Node_2>(props: EdgeProps<EdgeType>): JSX.Element;
76
+
77
+ export declare function SmartStepEdge<EdgeType extends Edge = Edge, NodeType extends Node_2 = Node_2>(props: EdgeProps<EdgeType>): JSX.Element;
78
+
79
+ export declare function SmartStraightEdge<EdgeType extends Edge = Edge, NodeType extends Node_2 = Node_2>(props: EdgeProps<EdgeType>): JSX.Element;
80
+
81
+ /**
82
+ * Takes source and target {x, y} points, together with an array of number
83
+ * tuples [x, y] representing the points along the path, and returns a string
84
+ * to be used as the SVG path.
85
+ */
86
+ export declare type SVGDrawFunction = (source: XYPosition, target: XYPosition, path: number[][]) => string;
87
+
88
+ /**
89
+ * Draws a SVG path from a list of points, using rounded lines.
90
+ */
91
+ export declare const svgDrawSmoothLinePath: SVGDrawFunction;
92
+
93
+ /**
94
+ * Draws a SVG path from a list of points, using straight lines.
95
+ */
96
+ export declare const svgDrawStraightLinePath: SVGDrawFunction;
97
+
98
+ export { XYPosition }
99
+
100
+ export { }