@knotx/render 0.4.11 → 0.4.13
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/README.en.md +584 -0
- package/README.md +584 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +7 -7
package/README.en.md
ADDED
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
# @knotx/render
|
|
2
|
+
|
|
3
|
+
A React component library providing edge rendering capabilities for the Knotx graph editor.
|
|
4
|
+
|
|
5
|
+
## 📦 Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @knotx/render
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
yarn add @knotx/render
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add @knotx/render
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 🚀 Overview
|
|
20
|
+
|
|
21
|
+
`@knotx/render` is a rendering layer component library in the Knotx ecosystem, specifically designed for rendering edges (connections) in graph editors. It provides multiple edge types (straight lines, Bezier curves) and rich customization options, supporting arrow markers, labels, style customization, and more.
|
|
22
|
+
|
|
23
|
+
### Key Features
|
|
24
|
+
|
|
25
|
+
- 🎨 **Multiple Edge Types**: Support for straight lines, Bezier curves, and other connection types
|
|
26
|
+
- 🎯 **Arrow Markers**: Built-in arrow marker styles with support for custom markers
|
|
27
|
+
- 🏷️ **Label Support**: Add text labels to edges
|
|
28
|
+
- 🎛️ **Highly Customizable**: Support for styles, colors, widths, and various property customizations
|
|
29
|
+
- 🔧 **Extensible**: Based on abstract path builder design for easy extension of new edge types
|
|
30
|
+
- ⚡ **Performance Optimized**: SVG rendering with interaction area optimization
|
|
31
|
+
|
|
32
|
+
## 📋 API Documentation
|
|
33
|
+
|
|
34
|
+
### Components
|
|
35
|
+
|
|
36
|
+
#### `BaseEdge<TPathBuilderContext>`
|
|
37
|
+
|
|
38
|
+
Base edge component that serves as the foundation for all other edge components.
|
|
39
|
+
|
|
40
|
+
**Props**
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
interface BaseEdgeProps<TPathBuilderContext = void> extends EdgeProps {
|
|
44
|
+
className?: string // Custom CSS class name
|
|
45
|
+
style?: Record<string, any> // Custom style object
|
|
46
|
+
interactionWidth?: number // Interaction area width, default 20
|
|
47
|
+
label?: string // Edge label text
|
|
48
|
+
markerEnd?: string | MarkerProps // End marker
|
|
49
|
+
markerStart?: string | MarkerProps // Start marker
|
|
50
|
+
pathBuilder: PathBuilderType<any, TPathBuilderContext> // Path builder
|
|
51
|
+
context: TPathBuilderContext // Path builder context
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Usage Example**
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { BaseEdge, StraightPathBuilder } from '@knotx/render'
|
|
59
|
+
|
|
60
|
+
function CustomEdge() {
|
|
61
|
+
return (
|
|
62
|
+
<BaseEdge
|
|
63
|
+
sourceX={0}
|
|
64
|
+
sourceY={0}
|
|
65
|
+
targetX={100}
|
|
66
|
+
targetY={100}
|
|
67
|
+
pathBuilder={StraightPathBuilder}
|
|
68
|
+
context={undefined}
|
|
69
|
+
label="Connection"
|
|
70
|
+
style={{ stroke: '#1890ff', strokeWidth: 2 }}
|
|
71
|
+
/>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
#### `BezierEdge`
|
|
77
|
+
|
|
78
|
+
Bezier curve edge component, suitable for smooth curve connections.
|
|
79
|
+
|
|
80
|
+
**Props**
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
interface BezierEdgeProps extends Omit<BaseEdgeProps, 'pathBuilder' | 'context'> {}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Usage Example**
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
import { BezierEdge, getArrowMarker } from '@knotx/render'
|
|
90
|
+
|
|
91
|
+
function CurvedConnection() {
|
|
92
|
+
const arrowMarker = getArrowMarker('#ff4d4f')
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<BezierEdge
|
|
96
|
+
sourceX={50}
|
|
97
|
+
sourceY={50}
|
|
98
|
+
targetX={250}
|
|
99
|
+
targetY={150}
|
|
100
|
+
markerEnd={arrowMarker}
|
|
101
|
+
style={{ stroke: '#ff4d4f', strokeWidth: 2 }}
|
|
102
|
+
label="Bezier Curve"
|
|
103
|
+
/>
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
#### `StraightEdge`
|
|
109
|
+
|
|
110
|
+
Straight line edge component for simple direct connections.
|
|
111
|
+
|
|
112
|
+
**Props**
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
interface StraightEdgeProps extends Omit<BaseEdgeProps, 'pathBuilder' | 'context'> {}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Usage Example**
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
import { getArrowClosedMarker, StraightEdge } from '@knotx/render'
|
|
122
|
+
|
|
123
|
+
function DirectConnection() {
|
|
124
|
+
const arrowMarker = getArrowClosedMarker('#52c41a')
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<StraightEdge
|
|
128
|
+
sourceX={0}
|
|
129
|
+
sourceY={0}
|
|
130
|
+
targetX={200}
|
|
131
|
+
targetY={100}
|
|
132
|
+
markerEnd={arrowMarker}
|
|
133
|
+
markerStart={arrowMarker}
|
|
134
|
+
style={{ stroke: '#52c41a', strokeWidth: 3 }}
|
|
135
|
+
interactionWidth={30}
|
|
136
|
+
/>
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### `MarkerDefinitions`
|
|
142
|
+
|
|
143
|
+
Marker definition component for centralized marker management and reuse.
|
|
144
|
+
|
|
145
|
+
**Props**
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
interface MarkerDefinitionsProps {
|
|
149
|
+
markers: MarkerProps[]
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Usage Example**
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
import { getArrowClosedMarker, getArrowMarker, MarkerDefinitions } from '@knotx/render'
|
|
157
|
+
|
|
158
|
+
function EdgeContainer() {
|
|
159
|
+
const markers = [
|
|
160
|
+
getArrowMarker('#1890ff'),
|
|
161
|
+
getArrowClosedMarker('#ff4d4f'),
|
|
162
|
+
getArrowMarker('#52c41a')
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<svg>
|
|
167
|
+
<MarkerDefinitions markers={markers} />
|
|
168
|
+
{/* Your edge components */}
|
|
169
|
+
</svg>
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Path Builders
|
|
175
|
+
|
|
176
|
+
#### `PathBuilder<TType, TContext>`
|
|
177
|
+
|
|
178
|
+
Abstract path builder base class for creating custom edge types.
|
|
179
|
+
|
|
180
|
+
**Abstract Methods**
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
abstract class PathBuilder<TType extends string, TContext = never> {
|
|
184
|
+
constructor(
|
|
185
|
+
readonly sourceX: number,
|
|
186
|
+
readonly sourceY: number,
|
|
187
|
+
readonly targetX: number,
|
|
188
|
+
readonly targetY: number
|
|
189
|
+
) {}
|
|
190
|
+
|
|
191
|
+
abstract type: TType
|
|
192
|
+
abstract buildPath(context: TContext): string
|
|
193
|
+
abstract interpolate(t: number, context: TContext): { x: number, y: number }
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Custom Path Builder Example**
|
|
198
|
+
|
|
199
|
+
```tsx
|
|
200
|
+
class CustomPathBuilder extends PathBuilder<'custom'> {
|
|
201
|
+
type = 'custom' as const
|
|
202
|
+
|
|
203
|
+
buildPath(): string {
|
|
204
|
+
// Create custom SVG path
|
|
205
|
+
const midX = (this.sourceX + this.targetX) / 2
|
|
206
|
+
const midY = (this.sourceY + this.targetY) / 2
|
|
207
|
+
|
|
208
|
+
return `M ${this.sourceX} ${this.sourceY}
|
|
209
|
+
Q ${midX} ${midY - 50} ${this.targetX} ${this.targetY}`
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
interpolate(t: number): { x: number, y: number } {
|
|
213
|
+
// Implement path point interpolation
|
|
214
|
+
const x = this.sourceX + t * (this.targetX - this.sourceX)
|
|
215
|
+
const y = this.sourceY + t * (this.targetY - this.sourceY)
|
|
216
|
+
return { x, y }
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
#### `StraightPathBuilder`
|
|
222
|
+
|
|
223
|
+
Straight line path builder that generates straight line paths.
|
|
224
|
+
|
|
225
|
+
```tsx
|
|
226
|
+
class StraightPathBuilder extends PathBuilder<'straight'> {
|
|
227
|
+
type = 'straight' as const
|
|
228
|
+
buildPath(): string
|
|
229
|
+
interpolate(t: number): { x: number, y: number }
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
#### `BezierPathBuilder`
|
|
234
|
+
|
|
235
|
+
Bezier curve path builder that generates smooth curve paths.
|
|
236
|
+
|
|
237
|
+
```tsx
|
|
238
|
+
class BezierPathBuilder extends PathBuilder<'bezier'> {
|
|
239
|
+
type = 'bezier' as const
|
|
240
|
+
buildPath(): string
|
|
241
|
+
interpolate(t: number): { x: number, y: number }
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Marker Utility Functions
|
|
246
|
+
|
|
247
|
+
#### `getArrowMarker(color?: string)`
|
|
248
|
+
|
|
249
|
+
Create a standard arrow marker.
|
|
250
|
+
|
|
251
|
+
**Parameters**
|
|
252
|
+
- `color` (optional): Marker color, defaults to `currentColor`
|
|
253
|
+
|
|
254
|
+
**Returns**
|
|
255
|
+
- `MarkerProps`: Arrow marker configuration object
|
|
256
|
+
|
|
257
|
+
**Usage Example**
|
|
258
|
+
|
|
259
|
+
```tsx
|
|
260
|
+
import { getArrowMarker, StraightEdge } from '@knotx/render'
|
|
261
|
+
|
|
262
|
+
function EdgeWithArrow() {
|
|
263
|
+
const marker = getArrowMarker('#1890ff')
|
|
264
|
+
|
|
265
|
+
return (
|
|
266
|
+
<StraightEdge
|
|
267
|
+
sourceX={0}
|
|
268
|
+
sourceY={0}
|
|
269
|
+
targetX={100}
|
|
270
|
+
targetY={100}
|
|
271
|
+
markerEnd={marker}
|
|
272
|
+
/>
|
|
273
|
+
)
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
#### `getArrowClosedMarker(color?: string)`
|
|
278
|
+
|
|
279
|
+
Create a closed (filled) arrow marker.
|
|
280
|
+
|
|
281
|
+
**Parameters**
|
|
282
|
+
- `color` (optional): Marker color, defaults to `currentColor`
|
|
283
|
+
|
|
284
|
+
**Returns**
|
|
285
|
+
- `MarkerProps`: Closed arrow marker configuration object
|
|
286
|
+
|
|
287
|
+
**Usage Example**
|
|
288
|
+
|
|
289
|
+
```tsx
|
|
290
|
+
import { BezierEdge, getArrowClosedMarker } from '@knotx/render'
|
|
291
|
+
|
|
292
|
+
function EdgeWithClosedArrow() {
|
|
293
|
+
const marker = getArrowClosedMarker('#ff4d4f')
|
|
294
|
+
|
|
295
|
+
return (
|
|
296
|
+
<BezierEdge
|
|
297
|
+
sourceX={50}
|
|
298
|
+
sourceY={50}
|
|
299
|
+
targetX={200}
|
|
300
|
+
targetY={150}
|
|
301
|
+
markerEnd={marker}
|
|
302
|
+
style={{ stroke: '#ff4d4f' }}
|
|
303
|
+
/>
|
|
304
|
+
)
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
#### `getCustomMarker(type: string, options?: Partial<MarkerProps>)`
|
|
309
|
+
|
|
310
|
+
Create a custom marker.
|
|
311
|
+
|
|
312
|
+
**Parameters**
|
|
313
|
+
- `type`: Marker type identifier
|
|
314
|
+
- `options` (optional): Custom marker options
|
|
315
|
+
|
|
316
|
+
**Returns**
|
|
317
|
+
- `MarkerProps`: Custom marker configuration object
|
|
318
|
+
|
|
319
|
+
**Usage Example**
|
|
320
|
+
|
|
321
|
+
```tsx
|
|
322
|
+
import { BaseEdge, getCustomMarker, StraightPathBuilder } from '@knotx/render'
|
|
323
|
+
|
|
324
|
+
function EdgeWithCustomMarker() {
|
|
325
|
+
const marker = getCustomMarker('diamond', {
|
|
326
|
+
color: '#722ed1',
|
|
327
|
+
width: 12,
|
|
328
|
+
height: 12,
|
|
329
|
+
strokeWidth: 2
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
return (
|
|
333
|
+
<BaseEdge
|
|
334
|
+
sourceX={0}
|
|
335
|
+
sourceY={0}
|
|
336
|
+
targetX={150}
|
|
337
|
+
targetY={100}
|
|
338
|
+
pathBuilder={StraightPathBuilder}
|
|
339
|
+
context={undefined}
|
|
340
|
+
markerEnd={marker}
|
|
341
|
+
/>
|
|
342
|
+
)
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
#### `getArrowHeadMarkers(color?: string)`
|
|
347
|
+
|
|
348
|
+
Create two closed arrows as start and end markers.
|
|
349
|
+
|
|
350
|
+
**Parameters**
|
|
351
|
+
- `color` (optional): Marker color
|
|
352
|
+
|
|
353
|
+
**Returns**
|
|
354
|
+
- Object containing `markerStart` and `markerEnd`
|
|
355
|
+
|
|
356
|
+
**Usage Example**
|
|
357
|
+
|
|
358
|
+
```tsx
|
|
359
|
+
import { getArrowHeadMarkers, StraightEdge } from '@knotx/render'
|
|
360
|
+
|
|
361
|
+
function DoubleArrowEdge() {
|
|
362
|
+
const { markerStart, markerEnd } = getArrowHeadMarkers('#13c2c2')
|
|
363
|
+
|
|
364
|
+
return (
|
|
365
|
+
<StraightEdge
|
|
366
|
+
sourceX={0}
|
|
367
|
+
sourceY={0}
|
|
368
|
+
targetX={200}
|
|
369
|
+
targetY={100}
|
|
370
|
+
markerStart={markerStart}
|
|
371
|
+
markerEnd={markerEnd}
|
|
372
|
+
style={{ stroke: '#13c2c2', strokeWidth: 2 }}
|
|
373
|
+
/>
|
|
374
|
+
)
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Type Definitions
|
|
379
|
+
|
|
380
|
+
#### `MarkerType`
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
enum MarkerType {
|
|
384
|
+
Arrow = 'arrow',
|
|
385
|
+
ArrowClosed = 'arrowclosed'
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
#### `MarkerProps`
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
interface MarkerProps {
|
|
393
|
+
id: string // Unique marker identifier
|
|
394
|
+
type: MarkerType | string // Marker type
|
|
395
|
+
color?: string // Marker color
|
|
396
|
+
width?: number // Marker width
|
|
397
|
+
height?: number // Marker height
|
|
398
|
+
markerUnits?: string // Marker units
|
|
399
|
+
orient?: string // Marker orientation
|
|
400
|
+
strokeWidth?: number // Stroke width
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
#### `PathBuilderType`
|
|
405
|
+
|
|
406
|
+
```tsx
|
|
407
|
+
type PathBuilderType<T extends string = any, TContext = void> =
|
|
408
|
+
new (...args: ConstructorParameters<typeof PathBuilder<T, TContext>>) =>
|
|
409
|
+
PathBuilder<T, TContext>
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
## 🗂️ Directory Structure
|
|
413
|
+
|
|
414
|
+
```
|
|
415
|
+
packages/render/
|
|
416
|
+
├── src/
|
|
417
|
+
│ ├── edges/
|
|
418
|
+
│ │ ├── base-edge.tsx # Base edge component
|
|
419
|
+
│ │ ├── bezier.tsx # Bezier curve edge
|
|
420
|
+
│ │ ├── straight.tsx # Straight line edge
|
|
421
|
+
│ │ ├── markers.tsx # Marker-related functionality
|
|
422
|
+
│ │ ├── path-builder.ts # Path builders
|
|
423
|
+
│ │ └── index.ts # Edge module exports
|
|
424
|
+
│ └── index.ts # Main entry point
|
|
425
|
+
├── dist/ # Build output directory
|
|
426
|
+
├── package.json # Package configuration
|
|
427
|
+
├── tsconfig.json # TypeScript configuration
|
|
428
|
+
├── build.config.ts # Build configuration
|
|
429
|
+
└── README.md # Documentation
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## 🎯 Complete Usage Examples
|
|
433
|
+
|
|
434
|
+
### Basic Usage
|
|
435
|
+
|
|
436
|
+
```tsx
|
|
437
|
+
import {
|
|
438
|
+
BezierEdge,
|
|
439
|
+
getArrowClosedMarker,
|
|
440
|
+
getArrowMarker,
|
|
441
|
+
StraightEdge
|
|
442
|
+
} from '@knotx/render'
|
|
443
|
+
import React from 'react'
|
|
444
|
+
|
|
445
|
+
function GraphEditor() {
|
|
446
|
+
return (
|
|
447
|
+
<div style={{ position: 'relative', width: 800, height: 600 }}>
|
|
448
|
+
{/* Straight line connection */}
|
|
449
|
+
<StraightEdge
|
|
450
|
+
sourceX={50}
|
|
451
|
+
sourceY={50}
|
|
452
|
+
targetX={200}
|
|
453
|
+
targetY={100}
|
|
454
|
+
markerEnd={getArrowMarker('#1890ff')}
|
|
455
|
+
style={{ stroke: '#1890ff', strokeWidth: 2 }}
|
|
456
|
+
label="Straight Connection"
|
|
457
|
+
/>
|
|
458
|
+
|
|
459
|
+
{/* Bezier curve connection */}
|
|
460
|
+
<BezierEdge
|
|
461
|
+
sourceX={50}
|
|
462
|
+
sourceY={150}
|
|
463
|
+
targetX={250}
|
|
464
|
+
targetY={200}
|
|
465
|
+
markerEnd={getArrowClosedMarker('#ff4d4f')}
|
|
466
|
+
style={{ stroke: '#ff4d4f', strokeWidth: 2 }}
|
|
467
|
+
label="Curved Connection"
|
|
468
|
+
/>
|
|
469
|
+
</div>
|
|
470
|
+
)
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### Custom Edge Types
|
|
475
|
+
|
|
476
|
+
```tsx
|
|
477
|
+
import { BaseEdge, PathBuilder } from '@knotx/render'
|
|
478
|
+
|
|
479
|
+
// Create custom path builder
|
|
480
|
+
class StepPathBuilder extends PathBuilder<'step'> {
|
|
481
|
+
type = 'step' as const
|
|
482
|
+
|
|
483
|
+
buildPath(): string {
|
|
484
|
+
const midX = (this.sourceX + this.targetX) / 2
|
|
485
|
+
return `M ${this.sourceX} ${this.sourceY}
|
|
486
|
+
L ${midX} ${this.sourceY}
|
|
487
|
+
L ${midX} ${this.targetY}
|
|
488
|
+
L ${this.targetX} ${this.targetY}`
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
interpolate(t: number): { x: number, y: number } {
|
|
492
|
+
const midX = (this.sourceX + this.targetX) / 2
|
|
493
|
+
|
|
494
|
+
if (t <= 0.33) {
|
|
495
|
+
const localT = t / 0.33
|
|
496
|
+
return {
|
|
497
|
+
x: this.sourceX + localT * (midX - this.sourceX),
|
|
498
|
+
y: this.sourceY
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
else if (t <= 0.66) {
|
|
502
|
+
const localT = (t - 0.33) / 0.33
|
|
503
|
+
return {
|
|
504
|
+
x: midX,
|
|
505
|
+
y: this.sourceY + localT * (this.targetY - this.sourceY)
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
else {
|
|
509
|
+
const localT = (t - 0.66) / 0.34
|
|
510
|
+
return {
|
|
511
|
+
x: midX + localT * (this.targetX - midX),
|
|
512
|
+
y: this.targetY
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Use custom path builder
|
|
519
|
+
function StepEdge(props: Omit<BaseEdgeProps, 'pathBuilder' | 'context'>) {
|
|
520
|
+
return (
|
|
521
|
+
<BaseEdge
|
|
522
|
+
{...props}
|
|
523
|
+
pathBuilder={StepPathBuilder}
|
|
524
|
+
context={undefined}
|
|
525
|
+
/>
|
|
526
|
+
)
|
|
527
|
+
}
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### Advanced Marker Management
|
|
531
|
+
|
|
532
|
+
```tsx
|
|
533
|
+
import { getArrowMarker, getCustomMarker, MarkerDefinitions } from '@knotx/render'
|
|
534
|
+
|
|
535
|
+
function AdvancedGraph() {
|
|
536
|
+
// Pre-define markers
|
|
537
|
+
const markers = [
|
|
538
|
+
getArrowMarker('#1890ff'),
|
|
539
|
+
getArrowMarker('#ff4d4f'),
|
|
540
|
+
getCustomMarker('circle', {
|
|
541
|
+
color: '#52c41a',
|
|
542
|
+
width: 8,
|
|
543
|
+
height: 8
|
|
544
|
+
})
|
|
545
|
+
]
|
|
546
|
+
|
|
547
|
+
return (
|
|
548
|
+
<svg width="800" height="600">
|
|
549
|
+
<MarkerDefinitions markers={markers} />
|
|
550
|
+
|
|
551
|
+
{/* Use predefined markers */}
|
|
552
|
+
<StraightEdge
|
|
553
|
+
sourceX={100}
|
|
554
|
+
sourceY={100}
|
|
555
|
+
targetX={300}
|
|
556
|
+
targetY={200}
|
|
557
|
+
markerEnd={markers[0]}
|
|
558
|
+
style={{ stroke: '#1890ff' }}
|
|
559
|
+
/>
|
|
560
|
+
|
|
561
|
+
<BezierEdge
|
|
562
|
+
sourceX={100}
|
|
563
|
+
sourceY={200}
|
|
564
|
+
targetX={400}
|
|
565
|
+
targetY={150}
|
|
566
|
+
markerEnd={markers[1]}
|
|
567
|
+
style={{ stroke: '#ff4d4f' }}
|
|
568
|
+
/>
|
|
569
|
+
</svg>
|
|
570
|
+
)
|
|
571
|
+
}
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
## 📄 License
|
|
575
|
+
|
|
576
|
+
MIT
|
|
577
|
+
|
|
578
|
+
## 🤝 Contributing
|
|
579
|
+
|
|
580
|
+
Issues and pull requests are welcome. See [CONTRIBUTING.md](../../CONTRIBUTING.md) for details.
|
|
581
|
+
|
|
582
|
+
## 📞 Support
|
|
583
|
+
|
|
584
|
+
If you encounter any issues or need help, please submit an issue on [GitHub Issues](https://github.com/boenfu/knotx/issues).
|
package/README.md
ADDED
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
# @knotx/render
|
|
2
|
+
|
|
3
|
+
一个专为 Knotx 图形编辑器提供边缘(Edge)渲染功能的 React 组件库。
|
|
4
|
+
|
|
5
|
+
## 📦 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @knotx/render
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
yarn add @knotx/render
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add @knotx/render
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 🚀 基本概述
|
|
20
|
+
|
|
21
|
+
`@knotx/render` 是 Knotx 生态系统中的渲染层组件库,专门用于渲染图形编辑器中的边缘(连接线)。它提供了多种边缘类型(直线、贝塞尔曲线)和丰富的自定义选项,支持箭头标记、标签、样式定制等功能。
|
|
22
|
+
|
|
23
|
+
### 主要特性
|
|
24
|
+
|
|
25
|
+
- 🎨 **多种边缘类型**: 支持直线、贝塞尔曲线等多种连接线类型
|
|
26
|
+
- 🎯 **箭头标记**: 内置多种箭头标记样式,支持自定义标记
|
|
27
|
+
- 🏷️ **标签支持**: 支持在边缘上添加文本标签
|
|
28
|
+
- 🎛️ **高度可定制**: 支持样式、颜色、宽度等各种属性自定义
|
|
29
|
+
- 🔧 **扩展性强**: 基于抽象路径构建器设计,可轻松扩展新的边缘类型
|
|
30
|
+
- ⚡ **性能优化**: 采用 SVG 渲染,支持交互区域优化
|
|
31
|
+
|
|
32
|
+
## 📋 API 文档
|
|
33
|
+
|
|
34
|
+
### 组件
|
|
35
|
+
|
|
36
|
+
#### `BaseEdge<TPathBuilderContext>`
|
|
37
|
+
|
|
38
|
+
基础边缘组件,所有其他边缘组件的基础。
|
|
39
|
+
|
|
40
|
+
**Props**
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
interface BaseEdgeProps<TPathBuilderContext = void> extends EdgeProps {
|
|
44
|
+
className?: string // 自定义 CSS 类名
|
|
45
|
+
style?: Record<string, any> // 自定义样式对象
|
|
46
|
+
interactionWidth?: number // 交互区域宽度,默认 20
|
|
47
|
+
label?: string // 边缘标签文本
|
|
48
|
+
markerEnd?: string | MarkerProps // 终点标记
|
|
49
|
+
markerStart?: string | MarkerProps // 起点标记
|
|
50
|
+
pathBuilder: PathBuilderType<any, TPathBuilderContext> // 路径构建器
|
|
51
|
+
context: TPathBuilderContext // 路径构建器上下文
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**使用示例**
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { BaseEdge, StraightPathBuilder } from '@knotx/render'
|
|
59
|
+
|
|
60
|
+
function CustomEdge() {
|
|
61
|
+
return (
|
|
62
|
+
<BaseEdge
|
|
63
|
+
sourceX={0}
|
|
64
|
+
sourceY={0}
|
|
65
|
+
targetX={100}
|
|
66
|
+
targetY={100}
|
|
67
|
+
pathBuilder={StraightPathBuilder}
|
|
68
|
+
context={undefined}
|
|
69
|
+
label="连接线"
|
|
70
|
+
style={{ stroke: '#1890ff', strokeWidth: 2 }}
|
|
71
|
+
/>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
#### `BezierEdge`
|
|
77
|
+
|
|
78
|
+
贝塞尔曲线边缘组件,适用于需要平滑曲线连接的场景。
|
|
79
|
+
|
|
80
|
+
**Props**
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
interface BezierEdgeProps extends Omit<BaseEdgeProps, 'pathBuilder' | 'context'> {}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**使用示例**
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
import { BezierEdge, getArrowMarker } from '@knotx/render'
|
|
90
|
+
|
|
91
|
+
function CurvedConnection() {
|
|
92
|
+
const arrowMarker = getArrowMarker('#ff4d4f')
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<BezierEdge
|
|
96
|
+
sourceX={50}
|
|
97
|
+
sourceY={50}
|
|
98
|
+
targetX={250}
|
|
99
|
+
targetY={150}
|
|
100
|
+
markerEnd={arrowMarker}
|
|
101
|
+
style={{ stroke: '#ff4d4f', strokeWidth: 2 }}
|
|
102
|
+
label="贝塞尔曲线"
|
|
103
|
+
/>
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
#### `StraightEdge`
|
|
109
|
+
|
|
110
|
+
直线边缘组件,适用于简单的直线连接。
|
|
111
|
+
|
|
112
|
+
**Props**
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
interface StraightEdgeProps extends Omit<BaseEdgeProps, 'pathBuilder' | 'context'> {}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**使用示例**
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
import { getArrowClosedMarker, StraightEdge } from '@knotx/render'
|
|
122
|
+
|
|
123
|
+
function DirectConnection() {
|
|
124
|
+
const arrowMarker = getArrowClosedMarker('#52c41a')
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<StraightEdge
|
|
128
|
+
sourceX={0}
|
|
129
|
+
sourceY={0}
|
|
130
|
+
targetX={200}
|
|
131
|
+
targetY={100}
|
|
132
|
+
markerEnd={arrowMarker}
|
|
133
|
+
markerStart={arrowMarker}
|
|
134
|
+
style={{ stroke: '#52c41a', strokeWidth: 3 }}
|
|
135
|
+
interactionWidth={30}
|
|
136
|
+
/>
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### `MarkerDefinitions`
|
|
142
|
+
|
|
143
|
+
标记定义组件,用于集中管理和重用标记。
|
|
144
|
+
|
|
145
|
+
**Props**
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
interface MarkerDefinitionsProps {
|
|
149
|
+
markers: MarkerProps[]
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**使用示例**
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
import { getArrowClosedMarker, getArrowMarker, MarkerDefinitions } from '@knotx/render'
|
|
157
|
+
|
|
158
|
+
function EdgeContainer() {
|
|
159
|
+
const markers = [
|
|
160
|
+
getArrowMarker('#1890ff'),
|
|
161
|
+
getArrowClosedMarker('#ff4d4f'),
|
|
162
|
+
getArrowMarker('#52c41a')
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<svg>
|
|
167
|
+
<MarkerDefinitions markers={markers} />
|
|
168
|
+
{/* 你的边缘组件 */}
|
|
169
|
+
</svg>
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### 路径构建器
|
|
175
|
+
|
|
176
|
+
#### `PathBuilder<TType, TContext>`
|
|
177
|
+
|
|
178
|
+
抽象路径构建器基类,用于创建自定义边缘类型。
|
|
179
|
+
|
|
180
|
+
**抽象方法**
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
abstract class PathBuilder<TType extends string, TContext = never> {
|
|
184
|
+
constructor(
|
|
185
|
+
readonly sourceX: number,
|
|
186
|
+
readonly sourceY: number,
|
|
187
|
+
readonly targetX: number,
|
|
188
|
+
readonly targetY: number
|
|
189
|
+
) {}
|
|
190
|
+
|
|
191
|
+
abstract type: TType
|
|
192
|
+
abstract buildPath(context: TContext): string
|
|
193
|
+
abstract interpolate(t: number, context: TContext): { x: number, y: number }
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**创建自定义路径构建器示例**
|
|
198
|
+
|
|
199
|
+
```tsx
|
|
200
|
+
class CustomPathBuilder extends PathBuilder<'custom'> {
|
|
201
|
+
type = 'custom' as const
|
|
202
|
+
|
|
203
|
+
buildPath(): string {
|
|
204
|
+
// 创建自定义的 SVG 路径
|
|
205
|
+
const midX = (this.sourceX + this.targetX) / 2
|
|
206
|
+
const midY = (this.sourceY + this.targetY) / 2
|
|
207
|
+
|
|
208
|
+
return `M ${this.sourceX} ${this.sourceY}
|
|
209
|
+
Q ${midX} ${midY - 50} ${this.targetX} ${this.targetY}`
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
interpolate(t: number): { x: number, y: number } {
|
|
213
|
+
// 实现路径上点的插值计算
|
|
214
|
+
const x = this.sourceX + t * (this.targetX - this.sourceX)
|
|
215
|
+
const y = this.sourceY + t * (this.targetY - this.sourceY)
|
|
216
|
+
return { x, y }
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
#### `StraightPathBuilder`
|
|
222
|
+
|
|
223
|
+
直线路径构建器,生成直线路径。
|
|
224
|
+
|
|
225
|
+
```tsx
|
|
226
|
+
class StraightPathBuilder extends PathBuilder<'straight'> {
|
|
227
|
+
type = 'straight' as const
|
|
228
|
+
buildPath(): string
|
|
229
|
+
interpolate(t: number): { x: number, y: number }
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
#### `BezierPathBuilder`
|
|
234
|
+
|
|
235
|
+
贝塞尔曲线路径构建器,生成平滑的曲线路径。
|
|
236
|
+
|
|
237
|
+
```tsx
|
|
238
|
+
class BezierPathBuilder extends PathBuilder<'bezier'> {
|
|
239
|
+
type = 'bezier' as const
|
|
240
|
+
buildPath(): string
|
|
241
|
+
interpolate(t: number): { x: number, y: number }
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### 标记工具函数
|
|
246
|
+
|
|
247
|
+
#### `getArrowMarker(color?: string)`
|
|
248
|
+
|
|
249
|
+
创建标准箭头标记。
|
|
250
|
+
|
|
251
|
+
**参数**
|
|
252
|
+
- `color` (可选): 标记颜色,默认为 `currentColor`
|
|
253
|
+
|
|
254
|
+
**返回值**
|
|
255
|
+
- `MarkerProps`: 箭头标记配置对象
|
|
256
|
+
|
|
257
|
+
**使用示例**
|
|
258
|
+
|
|
259
|
+
```tsx
|
|
260
|
+
import { getArrowMarker, StraightEdge } from '@knotx/render'
|
|
261
|
+
|
|
262
|
+
function EdgeWithArrow() {
|
|
263
|
+
const marker = getArrowMarker('#1890ff')
|
|
264
|
+
|
|
265
|
+
return (
|
|
266
|
+
<StraightEdge
|
|
267
|
+
sourceX={0}
|
|
268
|
+
sourceY={0}
|
|
269
|
+
targetX={100}
|
|
270
|
+
targetY={100}
|
|
271
|
+
markerEnd={marker}
|
|
272
|
+
/>
|
|
273
|
+
)
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
#### `getArrowClosedMarker(color?: string)`
|
|
278
|
+
|
|
279
|
+
创建实心箭头标记。
|
|
280
|
+
|
|
281
|
+
**参数**
|
|
282
|
+
- `color` (可选): 标记颜色,默认为 `currentColor`
|
|
283
|
+
|
|
284
|
+
**返回值**
|
|
285
|
+
- `MarkerProps`: 实心箭头标记配置对象
|
|
286
|
+
|
|
287
|
+
**使用示例**
|
|
288
|
+
|
|
289
|
+
```tsx
|
|
290
|
+
import { BezierEdge, getArrowClosedMarker } from '@knotx/render'
|
|
291
|
+
|
|
292
|
+
function EdgeWithClosedArrow() {
|
|
293
|
+
const marker = getArrowClosedMarker('#ff4d4f')
|
|
294
|
+
|
|
295
|
+
return (
|
|
296
|
+
<BezierEdge
|
|
297
|
+
sourceX={50}
|
|
298
|
+
sourceY={50}
|
|
299
|
+
targetX={200}
|
|
300
|
+
targetY={150}
|
|
301
|
+
markerEnd={marker}
|
|
302
|
+
style={{ stroke: '#ff4d4f' }}
|
|
303
|
+
/>
|
|
304
|
+
)
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
#### `getCustomMarker(type: string, options?: Partial<MarkerProps>)`
|
|
309
|
+
|
|
310
|
+
创建自定义标记。
|
|
311
|
+
|
|
312
|
+
**参数**
|
|
313
|
+
- `type`: 标记类型标识符
|
|
314
|
+
- `options` (可选): 自定义标记选项
|
|
315
|
+
|
|
316
|
+
**返回值**
|
|
317
|
+
- `MarkerProps`: 自定义标记配置对象
|
|
318
|
+
|
|
319
|
+
**使用示例**
|
|
320
|
+
|
|
321
|
+
```tsx
|
|
322
|
+
import { BaseEdge, getCustomMarker, StraightPathBuilder } from '@knotx/render'
|
|
323
|
+
|
|
324
|
+
function EdgeWithCustomMarker() {
|
|
325
|
+
const marker = getCustomMarker('diamond', {
|
|
326
|
+
color: '#722ed1',
|
|
327
|
+
width: 12,
|
|
328
|
+
height: 12,
|
|
329
|
+
strokeWidth: 2
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
return (
|
|
333
|
+
<BaseEdge
|
|
334
|
+
sourceX={0}
|
|
335
|
+
sourceY={0}
|
|
336
|
+
targetX={150}
|
|
337
|
+
targetY={100}
|
|
338
|
+
pathBuilder={StraightPathBuilder}
|
|
339
|
+
context={undefined}
|
|
340
|
+
markerEnd={marker}
|
|
341
|
+
/>
|
|
342
|
+
)
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
#### `getArrowHeadMarkers(color?: string)`
|
|
347
|
+
|
|
348
|
+
创建两个实心箭头作为起点和终点的标记。
|
|
349
|
+
|
|
350
|
+
**参数**
|
|
351
|
+
- `color` (可选): 标记颜色
|
|
352
|
+
|
|
353
|
+
**返回值**
|
|
354
|
+
- 包含 `markerStart` 和 `markerEnd` 的对象
|
|
355
|
+
|
|
356
|
+
**使用示例**
|
|
357
|
+
|
|
358
|
+
```tsx
|
|
359
|
+
import { getArrowHeadMarkers, StraightEdge } from '@knotx/render'
|
|
360
|
+
|
|
361
|
+
function DoubleArrowEdge() {
|
|
362
|
+
const { markerStart, markerEnd } = getArrowHeadMarkers('#13c2c2')
|
|
363
|
+
|
|
364
|
+
return (
|
|
365
|
+
<StraightEdge
|
|
366
|
+
sourceX={0}
|
|
367
|
+
sourceY={0}
|
|
368
|
+
targetX={200}
|
|
369
|
+
targetY={100}
|
|
370
|
+
markerStart={markerStart}
|
|
371
|
+
markerEnd={markerEnd}
|
|
372
|
+
style={{ stroke: '#13c2c2', strokeWidth: 2 }}
|
|
373
|
+
/>
|
|
374
|
+
)
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### 类型定义
|
|
379
|
+
|
|
380
|
+
#### `MarkerType`
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
enum MarkerType {
|
|
384
|
+
Arrow = 'arrow',
|
|
385
|
+
ArrowClosed = 'arrowclosed'
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
#### `MarkerProps`
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
interface MarkerProps {
|
|
393
|
+
id: string // 标记唯一标识符
|
|
394
|
+
type: MarkerType | string // 标记类型
|
|
395
|
+
color?: string // 标记颜色
|
|
396
|
+
width?: number // 标记宽度
|
|
397
|
+
height?: number // 标记高度
|
|
398
|
+
markerUnits?: string // 标记单位
|
|
399
|
+
orient?: string // 标记方向
|
|
400
|
+
strokeWidth?: number // 描边宽度
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
#### `PathBuilderType`
|
|
405
|
+
|
|
406
|
+
```tsx
|
|
407
|
+
type PathBuilderType<T extends string = any, TContext = void> =
|
|
408
|
+
new (...args: ConstructorParameters<typeof PathBuilder<T, TContext>>) =>
|
|
409
|
+
PathBuilder<T, TContext>
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
## 🗂️ 文件目录结构
|
|
413
|
+
|
|
414
|
+
```
|
|
415
|
+
packages/render/
|
|
416
|
+
├── src/
|
|
417
|
+
│ ├── edges/
|
|
418
|
+
│ │ ├── base-edge.tsx # 基础边缘组件
|
|
419
|
+
│ │ ├── bezier.tsx # 贝塞尔曲线边缘
|
|
420
|
+
│ │ ├── straight.tsx # 直线边缘
|
|
421
|
+
│ │ ├── markers.tsx # 标记相关功能
|
|
422
|
+
│ │ ├── path-builder.ts # 路径构建器
|
|
423
|
+
│ │ └── index.ts # 边缘模块导出
|
|
424
|
+
│ └── index.ts # 主入口文件
|
|
425
|
+
├── dist/ # 构建输出目录
|
|
426
|
+
├── package.json # 包配置文件
|
|
427
|
+
├── tsconfig.json # TypeScript 配置
|
|
428
|
+
├── build.config.ts # 构建配置
|
|
429
|
+
└── README.md # 文档文件
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## 🎯 完整使用示例
|
|
433
|
+
|
|
434
|
+
### 基础使用
|
|
435
|
+
|
|
436
|
+
```tsx
|
|
437
|
+
import {
|
|
438
|
+
BezierEdge,
|
|
439
|
+
getArrowClosedMarker,
|
|
440
|
+
getArrowMarker,
|
|
441
|
+
StraightEdge
|
|
442
|
+
} from '@knotx/render'
|
|
443
|
+
import React from 'react'
|
|
444
|
+
|
|
445
|
+
function GraphEditor() {
|
|
446
|
+
return (
|
|
447
|
+
<div style={{ position: 'relative', width: 800, height: 600 }}>
|
|
448
|
+
{/* 直线连接 */}
|
|
449
|
+
<StraightEdge
|
|
450
|
+
sourceX={50}
|
|
451
|
+
sourceY={50}
|
|
452
|
+
targetX={200}
|
|
453
|
+
targetY={100}
|
|
454
|
+
markerEnd={getArrowMarker('#1890ff')}
|
|
455
|
+
style={{ stroke: '#1890ff', strokeWidth: 2 }}
|
|
456
|
+
label="直线连接"
|
|
457
|
+
/>
|
|
458
|
+
|
|
459
|
+
{/* 贝塞尔曲线连接 */}
|
|
460
|
+
<BezierEdge
|
|
461
|
+
sourceX={50}
|
|
462
|
+
sourceY={150}
|
|
463
|
+
targetX={250}
|
|
464
|
+
targetY={200}
|
|
465
|
+
markerEnd={getArrowClosedMarker('#ff4d4f')}
|
|
466
|
+
style={{ stroke: '#ff4d4f', strokeWidth: 2 }}
|
|
467
|
+
label="曲线连接"
|
|
468
|
+
/>
|
|
469
|
+
</div>
|
|
470
|
+
)
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### 自定义边缘类型
|
|
475
|
+
|
|
476
|
+
```tsx
|
|
477
|
+
import { BaseEdge, PathBuilder } from '@knotx/render'
|
|
478
|
+
|
|
479
|
+
// 创建自定义路径构建器
|
|
480
|
+
class StepPathBuilder extends PathBuilder<'step'> {
|
|
481
|
+
type = 'step' as const
|
|
482
|
+
|
|
483
|
+
buildPath(): string {
|
|
484
|
+
const midX = (this.sourceX + this.targetX) / 2
|
|
485
|
+
return `M ${this.sourceX} ${this.sourceY}
|
|
486
|
+
L ${midX} ${this.sourceY}
|
|
487
|
+
L ${midX} ${this.targetY}
|
|
488
|
+
L ${this.targetX} ${this.targetY}`
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
interpolate(t: number): { x: number, y: number } {
|
|
492
|
+
const midX = (this.sourceX + this.targetX) / 2
|
|
493
|
+
|
|
494
|
+
if (t <= 0.33) {
|
|
495
|
+
const localT = t / 0.33
|
|
496
|
+
return {
|
|
497
|
+
x: this.sourceX + localT * (midX - this.sourceX),
|
|
498
|
+
y: this.sourceY
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
else if (t <= 0.66) {
|
|
502
|
+
const localT = (t - 0.33) / 0.33
|
|
503
|
+
return {
|
|
504
|
+
x: midX,
|
|
505
|
+
y: this.sourceY + localT * (this.targetY - this.sourceY)
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
else {
|
|
509
|
+
const localT = (t - 0.66) / 0.34
|
|
510
|
+
return {
|
|
511
|
+
x: midX + localT * (this.targetX - midX),
|
|
512
|
+
y: this.targetY
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// 使用自定义路径构建器
|
|
519
|
+
function StepEdge(props: Omit<BaseEdgeProps, 'pathBuilder' | 'context'>) {
|
|
520
|
+
return (
|
|
521
|
+
<BaseEdge
|
|
522
|
+
{...props}
|
|
523
|
+
pathBuilder={StepPathBuilder}
|
|
524
|
+
context={undefined}
|
|
525
|
+
/>
|
|
526
|
+
)
|
|
527
|
+
}
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### 高级标记管理
|
|
531
|
+
|
|
532
|
+
```tsx
|
|
533
|
+
import { getArrowMarker, getCustomMarker, MarkerDefinitions } from '@knotx/render'
|
|
534
|
+
|
|
535
|
+
function AdvancedGraph() {
|
|
536
|
+
// 预定义标记
|
|
537
|
+
const markers = [
|
|
538
|
+
getArrowMarker('#1890ff'),
|
|
539
|
+
getArrowMarker('#ff4d4f'),
|
|
540
|
+
getCustomMarker('circle', {
|
|
541
|
+
color: '#52c41a',
|
|
542
|
+
width: 8,
|
|
543
|
+
height: 8
|
|
544
|
+
})
|
|
545
|
+
]
|
|
546
|
+
|
|
547
|
+
return (
|
|
548
|
+
<svg width="800" height="600">
|
|
549
|
+
<MarkerDefinitions markers={markers} />
|
|
550
|
+
|
|
551
|
+
{/* 使用预定义标记 */}
|
|
552
|
+
<StraightEdge
|
|
553
|
+
sourceX={100}
|
|
554
|
+
sourceY={100}
|
|
555
|
+
targetX={300}
|
|
556
|
+
targetY={200}
|
|
557
|
+
markerEnd={markers[0]}
|
|
558
|
+
style={{ stroke: '#1890ff' }}
|
|
559
|
+
/>
|
|
560
|
+
|
|
561
|
+
<BezierEdge
|
|
562
|
+
sourceX={100}
|
|
563
|
+
sourceY={200}
|
|
564
|
+
targetX={400}
|
|
565
|
+
targetY={150}
|
|
566
|
+
markerEnd={markers[1]}
|
|
567
|
+
style={{ stroke: '#ff4d4f' }}
|
|
568
|
+
/>
|
|
569
|
+
</svg>
|
|
570
|
+
)
|
|
571
|
+
}
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
## 📄 许可证
|
|
575
|
+
|
|
576
|
+
MIT
|
|
577
|
+
|
|
578
|
+
## 🤝 贡献
|
|
579
|
+
|
|
580
|
+
欢迎提交问题和拉取请求。详见 [CONTRIBUTING.md](../../CONTRIBUTING.md)
|
|
581
|
+
|
|
582
|
+
## 📞 支持
|
|
583
|
+
|
|
584
|
+
如果您遇到任何问题或需要帮助,请在 [GitHub Issues](https://github.com/boenfu/knotx/issues) 中提交问题。
|
package/dist/index.cjs
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knotx/render",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.13",
|
|
4
4
|
"description": "Render for Knotx",
|
|
5
5
|
"author": "boenfu",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,18 +28,18 @@
|
|
|
28
28
|
"dist"
|
|
29
29
|
],
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"@knotx/jsx": "0.4.
|
|
31
|
+
"@knotx/jsx": "0.4.13"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"bezier-js": "^6.1.4",
|
|
35
|
-
"@knotx/core": "0.4.
|
|
35
|
+
"@knotx/core": "0.4.13"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/bezier-js": "^4.1.3",
|
|
39
|
-
"@knotx/
|
|
40
|
-
"@knotx/
|
|
41
|
-
"@knotx/jsx": "0.4.
|
|
42
|
-
"@knotx/typescript-config": "0.4.
|
|
39
|
+
"@knotx/build-config": "0.4.13",
|
|
40
|
+
"@knotx/eslint-config": "0.4.13",
|
|
41
|
+
"@knotx/jsx": "0.4.13",
|
|
42
|
+
"@knotx/typescript-config": "0.4.13"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
45
|
"build": "unbuild",
|