cactuz 0.0.9 → 0.1.1
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.md +152 -140
- package/dist/components/CactusTree.svelte +173 -31
- package/dist/components/CactusTree.svelte.d.ts +188 -101
- package/dist/components/cactusTree/drawEdge.d.ts +2 -1
- package/dist/components/cactusTree/drawEdge.js +118 -26
- package/dist/components/cactusTree/drawLabel.d.ts +89 -56
- package/dist/components/cactusTree/drawLabel.js +420 -240
- package/dist/components/cactusTree/drawNode.d.ts +63 -53
- package/dist/components/cactusTree/drawNode.js +261 -110
- package/dist/components/cactusTree/labelPositions.d.ts +15 -3
- package/dist/components/cactusTree/labelPositions.js +142 -19
- package/dist/components/cactusTree/layoutUtils.js +2 -25
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -46,6 +46,8 @@ npm install cactuz
|
|
|
46
46
|
<CactusTree width={800} height={600} {nodes} {links} />
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
---
|
|
50
|
+
|
|
49
51
|
## API Reference
|
|
50
52
|
|
|
51
53
|
### CactusTree Component
|
|
@@ -53,7 +55,7 @@ npm install cactuz
|
|
|
53
55
|
#### Props
|
|
54
56
|
|
|
55
57
|
| Prop | Type | Required | Default | Description |
|
|
56
|
-
| ---------- | ---------
|
|
58
|
+
| ---------- | --------- |:--------:|:-------:| ---------------------------------- |
|
|
57
59
|
| `width` | `number` | yes | - | Canvas width in pixels |
|
|
58
60
|
| `height` | `number` | yes | - | Canvas height in pixels |
|
|
59
61
|
| `nodes` | `Node[]` | yes | - | Array of hierarchical nodes |
|
|
@@ -69,7 +71,7 @@ npm install cactuz
|
|
|
69
71
|
interface Node {
|
|
70
72
|
id: string; // Unique identifier
|
|
71
73
|
name: string; // Display name
|
|
72
|
-
parent: string | null; // Parent node ID
|
|
74
|
+
parent: string | null; // Parent node ID
|
|
73
75
|
weight?: number; // Optional explicit weight
|
|
74
76
|
}
|
|
75
77
|
```
|
|
@@ -91,90 +93,107 @@ interface Options {
|
|
|
91
93
|
arcSpan?: number; // Arc span in radians (default: 5π/4)
|
|
92
94
|
sizeGrowthRate?: number; // Size growth rate (default: 0.75)
|
|
93
95
|
orientation?: number; // Root orientation in radians (default: π/2)
|
|
94
|
-
zoom?: number; //
|
|
96
|
+
zoom?: number; // Layout zoom factor (default: 1.0)
|
|
97
|
+
numLabels?: number; // Number of labels (default: 30)
|
|
95
98
|
}
|
|
96
99
|
```
|
|
97
100
|
|
|
101
|
+
**Note:** Negative values create gaps and connect nodes with links.
|
|
102
|
+
|
|
98
103
|
#### Styles
|
|
99
104
|
|
|
105
|
+
The `styles` prop is a nested object with optional groups and an optional `depths` array containing per-depth overrides. Per-depth overrides take precedence over global group values.
|
|
106
|
+
|
|
100
107
|
```typescript
|
|
101
108
|
interface Styles {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
109
|
+
node?: {
|
|
110
|
+
fillColor?: string;
|
|
111
|
+
fillOpacity?: number;
|
|
112
|
+
strokeColor?: string;
|
|
113
|
+
strokeOpacity?: number;
|
|
114
|
+
strokeWidth?: number;
|
|
115
|
+
highlight?: {
|
|
116
|
+
fillColor?: string;
|
|
117
|
+
fillOpacity?: number;
|
|
118
|
+
strokeColor?: string;
|
|
119
|
+
strokeOpacity?: number;
|
|
120
|
+
strokeWidth?: number;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
edge?: {
|
|
124
|
+
strokeColor?: string;
|
|
125
|
+
strokeOpacity?: number;
|
|
126
|
+
strokeWidth?: number;
|
|
127
|
+
highlight?: {
|
|
128
|
+
strokeColor?: string;
|
|
129
|
+
strokeOpacity?: number;
|
|
130
|
+
strokeWidth?: number;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
label?: {
|
|
134
|
+
textColor?: string;
|
|
135
|
+
textOpacity?: number;
|
|
136
|
+
fontFamily?: string;
|
|
137
|
+
minFontSize?: number;
|
|
138
|
+
maxFontSize?: number;
|
|
139
|
+
fontWeight?: string;
|
|
140
|
+
padding?: number;
|
|
141
|
+
link?: {
|
|
142
|
+
strokeColor?: string;
|
|
143
|
+
strokeOpacity?: number;
|
|
144
|
+
strokeWidth?: number;
|
|
145
|
+
padding?: number;
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
line?: {
|
|
149
|
+
strokeColor?: string;
|
|
150
|
+
strokeOpacity?: number;
|
|
151
|
+
strokeWidth?: number;
|
|
152
|
+
};
|
|
153
|
+
depths?: DepthStyle[]; // Per-depth overrides
|
|
137
154
|
}
|
|
138
155
|
```
|
|
139
156
|
|
|
140
157
|
#### Depth-Specific Styling
|
|
141
158
|
|
|
159
|
+
Each item in `styles.depths` must include a `depth` integer.
|
|
160
|
+
|
|
142
161
|
```typescript
|
|
143
162
|
interface DepthStyle {
|
|
144
|
-
depth: number; //
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
163
|
+
depth: number; // 0 = root, positive = deeper levels, negative values may be used for leaf-oriented overrides (implementation uses mapping for negative depths)
|
|
164
|
+
node?: {
|
|
165
|
+
fillColor?: string;
|
|
166
|
+
fillOpacity?: number;
|
|
167
|
+
strokeColor?: string;
|
|
168
|
+
strokeOpacity?: number;
|
|
169
|
+
strokeWidth?: number;
|
|
170
|
+
};
|
|
171
|
+
label?: {
|
|
172
|
+
textColor?: string;
|
|
173
|
+
textOpacity?: number;
|
|
174
|
+
fontFamily?: string;
|
|
175
|
+
minFontSize?: number;
|
|
176
|
+
maxFontSize?: number;
|
|
177
|
+
fontWeight?: string;
|
|
178
|
+
padding?: number;
|
|
179
|
+
link?: {
|
|
180
|
+
strokeColor?: string;
|
|
181
|
+
strokeOpacity?: number;
|
|
182
|
+
strokeWidth?: number;
|
|
183
|
+
padding?: number;
|
|
184
|
+
};
|
|
185
|
+
};
|
|
186
|
+
line?: {
|
|
187
|
+
strokeColor?: string;
|
|
188
|
+
strokeOpacity?: number;
|
|
189
|
+
strokeWidth?: number;
|
|
190
|
+
};
|
|
157
191
|
}
|
|
158
192
|
```
|
|
159
193
|
|
|
160
194
|
### CactusLayout Class
|
|
161
195
|
|
|
162
|
-
For
|
|
163
|
-
|
|
164
|
-
```javascript
|
|
165
|
-
import { CactusLayout } from 'cactuz';
|
|
166
|
-
|
|
167
|
-
const layout = new CactusLayout(
|
|
168
|
-
800, // width
|
|
169
|
-
600, // height
|
|
170
|
-
1.0, // zoom
|
|
171
|
-
0.5, // overlap
|
|
172
|
-
Math.PI, // arcSpan
|
|
173
|
-
0.75, // sizeGrowthRate
|
|
174
|
-
);
|
|
175
|
-
|
|
176
|
-
const nodeData = layout.render(nodes, 400, 300, -Math.PI / 2);
|
|
177
|
-
```
|
|
196
|
+
For non-Svelte usage you can use the layout algorithm directly.
|
|
178
197
|
|
|
179
198
|
#### Constructor
|
|
180
199
|
|
|
@@ -222,103 +241,97 @@ interface NodeData {
|
|
|
222
241
|
}
|
|
223
242
|
```
|
|
224
243
|
|
|
244
|
+
```javascript
|
|
245
|
+
import { CactusLayout } from 'cactuz';
|
|
246
|
+
|
|
247
|
+
const layout = new CactusLayout(
|
|
248
|
+
800, // width
|
|
249
|
+
600, // height
|
|
250
|
+
1.0, // zoom
|
|
251
|
+
0.5, // overlap
|
|
252
|
+
Math.PI, // arcSpan
|
|
253
|
+
0.75, // sizeGrowthRate
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
const nodeData = layout.render(nodes, 400, 300, -Math.PI / 2);
|
|
257
|
+
```
|
|
258
|
+
|
|
225
259
|
## Advanced Usage
|
|
226
260
|
|
|
227
|
-
###
|
|
261
|
+
### Global and Depth-based Styling Example
|
|
262
|
+
|
|
263
|
+
This example demonstrates styles and per-depth overrides. It shows a global style for general appearance, then customizes roots and leaves via `depths`.
|
|
228
264
|
|
|
229
265
|
```svelte
|
|
230
266
|
<script>
|
|
231
267
|
import { CactusTree } from 'cactuz';
|
|
232
268
|
|
|
233
269
|
const styles = {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
270
|
+
node: {
|
|
271
|
+
fillColor: '#f0f8ff',
|
|
272
|
+
strokeColor: '#4682b4',
|
|
273
|
+
strokeWidth: 2,
|
|
274
|
+
},
|
|
275
|
+
edge: {
|
|
276
|
+
strokeColor: '#e74c3c',
|
|
277
|
+
strokeOpacity: 0.2,
|
|
278
|
+
strokeWidth: 2,
|
|
279
|
+
},
|
|
280
|
+
label: {
|
|
281
|
+
textColor: '#2c3e50',
|
|
282
|
+
textOpacity: 1,
|
|
283
|
+
fontFamily: 'Arial, sans-serif',
|
|
284
|
+
minFontSize: 8,
|
|
285
|
+
maxFontSize: 16,
|
|
286
|
+
padding: 2,
|
|
287
|
+
link: {
|
|
288
|
+
strokeColor: '#aaaaaa',
|
|
289
|
+
strokeOpacity: 1,
|
|
290
|
+
strokeWidth: 0.6,
|
|
291
|
+
padding: 1,
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
line: {
|
|
295
|
+
strokeColor: '#cccccc',
|
|
296
|
+
strokeOpacity: 1,
|
|
297
|
+
strokeWidth: 1,
|
|
298
|
+
},
|
|
299
|
+
node: {
|
|
300
|
+
highlight: {
|
|
301
|
+
fillColor: '#ffd700',
|
|
302
|
+
strokeColor: '#ff8c00',
|
|
303
|
+
},
|
|
304
|
+
},
|
|
244
305
|
depths: [
|
|
245
306
|
{
|
|
246
|
-
depth: 0, //
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
label: '#ecf0f1',
|
|
307
|
+
depth: 0, // root
|
|
308
|
+
node: { fillColor: '#2c3e50', strokeColor: '#ecf0f1' },
|
|
309
|
+
label: { textColor: '#ecf0f1' },
|
|
250
310
|
},
|
|
251
311
|
{
|
|
252
|
-
depth: -1, //
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
label: '#2c3e50',
|
|
312
|
+
depth: -1, // leaves
|
|
313
|
+
node: { fillColor: '#e74c3c', strokeColor: '#c0392b' },
|
|
314
|
+
label: { textColor: '#ffffff' },
|
|
256
315
|
},
|
|
257
316
|
],
|
|
258
317
|
};
|
|
259
318
|
</script>
|
|
260
319
|
|
|
261
|
-
<CactusTree {
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
### Interactive Features
|
|
265
|
-
|
|
266
|
-
The component provides several interactive features:
|
|
267
|
-
|
|
268
|
-
- **Pan**: Click and drag to pan the visualization
|
|
269
|
-
- **Zoom**: Use mouse wheel to zoom in/out
|
|
270
|
-
- **Hover**: Hover over nodes to highlight connections
|
|
271
|
-
|
|
272
|
-
## Examples
|
|
273
|
-
|
|
274
|
-
### Basic Tree
|
|
275
|
-
|
|
276
|
-
```svelte
|
|
277
|
-
<CactusTree
|
|
278
|
-
width={600}
|
|
279
|
-
height={400}
|
|
280
|
-
nodes={[
|
|
281
|
-
{ id: 'a', name: 'Root', parent: null },
|
|
282
|
-
{ id: 'b', name: 'Branch 1', parent: 'a' },
|
|
283
|
-
{ id: 'c', name: 'Branch 2', parent: 'a' },
|
|
284
|
-
{ id: 'd', name: 'Leaf 1', parent: 'b' },
|
|
285
|
-
{ id: 'e', name: 'Leaf 2', parent: 'b' },
|
|
286
|
-
]}
|
|
287
|
-
/>
|
|
320
|
+
<CactusTree width={800} height={600} {nodes} {links} styles={styles} />
|
|
288
321
|
```
|
|
289
322
|
|
|
290
|
-
###
|
|
323
|
+
### Negative Overlap and Link Filtering
|
|
291
324
|
|
|
292
325
|
```svelte
|
|
293
326
|
<CactusTree
|
|
294
327
|
width={800}
|
|
295
328
|
height={600}
|
|
296
329
|
{nodes}
|
|
297
|
-
links={[
|
|
298
|
-
{ source: 'leaf1', target: 'leaf3' },
|
|
299
|
-
{ source: 'leaf2', target: 'leaf4' },
|
|
300
|
-
]}
|
|
301
|
-
styles={{
|
|
302
|
-
edge: '#3498db',
|
|
303
|
-
edgeOpacity: 0.3,
|
|
304
|
-
edgeWidth: 2,
|
|
305
|
-
}}
|
|
306
|
-
/>
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
### Negative Overlap and Link Filtering
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
```svelte
|
|
313
|
-
<CactusTree
|
|
314
|
-
width={1000}
|
|
315
|
-
height={800}
|
|
316
|
-
{nodes}
|
|
317
330
|
options={{
|
|
318
|
-
overlap: -1.1,
|
|
319
|
-
arcSpan: 2 * Math.PI,
|
|
320
|
-
orientation: 7 / 9 * Math.PI, //
|
|
321
|
-
zoom: 0.7
|
|
331
|
+
overlap: -1.1, // Gaps between nodes
|
|
332
|
+
arcSpan: 2 * Math.PI, // Full circle layout (radians)
|
|
333
|
+
orientation: (7 / 9) * Math.PI, // Root orientation (radians)
|
|
334
|
+
zoom: 0.7
|
|
322
335
|
}}
|
|
323
336
|
/>
|
|
324
337
|
```
|
|
@@ -327,5 +340,4 @@ The component provides several interactive features:
|
|
|
327
340
|
<img src="https://github.com/spren9er/cactuz/blob/main/docs/images/cactus_tree_advanced.png?raw=true" alt="cactus-tree-advanced" width="75%" height="75%">
|
|
328
341
|
</div>
|
|
329
342
|
|
|
330
|
-
For a negative overlap parameter, nodes are connected by links.
|
|
331
|
-
Also, when hovering over leaf nodes, only the links connected to that node are shown, while all other links are hidden. This allows for better readability in dense visualizations.
|
|
343
|
+
For a negative overlap parameter, nodes are connected by links. Also, when hovering over leaf nodes, only the links connected to that node are shown, while all other links are hidden. This allows for better readability in dense visualizations.
|
|
@@ -16,7 +16,107 @@
|
|
|
16
16
|
buildLookupMaps,
|
|
17
17
|
} from './cactusTree/layoutUtils.js';
|
|
18
18
|
|
|
19
|
-
/** @type {{
|
|
19
|
+
/** @type {{
|
|
20
|
+
width: number,
|
|
21
|
+
height: number,
|
|
22
|
+
nodes: Array<{ id: string, name: string, parent: string | null, weight?: number }>,
|
|
23
|
+
links?: Array<{ source: string, target: string }>,
|
|
24
|
+
options?: {
|
|
25
|
+
overlap?: number,
|
|
26
|
+
arcSpan?: number,
|
|
27
|
+
sizeGrowthRate?: number,
|
|
28
|
+
orientation?: number,
|
|
29
|
+
zoom?: number,
|
|
30
|
+
numLabels?: number
|
|
31
|
+
},
|
|
32
|
+
styles?: {
|
|
33
|
+
node?: {
|
|
34
|
+
fillColor?: string,
|
|
35
|
+
fillOpacity?: number,
|
|
36
|
+
strokeColor?: string,
|
|
37
|
+
strokeOpacity?: number,
|
|
38
|
+
strokeWidth?: number,
|
|
39
|
+
highlight?: {
|
|
40
|
+
fillColor?: string,
|
|
41
|
+
fillOpacity?: number,
|
|
42
|
+
strokeColor?: string,
|
|
43
|
+
strokeOpacity?: number,
|
|
44
|
+
strokeWidth?: number,
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
edge?: {
|
|
48
|
+
strokeColor?: string,
|
|
49
|
+
strokeOpacity?: number,
|
|
50
|
+
strokeWidth?: number,
|
|
51
|
+
highlight?: {
|
|
52
|
+
strokeColor?: string,
|
|
53
|
+
strokeOpacity?: number,
|
|
54
|
+
strokeWidth?: number
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
label?: {
|
|
58
|
+
textColor?: string,
|
|
59
|
+
textOpacity?: number,
|
|
60
|
+
fontFamily?: string,
|
|
61
|
+
minFontSize?: number,
|
|
62
|
+
maxFontSize?: number,
|
|
63
|
+
fontWeight?: string,
|
|
64
|
+
padding?: number,
|
|
65
|
+
link?: {
|
|
66
|
+
strokeColor?: string,
|
|
67
|
+
strokeOpacity?: number,
|
|
68
|
+
strokeWidth?: number,
|
|
69
|
+
length?: number
|
|
70
|
+
padding?: number,
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
line?: {
|
|
74
|
+
strokeColor?: string,
|
|
75
|
+
strokeOpacity?: number,
|
|
76
|
+
strokeWidth?: number
|
|
77
|
+
},
|
|
78
|
+
depths?: Array<{
|
|
79
|
+
depth: number,
|
|
80
|
+
node?: {
|
|
81
|
+
fillColor?: string,
|
|
82
|
+
fillOpacity?: number,
|
|
83
|
+
strokeColor?: string,
|
|
84
|
+
strokeOpacity?: number,
|
|
85
|
+
strokeWidth?: number,
|
|
86
|
+
highlight?: {
|
|
87
|
+
fillColor?: string,
|
|
88
|
+
fillOpacity?: number,
|
|
89
|
+
strokeColor?: string,
|
|
90
|
+
strokeOpacity?: number,
|
|
91
|
+
strokeWidth?: number,
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
label?: {
|
|
95
|
+
textColor?: string,
|
|
96
|
+
textOpacity?: number,
|
|
97
|
+
fontFamily?: string,
|
|
98
|
+
minFontSize?: number,
|
|
99
|
+
maxFontSize?: number,
|
|
100
|
+
fontWeight?: string,
|
|
101
|
+
padding?: number,
|
|
102
|
+
link?: {
|
|
103
|
+
strokeColor?: string,
|
|
104
|
+
strokeOpacity?: number,
|
|
105
|
+
strokeWidth?: number,
|
|
106
|
+
length?: number
|
|
107
|
+
padding?: number,
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
line?: {
|
|
111
|
+
strokeColor?: string,
|
|
112
|
+
strokeOpacity?: number,
|
|
113
|
+
strokeWidth?: number
|
|
114
|
+
}
|
|
115
|
+
}>
|
|
116
|
+
},
|
|
117
|
+
pannable?: boolean,
|
|
118
|
+
zoomable?: boolean
|
|
119
|
+
}} */
|
|
20
120
|
let {
|
|
21
121
|
width,
|
|
22
122
|
height,
|
|
@@ -34,37 +134,81 @@
|
|
|
34
134
|
sizeGrowthRate: 0.75,
|
|
35
135
|
orientation: Math.PI / 2,
|
|
36
136
|
zoom: 1.0,
|
|
137
|
+
numLabels: 30,
|
|
37
138
|
};
|
|
38
139
|
|
|
39
140
|
const defaultStyle = {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
141
|
+
node: {
|
|
142
|
+
fillColor: '#efefef',
|
|
143
|
+
fillOpacity: 1,
|
|
144
|
+
strokeColor: '#333333',
|
|
145
|
+
strokeOpacity: 1,
|
|
146
|
+
strokeWidth: 1,
|
|
147
|
+
highlight: {
|
|
148
|
+
fillColor: '#ffcc99',
|
|
149
|
+
fillOpacity: 1,
|
|
150
|
+
strokeColor: '#ff6600',
|
|
151
|
+
strokeOpacity: 1,
|
|
152
|
+
strokeWidth: 1,
|
|
153
|
+
enabled: true,
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
edge: {
|
|
157
|
+
strokeColor: '#ff6b6b',
|
|
158
|
+
strokeOpacity: 0.1,
|
|
159
|
+
strokeWidth: 1,
|
|
160
|
+
highlight: {
|
|
161
|
+
strokeColor: '#ff6600',
|
|
162
|
+
strokeOpacity: 1,
|
|
163
|
+
strokeWidth: 1,
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
label: {
|
|
167
|
+
textColor: '#333333',
|
|
168
|
+
textOpacity: 1,
|
|
169
|
+
fontFamily: 'monospace',
|
|
170
|
+
minFontSize: 8,
|
|
171
|
+
maxFontSize: 14,
|
|
172
|
+
fontWeight: 'normal',
|
|
173
|
+
padding: 1,
|
|
174
|
+
link: {
|
|
175
|
+
strokeColor: '#333333',
|
|
176
|
+
strokeOpacity: 1,
|
|
177
|
+
strokeWidth: 0.5,
|
|
178
|
+
padding: 0,
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
line: {
|
|
182
|
+
strokeColor: '#333333',
|
|
183
|
+
strokeOpacity: 1,
|
|
184
|
+
strokeWidth: 1,
|
|
185
|
+
},
|
|
186
|
+
depths: [],
|
|
63
187
|
};
|
|
64
188
|
|
|
65
189
|
// Merge options and styles
|
|
66
190
|
const mergedOptions = $derived({ ...defaultOptions, ...options });
|
|
67
|
-
const mergedStyle = $derived({
|
|
191
|
+
const mergedStyle = $derived({
|
|
192
|
+
node: {
|
|
193
|
+
...(defaultStyle.node || {}),
|
|
194
|
+
...(styles.node || {}),
|
|
195
|
+
highlight: {
|
|
196
|
+
...((defaultStyle.node && defaultStyle.node.highlight) || {}),
|
|
197
|
+
...((styles.node && styles.node.highlight) || {}),
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
edge: {
|
|
201
|
+
...(defaultStyle.edge || {}),
|
|
202
|
+
...(styles.edge || {}),
|
|
203
|
+
highlight: {
|
|
204
|
+
...((defaultStyle.edge && defaultStyle.edge.highlight) || {}),
|
|
205
|
+
...((styles.edge && styles.edge.highlight) || {}),
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
label: { ...(defaultStyle.label || {}), ...(styles.label || {}) },
|
|
209
|
+
line: { ...(defaultStyle.line || {}), ...(styles.line || {}) },
|
|
210
|
+
depths: styles.depths ?? defaultStyle.depths,
|
|
211
|
+
});
|
|
68
212
|
|
|
69
213
|
// Canvas and context
|
|
70
214
|
/** @type {HTMLCanvasElement} */
|
|
@@ -78,8 +222,6 @@
|
|
|
78
222
|
let nodeIdToRenderedNodeMap = new SvelteMap();
|
|
79
223
|
let leafNodes = new SvelteSet();
|
|
80
224
|
let negativeDepthNodes = new SvelteMap();
|
|
81
|
-
// @ts-ignore - Used internally by layout utilities
|
|
82
|
-
let nodeIdToNodeMap = new SvelteMap();
|
|
83
225
|
let depthStyleCache = new SvelteMap();
|
|
84
226
|
let hierarchicalPathCache = new SvelteMap();
|
|
85
227
|
let parentToChildrenNodeMap = new SvelteMap();
|
|
@@ -106,7 +248,7 @@
|
|
|
106
248
|
/** @type {number|null} */
|
|
107
249
|
let animationFrameId = null;
|
|
108
250
|
|
|
109
|
-
// Calculate layout and build lookup maps (called on each render
|
|
251
|
+
// Calculate layout and build lookup maps (called on each render)
|
|
110
252
|
function calculateLayoutAndMaps() {
|
|
111
253
|
if (!nodes?.length) {
|
|
112
254
|
renderedNodes = [];
|
|
@@ -133,8 +275,6 @@
|
|
|
133
275
|
nodeIdToRenderedNodeMap = lookupMaps.nodeIdToRenderedNodeMap;
|
|
134
276
|
leafNodes = lookupMaps.leafNodes;
|
|
135
277
|
negativeDepthNodes = lookupMaps.negativeDepthNodes;
|
|
136
|
-
nodeIdToNodeMap = lookupMaps.nodeIdToNodeMap;
|
|
137
|
-
void nodeIdToNodeMap; // Prevent unused variable warning
|
|
138
278
|
depthStyleCache = lookupMaps.depthStyleCache;
|
|
139
279
|
hierarchicalPathCache = lookupMaps.hierarchicalPathCache;
|
|
140
280
|
parentToChildrenNodeMap = lookupMaps.parentToChildrenNodeMap;
|
|
@@ -161,7 +301,7 @@
|
|
|
161
301
|
function draw() {
|
|
162
302
|
if (!canvas || !ctx) return;
|
|
163
303
|
|
|
164
|
-
// Clear and set up canvas context
|
|
304
|
+
// Clear and set up canvas context
|
|
165
305
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
166
306
|
ctx.save();
|
|
167
307
|
|
|
@@ -176,6 +316,7 @@
|
|
|
176
316
|
mergedStyle,
|
|
177
317
|
depthStyleCache,
|
|
178
318
|
mergedOptions.overlap,
|
|
319
|
+
negativeDepthNodes,
|
|
179
320
|
);
|
|
180
321
|
|
|
181
322
|
// Draw nodes
|
|
@@ -210,6 +351,7 @@
|
|
|
210
351
|
mergedStyle,
|
|
211
352
|
depthStyleCache,
|
|
212
353
|
negativeDepthNodes,
|
|
354
|
+
mergedOptions.numLabels,
|
|
213
355
|
panX,
|
|
214
356
|
panY,
|
|
215
357
|
);
|