pict-section-flow 0.0.10 → 0.0.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/.claude/launch.json +1 -1
- package/README.md +176 -0
- package/docs/.nojekyll +0 -0
- package/docs/Architecture.md +303 -0
- package/docs/Custom-Styling.md +275 -0
- package/docs/Data_Model.md +158 -0
- package/docs/Event_System.md +156 -0
- package/docs/Getting_Started.md +237 -0
- package/docs/Implementation_Reference.md +528 -0
- package/docs/Layout_Persistence.md +117 -0
- package/docs/README.md +115 -52
- package/docs/_cover.md +11 -0
- package/docs/_sidebar.md +52 -0
- package/docs/_topbar.md +8 -0
- package/docs/api/PictFlowCard.md +216 -0
- package/docs/api/PictFlowCardPropertiesPanel.md +235 -0
- package/docs/api/addConnection.md +101 -0
- package/docs/api/addNode.md +137 -0
- package/docs/api/autoLayout.md +77 -0
- package/docs/api/getFlowData.md +112 -0
- package/docs/api/marshalToView.md +95 -0
- package/docs/api/openPanel.md +128 -0
- package/docs/api/registerHandler.md +174 -0
- package/docs/api/registerNodeType.md +142 -0
- package/docs/api/removeConnection.md +57 -0
- package/docs/api/removeNode.md +80 -0
- package/docs/api/saveLayout.md +152 -0
- package/docs/api/screenToSVGCoords.md +68 -0
- package/docs/api/selectNode.md +116 -0
- package/docs/api/setTheme.md +168 -0
- package/docs/api/setZoom.md +97 -0
- package/docs/api/toggleFullscreen.md +68 -0
- package/docs/card-help/EACH.md +19 -0
- package/docs/card-help/FREAD.md +24 -0
- package/docs/card-help/FWRITE.md +24 -0
- package/docs/card-help/GET.md +22 -0
- package/docs/card-help/ITE.md +23 -0
- package/docs/card-help/LOG.md +23 -0
- package/docs/card-help/NOTE.md +17 -0
- package/docs/card-help/PREV.md +18 -0
- package/docs/card-help/SET.md +27 -0
- package/docs/card-help/SPKL.md +22 -0
- package/docs/card-help/STAT.md +23 -0
- package/docs/card-help/SW.md +25 -0
- package/docs/css/docuserve.css +73 -0
- package/docs/index.html +39 -0
- package/docs/retold-catalog.json +169 -0
- package/docs/retold-keyword-index.json +13942 -0
- package/example_applications/simple_cards/package.json +1 -0
- package/example_applications/simple_cards/source/card-help-content.js +16 -0
- package/example_applications/simple_cards/source/cards/FlowCard-Comment.js +2 -0
- package/example_applications/simple_cards/source/cards/FlowCard-DataPreview.js +2 -0
- package/example_applications/simple_cards/source/cards/FlowCard-Each.js +2 -0
- package/example_applications/simple_cards/source/cards/FlowCard-FileRead.js +2 -0
- package/example_applications/simple_cards/source/cards/FlowCard-FileWrite.js +2 -0
- package/example_applications/simple_cards/source/cards/FlowCard-GetValue.js +2 -0
- package/example_applications/simple_cards/source/cards/FlowCard-IfThenElse.js +2 -0
- package/example_applications/simple_cards/source/cards/FlowCard-LogValues.js +2 -0
- package/example_applications/simple_cards/source/cards/FlowCard-SetValue.js +2 -0
- package/example_applications/simple_cards/source/cards/FlowCard-Sparkline.js +2 -0
- package/example_applications/simple_cards/source/cards/FlowCard-StatusMonitor.js +2 -0
- package/example_applications/simple_cards/source/cards/FlowCard-Switch.js +2 -0
- package/package.json +11 -7
- package/scripts/generate-card-help.js +214 -0
- package/source/Pict-Section-Flow.js +4 -0
- package/source/PictFlowCard.js +3 -1
- package/source/providers/PictProvider-Flow-CSS.js +245 -152
- package/source/providers/PictProvider-Flow-ConnectorShapes.js +24 -0
- package/source/providers/PictProvider-Flow-Geometry.js +195 -38
- package/source/providers/PictProvider-Flow-PanelChrome.js +14 -12
- package/source/services/PictService-Flow-ConnectionHandleManager.js +263 -0
- package/source/services/PictService-Flow-ConnectionRenderer.js +134 -183
- package/source/services/PictService-Flow-DataManager.js +338 -0
- package/source/services/PictService-Flow-InteractionManager.js +165 -7
- package/source/services/PictService-Flow-PathGenerator.js +282 -0
- package/source/services/PictService-Flow-PortRenderer.js +269 -0
- package/source/services/PictService-Flow-RenderManager.js +281 -0
- package/source/services/PictService-Flow-Tether.js +6 -42
- package/source/views/PictView-Flow-Node.js +2 -220
- package/source/views/PictView-Flow-PropertiesPanel.js +89 -44
- package/source/views/PictView-Flow.js +130 -882
- package/test/ConnectionHandleManager_tests.js +717 -0
- package/test/ConnectionRenderer_tests.js +591 -0
- package/test/DataManager_tests.js +859 -0
- package/test/Geometry_tests.js +767 -0
- package/test/PathGenerator_tests.js +978 -0
- package/test/PortRenderer_tests.js +367 -0
- package/test/RenderManager_tests.js +756 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# saveLayout / restoreLayout / deleteLayout
|
|
2
|
+
|
|
3
|
+
Save, restore, and manage spatial layout snapshots. Layouts capture node and panel positions plus viewport state, independent of the flow's logical content.
|
|
4
|
+
|
|
5
|
+
## Signatures
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
let tmpLayout = flowView._LayoutProvider.saveLayout(pName);
|
|
9
|
+
flowView._LayoutProvider.restoreLayout(pLayoutHash);
|
|
10
|
+
flowView._LayoutProvider.deleteLayout(pLayoutHash);
|
|
11
|
+
flowView._LayoutProvider.getLayouts();
|
|
12
|
+
flowView._LayoutProvider.loadPersistedLayouts();
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## saveLayout
|
|
16
|
+
|
|
17
|
+
Save the current spatial arrangement.
|
|
18
|
+
|
|
19
|
+
| Parameter | Type | Required | Description |
|
|
20
|
+
|-----------|------|----------|-------------|
|
|
21
|
+
| `pName` | string | Yes | Display name for the layout |
|
|
22
|
+
|
|
23
|
+
**Returns:** Layout data object.
|
|
24
|
+
|
|
25
|
+
**Events Fired:** `onLayoutSaved`
|
|
26
|
+
|
|
27
|
+
## restoreLayout
|
|
28
|
+
|
|
29
|
+
Restore a previously saved layout.
|
|
30
|
+
|
|
31
|
+
| Parameter | Type | Required | Description |
|
|
32
|
+
|-----------|------|----------|-------------|
|
|
33
|
+
| `pLayoutHash` | string | Yes | Hash of the layout to restore |
|
|
34
|
+
|
|
35
|
+
**Returns:** `boolean`
|
|
36
|
+
|
|
37
|
+
**Events Fired:** `onLayoutRestored`
|
|
38
|
+
|
|
39
|
+
## deleteLayout
|
|
40
|
+
|
|
41
|
+
Delete a saved layout.
|
|
42
|
+
|
|
43
|
+
| Parameter | Type | Required | Description |
|
|
44
|
+
|-----------|------|----------|-------------|
|
|
45
|
+
| `pLayoutHash` | string | Yes | Hash of the layout to delete |
|
|
46
|
+
|
|
47
|
+
**Returns:** `boolean`
|
|
48
|
+
|
|
49
|
+
**Events Fired:** `onLayoutDeleted`
|
|
50
|
+
|
|
51
|
+
## getLayouts
|
|
52
|
+
|
|
53
|
+
Returns an array of all saved layout objects.
|
|
54
|
+
|
|
55
|
+
## loadPersistedLayouts
|
|
56
|
+
|
|
57
|
+
Load layouts from the storage backend. Called automatically on initialization when using localStorage.
|
|
58
|
+
|
|
59
|
+
## Examples
|
|
60
|
+
|
|
61
|
+
### Save and list layouts
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
// Save the current arrangement
|
|
65
|
+
flowView._LayoutProvider.saveLayout('Default View');
|
|
66
|
+
flowView._LayoutProvider.saveLayout('Zoomed In');
|
|
67
|
+
|
|
68
|
+
// List all saved layouts
|
|
69
|
+
let tmpLayouts = flowView._LayoutProvider.getLayouts();
|
|
70
|
+
tmpLayouts.forEach((pLayout) =>
|
|
71
|
+
{
|
|
72
|
+
console.log(pLayout.Name, pLayout.Hash, pLayout.CreatedAt);
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Restore a layout
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
let tmpLayouts = flowView._LayoutProvider.getLayouts();
|
|
80
|
+
|
|
81
|
+
if (tmpLayouts.length > 0)
|
|
82
|
+
{
|
|
83
|
+
flowView._LayoutProvider.restoreLayout(tmpLayouts[0].Hash);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Layout picker UI
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
function renderLayoutPicker()
|
|
91
|
+
{
|
|
92
|
+
let tmpLayouts = flowView._LayoutProvider.getLayouts();
|
|
93
|
+
let tmpContainer = document.getElementById('layout-picker');
|
|
94
|
+
tmpContainer.innerHTML = '';
|
|
95
|
+
|
|
96
|
+
tmpLayouts.forEach((pLayout) =>
|
|
97
|
+
{
|
|
98
|
+
let tmpButton = document.createElement('button');
|
|
99
|
+
tmpButton.textContent = pLayout.Name;
|
|
100
|
+
tmpButton.addEventListener('click', () =>
|
|
101
|
+
{
|
|
102
|
+
flowView._LayoutProvider.restoreLayout(pLayout.Hash);
|
|
103
|
+
});
|
|
104
|
+
tmpContainer.appendChild(tmpButton);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Re-render picker when layouts change
|
|
109
|
+
flowView._EventHandlerProvider.registerHandler('onLayoutSaved', renderLayoutPicker);
|
|
110
|
+
flowView._EventHandlerProvider.registerHandler('onLayoutDeleted', renderLayoutPicker);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Override storage for REST API
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
let tmpLayoutProvider = flowView._LayoutProvider;
|
|
117
|
+
|
|
118
|
+
tmpLayoutProvider.storageWrite = function(pLayouts, fCallback)
|
|
119
|
+
{
|
|
120
|
+
fetch('/api/my-flow/layouts',
|
|
121
|
+
{
|
|
122
|
+
method: 'PUT',
|
|
123
|
+
headers: { 'Content-Type': 'application/json' },
|
|
124
|
+
body: JSON.stringify(pLayouts)
|
|
125
|
+
})
|
|
126
|
+
.then(() => fCallback(null))
|
|
127
|
+
.catch((pError) => fCallback(pError));
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
tmpLayoutProvider.storageRead = function(fCallback)
|
|
131
|
+
{
|
|
132
|
+
fetch('/api/my-flow/layouts')
|
|
133
|
+
.then((pResponse) => pResponse.json())
|
|
134
|
+
.then((pLayouts) => fCallback(null, pLayouts))
|
|
135
|
+
.catch((pError) => fCallback(pError, []));
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
tmpLayoutProvider.storageDelete = function(fCallback)
|
|
139
|
+
{
|
|
140
|
+
fetch('/api/my-flow/layouts', { method: 'DELETE' })
|
|
141
|
+
.then(() => fCallback(null))
|
|
142
|
+
.catch((pError) => fCallback(pError));
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// Reload from the new backend
|
|
146
|
+
tmpLayoutProvider.loadPersistedLayouts();
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## See Also
|
|
150
|
+
|
|
151
|
+
- [Layout Persistence](../Layout_Persistence.md) — Detailed guide on storage backends
|
|
152
|
+
- [autoLayout](autoLayout.md) — Automatic topological layout
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# screenToSVGCoords
|
|
2
|
+
|
|
3
|
+
Convert screen pixel coordinates (e.g. from a mouse event) to the SVG coordinate space used internally by the flow diagram. Accounts for the current pan offset and zoom level.
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
let tmpCoords = flowView.screenToSVGCoords(pScreenX, pScreenY);
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Parameters
|
|
12
|
+
|
|
13
|
+
| Parameter | Type | Required | Description |
|
|
14
|
+
|-----------|------|----------|-------------|
|
|
15
|
+
| `pScreenX` | number | Yes | X coordinate in screen pixels |
|
|
16
|
+
| `pScreenY` | number | Yes | Y coordinate in screen pixels |
|
|
17
|
+
|
|
18
|
+
## Returns
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
{ x: 142.5, y: 87.3 }
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
An object with `x` and `y` properties in SVG coordinate space.
|
|
25
|
+
|
|
26
|
+
## Examples
|
|
27
|
+
|
|
28
|
+
### Place a node at the click position
|
|
29
|
+
|
|
30
|
+
```javascript
|
|
31
|
+
document.getElementById('flow-container').addEventListener('click', (pEvent) =>
|
|
32
|
+
{
|
|
33
|
+
let tmpSVG = flowView.screenToSVGCoords(pEvent.clientX, pEvent.clientY);
|
|
34
|
+
flowView.addNode('default', tmpSVG.x, tmpSVG.y, 'New Node');
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Context menu at cursor position
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
document.getElementById('flow-container').addEventListener('contextmenu', (pEvent) =>
|
|
42
|
+
{
|
|
43
|
+
pEvent.preventDefault();
|
|
44
|
+
let tmpSVG = flowView.screenToSVGCoords(pEvent.clientX, pEvent.clientY);
|
|
45
|
+
|
|
46
|
+
showContextMenu(pEvent.clientX, pEvent.clientY,
|
|
47
|
+
{
|
|
48
|
+
svgX: tmpSVG.x,
|
|
49
|
+
svgY: tmpSVG.y
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Debug coordinate output
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
document.getElementById('flow-container').addEventListener('mousemove', (pEvent) =>
|
|
58
|
+
{
|
|
59
|
+
let tmpSVG = flowView.screenToSVGCoords(pEvent.clientX, pEvent.clientY);
|
|
60
|
+
document.getElementById('coords').textContent =
|
|
61
|
+
'SVG: (' + Math.round(tmpSVG.x) + ', ' + Math.round(tmpSVG.y) + ')';
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## See Also
|
|
66
|
+
|
|
67
|
+
- [setZoom](setZoom.md) — Viewport zoom (affects coordinate mapping)
|
|
68
|
+
- [addNode](addNode.md) — Create nodes at specific coordinates
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# selectNode / selectConnection / selectTether / deselectAll / deleteSelected
|
|
2
|
+
|
|
3
|
+
Manage the selection state of the flow canvas. At most one element (node, connection, or tether) can be selected at a time.
|
|
4
|
+
|
|
5
|
+
## Signatures
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
flowView.selectNode(pNodeHash);
|
|
9
|
+
flowView.selectConnection(pConnectionHash);
|
|
10
|
+
flowView.selectTether(pPanelHash);
|
|
11
|
+
flowView.deselectAll();
|
|
12
|
+
flowView.deleteSelected();
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## selectNode
|
|
16
|
+
|
|
17
|
+
Select a node by hash. Pass `null` to deselect.
|
|
18
|
+
|
|
19
|
+
| Parameter | Type | Description |
|
|
20
|
+
|-----------|------|-------------|
|
|
21
|
+
| `pNodeHash` | string/null | Node hash, or `null` to deselect |
|
|
22
|
+
|
|
23
|
+
**Events Fired:** `onNodeSelected`
|
|
24
|
+
|
|
25
|
+
## selectConnection
|
|
26
|
+
|
|
27
|
+
Select a connection by hash. Pass `null` to deselect.
|
|
28
|
+
|
|
29
|
+
| Parameter | Type | Description |
|
|
30
|
+
|-----------|------|-------------|
|
|
31
|
+
| `pConnectionHash` | string/null | Connection hash, or `null` to deselect |
|
|
32
|
+
|
|
33
|
+
**Events Fired:** `onConnectionSelected`
|
|
34
|
+
|
|
35
|
+
## selectTether
|
|
36
|
+
|
|
37
|
+
Select a tether line by its panel hash. Pass `null` to deselect.
|
|
38
|
+
|
|
39
|
+
| Parameter | Type | Description |
|
|
40
|
+
|-----------|------|-------------|
|
|
41
|
+
| `pPanelHash` | string/null | Panel hash, or `null` to deselect |
|
|
42
|
+
|
|
43
|
+
**Events Fired:** `onTetherSelected`
|
|
44
|
+
|
|
45
|
+
## deselectAll
|
|
46
|
+
|
|
47
|
+
Clear all selection state (node, connection, and tether).
|
|
48
|
+
|
|
49
|
+
## deleteSelected
|
|
50
|
+
|
|
51
|
+
Delete the currently selected node or connection. If a node is selected, its connections are also removed.
|
|
52
|
+
|
|
53
|
+
**Returns:** `boolean` — `true` if something was deleted.
|
|
54
|
+
|
|
55
|
+
## Examples
|
|
56
|
+
|
|
57
|
+
### Programmatic selection
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
let tmpNode = flowView.addNode('default', 100, 100, 'My Node');
|
|
61
|
+
|
|
62
|
+
// Select the node
|
|
63
|
+
flowView.selectNode(tmpNode.Hash);
|
|
64
|
+
|
|
65
|
+
// Check selection state
|
|
66
|
+
let tmpFlowData = flowView.getFlowData();
|
|
67
|
+
console.log(tmpFlowData.ViewState.SelectedNodeHash); // 'node-...'
|
|
68
|
+
|
|
69
|
+
// Clear selection
|
|
70
|
+
flowView.deselectAll();
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Selection event handler
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
flowView._EventHandlerProvider.registerHandler('onNodeSelected',
|
|
77
|
+
(pNode) =>
|
|
78
|
+
{
|
|
79
|
+
if (pNode)
|
|
80
|
+
{
|
|
81
|
+
document.getElementById('details-panel').innerHTML =
|
|
82
|
+
'Selected: ' + pNode.Title + ' (' + pNode.Type + ')';
|
|
83
|
+
}
|
|
84
|
+
else
|
|
85
|
+
{
|
|
86
|
+
document.getElementById('details-panel').innerHTML = 'Nothing selected';
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Delete with confirmation
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
function handleDelete()
|
|
95
|
+
{
|
|
96
|
+
let tmpFlowData = flowView.getFlowData();
|
|
97
|
+
|
|
98
|
+
if (tmpFlowData.ViewState.SelectedNodeHash)
|
|
99
|
+
{
|
|
100
|
+
let tmpNode = flowView.getNode(tmpFlowData.ViewState.SelectedNodeHash);
|
|
101
|
+
if (confirm('Delete node "' + tmpNode.Title + '"?'))
|
|
102
|
+
{
|
|
103
|
+
flowView.deleteSelected();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else if (tmpFlowData.ViewState.SelectedConnectionHash)
|
|
107
|
+
{
|
|
108
|
+
flowView.deleteSelected();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## See Also
|
|
114
|
+
|
|
115
|
+
- [addNode](addNode.md) / [removeNode](removeNode.md) — Node CRUD
|
|
116
|
+
- [registerHandler](registerHandler.md) — Event hooks
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# setTheme / registerTheme
|
|
2
|
+
|
|
3
|
+
Manage the visual theme of the flow diagram. Six built-in themes are available, and you can register custom themes with CSS variable overrides.
|
|
4
|
+
|
|
5
|
+
## Signatures
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
flowView.setTheme(pThemeKey);
|
|
9
|
+
flowView._ThemeProvider.registerTheme(pThemeKey, pThemeConfig);
|
|
10
|
+
flowView.setNoiseLevel(pLevel);
|
|
11
|
+
flowView.getNoiseLevel();
|
|
12
|
+
flowView.getThemeKey();
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## setTheme
|
|
16
|
+
|
|
17
|
+
Switch to a registered theme and re-render.
|
|
18
|
+
|
|
19
|
+
| Parameter | Type | Description |
|
|
20
|
+
|-----------|------|-------------|
|
|
21
|
+
| `pThemeKey` | string | Theme identifier |
|
|
22
|
+
|
|
23
|
+
**Events Fired:** `onThemeChanged`
|
|
24
|
+
|
|
25
|
+
### Built-in Theme Keys
|
|
26
|
+
|
|
27
|
+
| Key | Style |
|
|
28
|
+
|-----|-------|
|
|
29
|
+
| `default` | Clean, modern, professional |
|
|
30
|
+
| `sketch` | Hand-drawn, informal |
|
|
31
|
+
| `blueprint` | Technical blueprint |
|
|
32
|
+
| `mono` | Monochrome |
|
|
33
|
+
| `retro-80s` | Neon retro |
|
|
34
|
+
| `retro-90s` | Vaporwave |
|
|
35
|
+
|
|
36
|
+
## registerTheme
|
|
37
|
+
|
|
38
|
+
Register a custom theme.
|
|
39
|
+
|
|
40
|
+
| Parameter | Type | Description |
|
|
41
|
+
|-----------|------|-------------|
|
|
42
|
+
| `pThemeKey` | string | Unique theme identifier |
|
|
43
|
+
| `pThemeConfig` | object | Theme configuration |
|
|
44
|
+
|
|
45
|
+
### Theme Configuration Shape
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
{
|
|
49
|
+
Key: 'dark',
|
|
50
|
+
Label: 'Dark Mode',
|
|
51
|
+
CSSVariables:
|
|
52
|
+
{
|
|
53
|
+
'--pf-canvas-bg': '#1a1a2e',
|
|
54
|
+
'--pf-node-body-fill': '#16213e',
|
|
55
|
+
'--pf-node-body-stroke': '#0f3460',
|
|
56
|
+
'--pf-text-primary': '#e8e8e8',
|
|
57
|
+
'--pf-node-selected-stroke': '#e94560'
|
|
58
|
+
},
|
|
59
|
+
AdditionalCSS: '/* Extra CSS rules */',
|
|
60
|
+
NodeBodyMode: 'rect',
|
|
61
|
+
NoiseConfig:
|
|
62
|
+
{
|
|
63
|
+
Enabled: true,
|
|
64
|
+
Amount: 0.5
|
|
65
|
+
},
|
|
66
|
+
ConnectionConfig:
|
|
67
|
+
{
|
|
68
|
+
StrokeDashArray: '5,5'
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
| Property | Type | Description |
|
|
74
|
+
|----------|------|-------------|
|
|
75
|
+
| `Key` | string | Unique identifier |
|
|
76
|
+
| `Label` | string | Display name |
|
|
77
|
+
| `CSSVariables` | object | Map of `--pf-*` variable names to values |
|
|
78
|
+
| `AdditionalCSS` | string | Extra CSS appended after variable overrides |
|
|
79
|
+
| `NodeBodyMode` | string | Node rendering mode: `'rect'` or `'bracket'` |
|
|
80
|
+
| `NoiseConfig` | object | Hand-drawn effect: `{ Enabled, Amount }` |
|
|
81
|
+
| `ConnectionConfig` | object | Connection styling: `{ StrokeDashArray }` |
|
|
82
|
+
|
|
83
|
+
## setNoiseLevel / getNoiseLevel
|
|
84
|
+
|
|
85
|
+
Control the hand-drawn rendering effect independently of the theme.
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
flowView.setNoiseLevel(0.5); // Moderate wobble
|
|
89
|
+
flowView.setNoiseLevel(0); // Precise, clean lines
|
|
90
|
+
flowView.setNoiseLevel(1); // Maximum hand-drawn effect
|
|
91
|
+
|
|
92
|
+
let tmpLevel = flowView.getNoiseLevel(); // 0.5
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## getThemeKey
|
|
96
|
+
|
|
97
|
+
Returns the active theme key string.
|
|
98
|
+
|
|
99
|
+
```javascript
|
|
100
|
+
let tmpKey = flowView.getThemeKey(); // 'default'
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Examples
|
|
104
|
+
|
|
105
|
+
### Switch to a built-in theme
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
flowView.setTheme('blueprint');
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Register and apply a custom dark theme
|
|
112
|
+
|
|
113
|
+
```javascript
|
|
114
|
+
flowView._ThemeProvider.registerTheme('dark',
|
|
115
|
+
{
|
|
116
|
+
Key: 'dark',
|
|
117
|
+
Label: 'Dark Mode',
|
|
118
|
+
CSSVariables:
|
|
119
|
+
{
|
|
120
|
+
'--pf-canvas-bg': '#1a1a2e',
|
|
121
|
+
'--pf-node-body-fill': '#16213e',
|
|
122
|
+
'--pf-node-body-stroke': '#0f3460',
|
|
123
|
+
'--pf-text-primary': '#e8e8e8',
|
|
124
|
+
'--pf-node-selected-stroke': '#e94560',
|
|
125
|
+
'--pf-connection-stroke': '#4a6fa5',
|
|
126
|
+
'--pf-toolbar-bg': '#162447',
|
|
127
|
+
'--pf-panel-bg': '#1a1a2e',
|
|
128
|
+
'--pf-panel-titlebar-bg': '#162447'
|
|
129
|
+
},
|
|
130
|
+
NodeBodyMode: 'rect'
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
flowView.setTheme('dark');
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Theme selector dropdown
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
document.getElementById('theme-select').addEventListener('change', (pEvent) =>
|
|
140
|
+
{
|
|
141
|
+
flowView.setTheme(pEvent.target.value);
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Corporate branding theme
|
|
146
|
+
|
|
147
|
+
```javascript
|
|
148
|
+
flowView._ThemeProvider.registerTheme('corporate',
|
|
149
|
+
{
|
|
150
|
+
Key: 'corporate',
|
|
151
|
+
Label: 'Corporate',
|
|
152
|
+
CSSVariables:
|
|
153
|
+
{
|
|
154
|
+
'--pf-canvas-bg': '#f5f6fa',
|
|
155
|
+
'--pf-node-selected-stroke': '#0066cc',
|
|
156
|
+
'--pf-node-body-stroke': '#c8d6e5',
|
|
157
|
+
'--pf-node-title-bar-color': '#003366',
|
|
158
|
+
'--pf-toolbar-bg': '#ffffff',
|
|
159
|
+
'--pf-panel-titlebar-bg': '#f0f2f5'
|
|
160
|
+
},
|
|
161
|
+
NoiseConfig: { Enabled: false }
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## See Also
|
|
166
|
+
|
|
167
|
+
- [Custom Styling](../Custom-Styling.md) — Full CSS custom properties reference
|
|
168
|
+
- [registerHandler](registerHandler.md) — Listen for `onThemeChanged` events
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# setZoom / zoomToFit
|
|
2
|
+
|
|
3
|
+
Control the viewport zoom level. `setZoom` sets an explicit zoom value with an optional focus point. `zoomToFit` automatically adjusts pan and zoom to frame all nodes in the viewport.
|
|
4
|
+
|
|
5
|
+
## Signatures
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
flowView.setZoom(pZoom, pFocusX, pFocusY);
|
|
9
|
+
flowView.zoomToFit();
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## setZoom
|
|
13
|
+
|
|
14
|
+
| Parameter | Type | Required | Description |
|
|
15
|
+
|-----------|------|----------|-------------|
|
|
16
|
+
| `pZoom` | number | Yes | Target zoom level (clamped to `MinZoom`..`MaxZoom`) |
|
|
17
|
+
| `pFocusX` | number | No | X coordinate in SVG space to zoom toward |
|
|
18
|
+
| `pFocusY` | number | No | Y coordinate in SVG space to zoom toward |
|
|
19
|
+
|
|
20
|
+
## zoomToFit
|
|
21
|
+
|
|
22
|
+
No parameters. Calculates the bounding box of all nodes and adjusts pan/zoom to fit them in the visible viewport with padding.
|
|
23
|
+
|
|
24
|
+
## Examples
|
|
25
|
+
|
|
26
|
+
### Set a specific zoom level
|
|
27
|
+
|
|
28
|
+
```javascript
|
|
29
|
+
// Zoom to 150%
|
|
30
|
+
flowView.setZoom(1.5);
|
|
31
|
+
|
|
32
|
+
// Zoom to 50% focused on a specific point
|
|
33
|
+
flowView.setZoom(0.5, 300, 200);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Zoom to fit after loading data
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
flowView.setFlowData(savedFlowData);
|
|
40
|
+
flowView.zoomToFit();
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Zoom controls
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
document.getElementById('zoom-in').addEventListener('click', () =>
|
|
47
|
+
{
|
|
48
|
+
let tmpCurrent = flowView.getFlowData().ViewState.Zoom;
|
|
49
|
+
flowView.setZoom(tmpCurrent + 0.1);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
document.getElementById('zoom-out').addEventListener('click', () =>
|
|
53
|
+
{
|
|
54
|
+
let tmpCurrent = flowView.getFlowData().ViewState.Zoom;
|
|
55
|
+
flowView.setZoom(tmpCurrent - 0.1);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
document.getElementById('zoom-fit').addEventListener('click', () =>
|
|
59
|
+
{
|
|
60
|
+
flowView.zoomToFit();
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Zoom to a specific node
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
function zoomToNode(pFlowView, pNodeHash, pZoomLevel)
|
|
68
|
+
{
|
|
69
|
+
let tmpNode = pFlowView.getNode(pNodeHash);
|
|
70
|
+
if (tmpNode)
|
|
71
|
+
{
|
|
72
|
+
let tmpCenterX = tmpNode.X + (tmpNode.Width / 2);
|
|
73
|
+
let tmpCenterY = tmpNode.Y + (tmpNode.Height / 2);
|
|
74
|
+
pFlowView.setZoom(pZoomLevel || 1.5, tmpCenterX, tmpCenterY);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
zoomToNode(flowView, myNode.Hash, 2.0);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Configuration
|
|
82
|
+
|
|
83
|
+
Zoom bounds are set in the view configuration:
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
{
|
|
87
|
+
MinZoom: 0.1,
|
|
88
|
+
MaxZoom: 5.0,
|
|
89
|
+
ZoomStep: 0.1
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## See Also
|
|
94
|
+
|
|
95
|
+
- [screenToSVGCoords](screenToSVGCoords.md) — Coordinate conversion
|
|
96
|
+
- [toggleFullscreen](toggleFullscreen.md) — Fullscreen mode
|
|
97
|
+
- [autoLayout](autoLayout.md) — Automatic node arrangement
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# toggleFullscreen / exitFullscreen
|
|
2
|
+
|
|
3
|
+
Toggle the flow diagram into a fullscreen overlay that covers the entire browser viewport. Useful for maximizing workspace on complex flows.
|
|
4
|
+
|
|
5
|
+
## Signatures
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
flowView.toggleFullscreen();
|
|
9
|
+
flowView.exitFullscreen();
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## toggleFullscreen
|
|
13
|
+
|
|
14
|
+
Toggles between normal and fullscreen modes.
|
|
15
|
+
|
|
16
|
+
**Returns:** `boolean` — the new fullscreen state (`true` if now fullscreen).
|
|
17
|
+
|
|
18
|
+
## exitFullscreen
|
|
19
|
+
|
|
20
|
+
Explicitly exits fullscreen mode if active.
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
### Toggle button
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
document.getElementById('fullscreen-btn').addEventListener('click', () =>
|
|
28
|
+
{
|
|
29
|
+
let tmpIsFullscreen = flowView.toggleFullscreen();
|
|
30
|
+
|
|
31
|
+
if (tmpIsFullscreen)
|
|
32
|
+
{
|
|
33
|
+
document.getElementById('fullscreen-btn').textContent = 'Exit Fullscreen';
|
|
34
|
+
}
|
|
35
|
+
else
|
|
36
|
+
{
|
|
37
|
+
document.getElementById('fullscreen-btn').textContent = 'Fullscreen';
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Escape key to exit
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
document.addEventListener('keydown', (pEvent) =>
|
|
46
|
+
{
|
|
47
|
+
if (pEvent.key === 'Escape')
|
|
48
|
+
{
|
|
49
|
+
flowView.exitFullscreen();
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Fullscreen with zoom-to-fit
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
flowView.toggleFullscreen();
|
|
58
|
+
|
|
59
|
+
// Wait for the CSS transition, then fit content
|
|
60
|
+
setTimeout(() =>
|
|
61
|
+
{
|
|
62
|
+
flowView.zoomToFit();
|
|
63
|
+
}, 300);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## See Also
|
|
67
|
+
|
|
68
|
+
- [setZoom / zoomToFit](setZoom.md) — Viewport controls
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Each (Loop Iterator)
|
|
2
|
+
|
|
3
|
+
The **Each** node iterates over a collection, executing connected downstream nodes once for each item. When iteration completes, the **Done** output fires.
|
|
4
|
+
|
|
5
|
+
## Ports
|
|
6
|
+
|
|
7
|
+
- **Collection** (input) — an array or iterable to loop over
|
|
8
|
+
- **Item** (output) — fires once per element with the current item
|
|
9
|
+
- **Done** (output) — fires after all items have been processed
|
|
10
|
+
|
|
11
|
+
## Behavior
|
|
12
|
+
|
|
13
|
+
When a collection arrives at the input port, the Each node processes items sequentially. For every element in the collection, the **Item** output is activated with the current element as the payload. After the final element is processed, the **Done** output fires to signal completion.
|
|
14
|
+
|
|
15
|
+
## Tips
|
|
16
|
+
|
|
17
|
+
- Connect **Item** to a processing chain and **Done** to continuation logic
|
|
18
|
+
- Nested loops are supported by chaining multiple Each nodes
|
|
19
|
+
- Empty collections skip directly to the **Done** output
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# File Read
|
|
2
|
+
|
|
3
|
+
The **File Read** node reads the contents of a file from the filesystem and outputs the data.
|
|
4
|
+
|
|
5
|
+
## Ports
|
|
6
|
+
|
|
7
|
+
- **Path** (input) — the filesystem path to read
|
|
8
|
+
- **Data** (output) — the file contents on success
|
|
9
|
+
- **Error** (output) — fires if the read operation fails
|
|
10
|
+
|
|
11
|
+
## Properties
|
|
12
|
+
|
|
13
|
+
- **FilePath** — the path to the file to read
|
|
14
|
+
- **Encoding** — character encoding for text files (e.g. `utf8`, `ascii`)
|
|
15
|
+
|
|
16
|
+
## Behavior
|
|
17
|
+
|
|
18
|
+
When triggered, the node reads the file at the configured path. On success, the raw file contents are emitted from the **Data** output. If the file does not exist or cannot be read, the **Error** output fires with a descriptive error message.
|
|
19
|
+
|
|
20
|
+
## Tips
|
|
21
|
+
|
|
22
|
+
- Use a Get Value node upstream to dynamically set the file path
|
|
23
|
+
- Pair with a Data Preview node to inspect the file contents
|
|
24
|
+
- Connect the **Error** output to logging or notification nodes for robust error handling
|