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.
Files changed (88) hide show
  1. package/.claude/launch.json +1 -1
  2. package/README.md +176 -0
  3. package/docs/.nojekyll +0 -0
  4. package/docs/Architecture.md +303 -0
  5. package/docs/Custom-Styling.md +275 -0
  6. package/docs/Data_Model.md +158 -0
  7. package/docs/Event_System.md +156 -0
  8. package/docs/Getting_Started.md +237 -0
  9. package/docs/Implementation_Reference.md +528 -0
  10. package/docs/Layout_Persistence.md +117 -0
  11. package/docs/README.md +115 -52
  12. package/docs/_cover.md +11 -0
  13. package/docs/_sidebar.md +52 -0
  14. package/docs/_topbar.md +8 -0
  15. package/docs/api/PictFlowCard.md +216 -0
  16. package/docs/api/PictFlowCardPropertiesPanel.md +235 -0
  17. package/docs/api/addConnection.md +101 -0
  18. package/docs/api/addNode.md +137 -0
  19. package/docs/api/autoLayout.md +77 -0
  20. package/docs/api/getFlowData.md +112 -0
  21. package/docs/api/marshalToView.md +95 -0
  22. package/docs/api/openPanel.md +128 -0
  23. package/docs/api/registerHandler.md +174 -0
  24. package/docs/api/registerNodeType.md +142 -0
  25. package/docs/api/removeConnection.md +57 -0
  26. package/docs/api/removeNode.md +80 -0
  27. package/docs/api/saveLayout.md +152 -0
  28. package/docs/api/screenToSVGCoords.md +68 -0
  29. package/docs/api/selectNode.md +116 -0
  30. package/docs/api/setTheme.md +168 -0
  31. package/docs/api/setZoom.md +97 -0
  32. package/docs/api/toggleFullscreen.md +68 -0
  33. package/docs/card-help/EACH.md +19 -0
  34. package/docs/card-help/FREAD.md +24 -0
  35. package/docs/card-help/FWRITE.md +24 -0
  36. package/docs/card-help/GET.md +22 -0
  37. package/docs/card-help/ITE.md +23 -0
  38. package/docs/card-help/LOG.md +23 -0
  39. package/docs/card-help/NOTE.md +17 -0
  40. package/docs/card-help/PREV.md +18 -0
  41. package/docs/card-help/SET.md +27 -0
  42. package/docs/card-help/SPKL.md +22 -0
  43. package/docs/card-help/STAT.md +23 -0
  44. package/docs/card-help/SW.md +25 -0
  45. package/docs/css/docuserve.css +73 -0
  46. package/docs/index.html +39 -0
  47. package/docs/retold-catalog.json +169 -0
  48. package/docs/retold-keyword-index.json +13942 -0
  49. package/example_applications/simple_cards/package.json +1 -0
  50. package/example_applications/simple_cards/source/card-help-content.js +16 -0
  51. package/example_applications/simple_cards/source/cards/FlowCard-Comment.js +2 -0
  52. package/example_applications/simple_cards/source/cards/FlowCard-DataPreview.js +2 -0
  53. package/example_applications/simple_cards/source/cards/FlowCard-Each.js +2 -0
  54. package/example_applications/simple_cards/source/cards/FlowCard-FileRead.js +2 -0
  55. package/example_applications/simple_cards/source/cards/FlowCard-FileWrite.js +2 -0
  56. package/example_applications/simple_cards/source/cards/FlowCard-GetValue.js +2 -0
  57. package/example_applications/simple_cards/source/cards/FlowCard-IfThenElse.js +2 -0
  58. package/example_applications/simple_cards/source/cards/FlowCard-LogValues.js +2 -0
  59. package/example_applications/simple_cards/source/cards/FlowCard-SetValue.js +2 -0
  60. package/example_applications/simple_cards/source/cards/FlowCard-Sparkline.js +2 -0
  61. package/example_applications/simple_cards/source/cards/FlowCard-StatusMonitor.js +2 -0
  62. package/example_applications/simple_cards/source/cards/FlowCard-Switch.js +2 -0
  63. package/package.json +11 -7
  64. package/scripts/generate-card-help.js +214 -0
  65. package/source/Pict-Section-Flow.js +4 -0
  66. package/source/PictFlowCard.js +3 -1
  67. package/source/providers/PictProvider-Flow-CSS.js +245 -152
  68. package/source/providers/PictProvider-Flow-ConnectorShapes.js +24 -0
  69. package/source/providers/PictProvider-Flow-Geometry.js +195 -38
  70. package/source/providers/PictProvider-Flow-PanelChrome.js +14 -12
  71. package/source/services/PictService-Flow-ConnectionHandleManager.js +263 -0
  72. package/source/services/PictService-Flow-ConnectionRenderer.js +134 -183
  73. package/source/services/PictService-Flow-DataManager.js +338 -0
  74. package/source/services/PictService-Flow-InteractionManager.js +165 -7
  75. package/source/services/PictService-Flow-PathGenerator.js +282 -0
  76. package/source/services/PictService-Flow-PortRenderer.js +269 -0
  77. package/source/services/PictService-Flow-RenderManager.js +281 -0
  78. package/source/services/PictService-Flow-Tether.js +6 -42
  79. package/source/views/PictView-Flow-Node.js +2 -220
  80. package/source/views/PictView-Flow-PropertiesPanel.js +89 -44
  81. package/source/views/PictView-Flow.js +130 -882
  82. package/test/ConnectionHandleManager_tests.js +717 -0
  83. package/test/ConnectionRenderer_tests.js +591 -0
  84. package/test/DataManager_tests.js +859 -0
  85. package/test/Geometry_tests.js +767 -0
  86. package/test/PathGenerator_tests.js +978 -0
  87. package/test/PortRenderer_tests.js +367 -0
  88. 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