@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 +21 -0
- package/README.md +355 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.mjs +409 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +108 -0
- package/src/SmartBezierEdge/index.tsx +26 -0
- package/src/SmartEdge/index.tsx +92 -0
- package/src/SmartStepEdge/index.tsx +29 -0
- package/src/SmartStraightEdge/index.tsx +29 -0
- package/src/functions/createGrid.ts +81 -0
- package/src/functions/drawSvgPath.ts +72 -0
- package/src/functions/generatePath.ts +60 -0
- package/src/functions/getBoundingBoxes.ts +138 -0
- package/src/functions/guaranteeWalkablePath.ts +38 -0
- package/src/functions/index.ts +7 -0
- package/src/functions/pointConversion.ts +49 -0
- package/src/functions/utils.ts +15 -0
- package/src/getSmartEdge/index.ts +160 -0
- package/src/index.tsx +18 -0
- package/src/internal/SmartEdgeDebug.tsx +43 -0
- package/src/internal/SmartEdgeDebugOverlay.tsx +24 -0
- package/src/internal/useSmartEdgeDebug.ts +26 -0
- package/src/pathfinding/aStar.ts +134 -0
- package/src/pathfinding/grid.ts +141 -0
- package/src/pathfinding/types.ts +3 -0
- package/src/stories/CustomLabel.tsx +94 -0
- package/src/stories/DummyData.ts +194 -0
- package/src/stories/GraphWrapper.tsx +23 -0
- package/src/stories/SmartEdge.stories.tsx +67 -0
- package/src/vite-env.d.ts +1 -0
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
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
9
|
+

|
|
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
|
+
[](https://ko-fi.com/J3J472RAJ)
|
|
32
|
+
|
|
33
|
+
_Really_ like this project? Sponsor me on GitHub:
|
|
34
|
+
|
|
35
|
+
[](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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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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 { }
|