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,235 @@
1
+ # PictFlowCardPropertiesPanel
2
+
3
+ Base class for flow card property panels. Extend this class to create custom panel types beyond the four built-in types (Template, Markdown, Form, View).
4
+
5
+ ## Import
6
+
7
+ ```javascript
8
+ const libPictFlowCardPropertiesPanel = require('pict-section-flow').PictFlowCardPropertiesPanel;
9
+ ```
10
+
11
+ ## Constructor
12
+
13
+ ```javascript
14
+ class MyPanel extends libPictFlowCardPropertiesPanel
15
+ {
16
+ constructor(pFable, pOptions, pServiceHash)
17
+ {
18
+ super(pFable, Object.assign({},
19
+ {
20
+ PanelType: 'Custom',
21
+ Title: 'My Panel',
22
+ Width: 300,
23
+ Height: 200,
24
+ Configuration: {}
25
+ }, pOptions), pServiceHash);
26
+ }
27
+ }
28
+ ```
29
+
30
+ ## Configuration Options
31
+
32
+ | Property | Type | Default | Description |
33
+ |----------|------|---------|-------------|
34
+ | `PanelType` | string | `'Base'` | Panel type identifier |
35
+ | `Title` | string | `'Properties'` | Panel title bar text |
36
+ | `Width` | number | `300` | Default width in pixels |
37
+ | `Height` | number | `200` | Default height in pixels |
38
+ | `Configuration` | object | `{}` | Panel-type-specific config |
39
+
40
+ ## Methods to Override
41
+
42
+ ### render(pContainer, pNodeData)
43
+
44
+ Render the panel's content into a DOM container element. Subclasses **must** override this.
45
+
46
+ | Parameter | Type | Description |
47
+ |-----------|------|-------------|
48
+ | `pContainer` | HTMLElement | The DOM element to render into |
49
+ | `pNodeData` | object | The node data object (has `.Data` property) |
50
+
51
+ ### marshalToPanel(pNodeData)
52
+
53
+ Marshal data from the node's Data object into the panel UI. Called when the panel opens or when data changes externally.
54
+
55
+ | Parameter | Type | Description |
56
+ |-----------|------|-------------|
57
+ | `pNodeData` | object | The node data object |
58
+
59
+ ### marshalFromPanel(pNodeData)
60
+
61
+ Marshal data from the panel UI into the node's Data object. Called before saving or when the panel is about to close.
62
+
63
+ | Parameter | Type | Description |
64
+ |-----------|------|-------------|
65
+ | `pNodeData` | object | The node data object to update |
66
+
67
+ ### destroy()
68
+
69
+ Called when the panel is being closed. Clean up resources, event listeners, etc.
70
+
71
+ ## Internal Properties
72
+
73
+ | Property | Type | Description |
74
+ |----------|------|-------------|
75
+ | `this._FlowView` | PictViewFlow | Reference to the flow view (set when panel is activated) |
76
+ | `this._NodeData` | object | The node data this panel is operating on |
77
+ | `this._ContentContainer` | HTMLElement | The DOM container element |
78
+ | `this._Configuration` | object | Panel-type-specific configuration |
79
+
80
+ ## Built-in Panel Types
81
+
82
+ ### Template
83
+
84
+ Renders Pict templates inside the panel.
85
+
86
+ ```javascript
87
+ {
88
+ PanelType: 'Template',
89
+ Configuration:
90
+ {
91
+ Templates:
92
+ [
93
+ {
94
+ Hash: 'my-template',
95
+ Template: '<div class="info">{~D:Record.Data.Label~}</div>'
96
+ }
97
+ ],
98
+ TemplateHash: 'my-template'
99
+ }
100
+ }
101
+ ```
102
+
103
+ ### Markdown
104
+
105
+ Renders markdown content via `pict-section-content`.
106
+
107
+ ```javascript
108
+ {
109
+ PanelType: 'Markdown',
110
+ Configuration:
111
+ {
112
+ Markdown: '## Help\nThis node reads a file from disk.\n\n**Inputs:** File path\n**Outputs:** File contents or error'
113
+ }
114
+ }
115
+ ```
116
+
117
+ ### Form
118
+
119
+ Creates an ephemeral `pict-section-form` section.
120
+
121
+ ```javascript
122
+ {
123
+ PanelType: 'Form',
124
+ Configuration:
125
+ {
126
+ Fields:
127
+ [
128
+ { Name: 'FilePath', DataType: 'String' },
129
+ { Name: 'Encoding', DataType: 'String' },
130
+ { Name: 'MaxSize', DataType: 'Number' }
131
+ ]
132
+ }
133
+ }
134
+ ```
135
+
136
+ ### View
137
+
138
+ Renders an existing registered Pict view inside the panel.
139
+
140
+ ```javascript
141
+ {
142
+ PanelType: 'View',
143
+ Configuration:
144
+ {
145
+ ViewHash: 'my-custom-view'
146
+ }
147
+ }
148
+ ```
149
+
150
+ ## Examples
151
+
152
+ ### Custom chart panel
153
+
154
+ ```javascript
155
+ class ChartPanel extends libPictFlowCardPropertiesPanel
156
+ {
157
+ constructor(pFable, pOptions, pServiceHash)
158
+ {
159
+ super(pFable, Object.assign({},
160
+ {
161
+ PanelType: 'Chart',
162
+ Title: 'Data Preview',
163
+ Width: 400,
164
+ Height: 300
165
+ }, pOptions), pServiceHash);
166
+
167
+ this._ChartInstance = null;
168
+ }
169
+
170
+ render(pContainer, pNodeData)
171
+ {
172
+ super.render(pContainer, pNodeData);
173
+
174
+ let tmpCanvas = document.createElement('canvas');
175
+ tmpCanvas.width = 380;
176
+ tmpCanvas.height = 260;
177
+ pContainer.appendChild(tmpCanvas);
178
+
179
+ // Create chart from node data
180
+ this._ChartInstance = new Chart(tmpCanvas,
181
+ {
182
+ type: 'line',
183
+ data: pNodeData.Data.ChartData || { labels: [], datasets: [] }
184
+ });
185
+ }
186
+
187
+ marshalToPanel(pNodeData)
188
+ {
189
+ super.marshalToPanel(pNodeData);
190
+ if (this._ChartInstance && pNodeData.Data.ChartData)
191
+ {
192
+ this._ChartInstance.data = pNodeData.Data.ChartData;
193
+ this._ChartInstance.update();
194
+ }
195
+ }
196
+
197
+ destroy()
198
+ {
199
+ if (this._ChartInstance)
200
+ {
201
+ this._ChartInstance.destroy();
202
+ this._ChartInstance = null;
203
+ }
204
+ super.destroy();
205
+ }
206
+ }
207
+ ```
208
+
209
+ ### Using a custom panel in a card
210
+
211
+ ```javascript
212
+ class DataPreviewCard extends libPictFlowCard
213
+ {
214
+ constructor(pFable, pOptions, pServiceHash)
215
+ {
216
+ super(pFable, Object.assign({},
217
+ {
218
+ Title: 'Data Preview',
219
+ Code: 'DPRV',
220
+ PropertiesPanel:
221
+ {
222
+ PanelType: 'Chart',
223
+ Title: 'Preview',
224
+ DefaultWidth: 400,
225
+ DefaultHeight: 300
226
+ }
227
+ }, pOptions), pServiceHash);
228
+ }
229
+ }
230
+ ```
231
+
232
+ ## See Also
233
+
234
+ - [PictFlowCard](PictFlowCard.md) — Define cards that use panels
235
+ - [openPanel / closePanel](openPanel.md) — Panel lifecycle methods
@@ -0,0 +1,101 @@
1
+ # addConnection
2
+
3
+ Connect two ports on the flow canvas. Creates a visual line between the source port (typically an output) and the target port (typically an input). The connection is validated before creation.
4
+
5
+ ## Signature
6
+
7
+ ```javascript
8
+ flowView.addConnection(pSourceNode, pSourcePort, pTargetNode, pTargetPort, pData)
9
+ ```
10
+
11
+ ## Parameters
12
+
13
+ | Parameter | Type | Required | Description |
14
+ |-----------|------|----------|-------------|
15
+ | `pSourceNode` | string | Yes | Hash of the source node |
16
+ | `pSourcePort` | string | Yes | Hash of the source port |
17
+ | `pTargetNode` | string | Yes | Hash of the target node |
18
+ | `pTargetPort` | string | Yes | Hash of the target port |
19
+ | `pData` | object | No | Optional connection metadata |
20
+
21
+ ### Connection Data Options
22
+
23
+ | Property | Type | Default | Description |
24
+ |----------|------|---------|-------------|
25
+ | `LineMode` | string | `'bezier'` | Path style: `'bezier'` or `'orthogonal'` |
26
+
27
+ ## Returns
28
+
29
+ The connection object on success, or `false` if validation failed (e.g. duplicate connection, self-connection, or port not found).
30
+
31
+ ```javascript
32
+ {
33
+ Hash: 'conn-x1y2z3',
34
+ SourceNodeHash: 'node-a1b2',
35
+ SourcePortHash: 'port-c3d4',
36
+ TargetNodeHash: 'node-e5f6',
37
+ TargetPortHash: 'port-g7h8',
38
+ Data:
39
+ {
40
+ LineMode: 'bezier',
41
+ HandleCustomized: false
42
+ }
43
+ }
44
+ ```
45
+
46
+ ## Events Fired
47
+
48
+ - `onConnectionCreated` — with the new connection object
49
+ - `onFlowChanged` — with the complete flow data
50
+
51
+ ## Examples
52
+
53
+ ### Basic connection
54
+
55
+ ```javascript
56
+ let tmpStart = flowView.addNode('start', 50, 150, 'Begin');
57
+ let tmpEnd = flowView.addNode('end', 400, 150, 'Done');
58
+
59
+ let tmpOutPort = tmpStart.Ports.find((pPort) => pPort.Direction === 'output');
60
+ let tmpInPort = tmpEnd.Ports.find((pPort) => pPort.Direction === 'input');
61
+
62
+ let tmpConn = flowView.addConnection(
63
+ tmpStart.Hash, tmpOutPort.Hash,
64
+ tmpEnd.Hash, tmpInPort.Hash
65
+ );
66
+
67
+ console.log(tmpConn.Hash); // 'conn-...'
68
+ ```
69
+
70
+ ### Orthogonal connection
71
+
72
+ ```javascript
73
+ let tmpConn = flowView.addConnection(
74
+ tmpA.Hash, tmpOutPort.Hash,
75
+ tmpB.Hash, tmpInPort.Hash,
76
+ { LineMode: 'orthogonal' }
77
+ );
78
+ ```
79
+
80
+ ### Decision node branching
81
+
82
+ ```javascript
83
+ let tmpDecision = flowView.addNode('decision', 200, 150, 'Check Status');
84
+ let tmpSuccess = flowView.addNode('default', 400, 50, 'Handle Success');
85
+ let tmpFailure = flowView.addNode('halt', 400, 250, 'Handle Error');
86
+
87
+ // Find the Yes and No output ports on the decision node
88
+ let tmpYesPort = tmpDecision.Ports.find((pPort) => pPort.Label === 'Yes');
89
+ let tmpNoPort = tmpDecision.Ports.find((pPort) => pPort.Label === 'No');
90
+
91
+ let tmpSuccessIn = tmpSuccess.Ports.find((pPort) => pPort.Direction === 'input');
92
+ let tmpFailureIn = tmpFailure.Ports.find((pPort) => pPort.Direction === 'input');
93
+
94
+ flowView.addConnection(tmpDecision.Hash, tmpYesPort.Hash, tmpSuccess.Hash, tmpSuccessIn.Hash);
95
+ flowView.addConnection(tmpDecision.Hash, tmpNoPort.Hash, tmpFailure.Hash, tmpFailureIn.Hash);
96
+ ```
97
+
98
+ ## See Also
99
+
100
+ - [removeConnection](removeConnection.md) — Delete a connection
101
+ - [addNode](addNode.md) — Create nodes to connect
@@ -0,0 +1,137 @@
1
+ # addNode
2
+
3
+ Create a new node on the flow canvas. The node is added to the flow data, assigned a UUID hash, populated with default ports from the node type definition, and the canvas is re-rendered.
4
+
5
+ ## Signature
6
+
7
+ ```javascript
8
+ flowView.addNode(pType, pX, pY, pTitle, pData)
9
+ ```
10
+
11
+ ## Parameters
12
+
13
+ | Parameter | Type | Required | Description |
14
+ |-----------|------|----------|-------------|
15
+ | `pType` | string | Yes | Node type key. Built-in types: `'start'`, `'end'`, `'halt'`, `'decision'`, `'default'`. Custom types use the `Code` from a registered `PictFlowCard`. |
16
+ | `pX` | number | Yes | X coordinate in SVG space |
17
+ | `pY` | number | Yes | Y coordinate in SVG space |
18
+ | `pTitle` | string | Yes | Display title shown on the node's title bar |
19
+ | `pData` | object | No | Optional custom data object attached to the node's `Data` property |
20
+
21
+ ## Returns
22
+
23
+ The newly created node object:
24
+
25
+ ```javascript
26
+ {
27
+ Hash: 'node-a1b2c3d4',
28
+ Type: 'start',
29
+ X: 50,
30
+ Y: 150,
31
+ Width: 140,
32
+ Height: 80,
33
+ Title: 'Begin',
34
+ Ports:
35
+ [
36
+ {
37
+ Hash: 'port-e5f6g7h8',
38
+ Direction: 'output',
39
+ Side: 'right',
40
+ Label: 'Out'
41
+ }
42
+ ],
43
+ Data: {}
44
+ }
45
+ ```
46
+
47
+ ## Events Fired
48
+
49
+ - `onNodeAdded` — with the new node object
50
+ - `onFlowChanged` — with the complete flow data
51
+
52
+ ## Examples
53
+
54
+ ### Basic usage
55
+
56
+ ```javascript
57
+ // Add a start node at position (50, 150)
58
+ let tmpStart = flowView.addNode('start', 50, 150, 'Begin');
59
+
60
+ // Add a processing node
61
+ let tmpProcess = flowView.addNode('default', 250, 150, 'Transform Data');
62
+
63
+ // Add an end node
64
+ let tmpEnd = flowView.addNode('end', 450, 150, 'Done');
65
+ ```
66
+
67
+ ### With custom data
68
+
69
+ ```javascript
70
+ let tmpFileRead = flowView.addNode('FREAD', 100, 200, 'Read Config',
71
+ {
72
+ FilePath: '/etc/app/config.json',
73
+ Encoding: 'utf-8'
74
+ });
75
+
76
+ console.log(tmpFileRead.Data.FilePath); // '/etc/app/config.json'
77
+ ```
78
+
79
+ ### Adding a decision node
80
+
81
+ ```javascript
82
+ let tmpDecision = flowView.addNode('decision', 300, 200, 'Is Valid?');
83
+
84
+ // The decision node has three ports by default: In, Yes, No
85
+ console.log(tmpDecision.Ports.length); // 3
86
+ ```
87
+
88
+ ### Programmatic flow construction
89
+
90
+ ```javascript
91
+ function buildPipeline(pFlowView, pSteps)
92
+ {
93
+ let tmpPreviousNode = null;
94
+
95
+ for (let i = 0; i < pSteps.length; i++)
96
+ {
97
+ let tmpNode = pFlowView.addNode(
98
+ pSteps[i].Type,
99
+ 100 + (i * 200),
100
+ 150,
101
+ pSteps[i].Title,
102
+ pSteps[i].Data
103
+ );
104
+
105
+ if (tmpPreviousNode)
106
+ {
107
+ let tmpOutPort = tmpPreviousNode.Ports.find((pPort) => pPort.Direction === 'output');
108
+ let tmpInPort = tmpNode.Ports.find((pPort) => pPort.Direction === 'input');
109
+
110
+ if (tmpOutPort && tmpInPort)
111
+ {
112
+ pFlowView.addConnection(
113
+ tmpPreviousNode.Hash, tmpOutPort.Hash,
114
+ tmpNode.Hash, tmpInPort.Hash
115
+ );
116
+ }
117
+ }
118
+
119
+ tmpPreviousNode = tmpNode;
120
+ }
121
+ }
122
+
123
+ buildPipeline(flowView,
124
+ [
125
+ { Type: 'start', Title: 'Begin' },
126
+ { Type: 'FREAD', Title: 'Load Data', Data: { FilePath: '/data/input.csv' } },
127
+ { Type: 'default', Title: 'Process' },
128
+ { Type: 'end', Title: 'Complete' }
129
+ ]);
130
+ ```
131
+
132
+ ## See Also
133
+
134
+ - [removeNode](removeNode.md) — Delete a node
135
+ - [getFlowData](getFlowData.md) — Retrieve the full flow state
136
+ - [PictFlowCard](PictFlowCard.md) — Define custom node types
137
+ - [registerNodeType](registerNodeType.md) — Register node types directly
@@ -0,0 +1,77 @@
1
+ # autoLayout
2
+
3
+ Automatically arrange all nodes in the flow using a topological sort algorithm. Nodes are positioned in columns based on their dependency order, with even vertical spacing within each column. This is useful for organizing complex flows or providing a clean starting arrangement.
4
+
5
+ ## Signature
6
+
7
+ ```javascript
8
+ flowView.autoLayout();
9
+ ```
10
+
11
+ ## Parameters
12
+
13
+ None.
14
+
15
+ ## Behavior
16
+
17
+ 1. Performs a topological sort of the node graph based on connections
18
+ 2. Assigns nodes to columns (layers) based on their depth from root nodes
19
+ 3. Distributes nodes evenly within each column
20
+ 4. Re-renders the entire canvas
21
+ 5. Optionally snaps to grid if `EnableGridSnap` is `true`
22
+
23
+ Nodes with no connections are placed in a separate area to the side.
24
+
25
+ ## Examples
26
+
27
+ ### Basic usage
28
+
29
+ ```javascript
30
+ // After constructing a complex flow programmatically
31
+ flowView.autoLayout();
32
+ flowView.zoomToFit();
33
+ ```
34
+
35
+ ### Auto-layout after data load
36
+
37
+ ```javascript
38
+ fetch('/api/flows/my-flow')
39
+ .then((pResponse) => pResponse.json())
40
+ .then((pFlowData) =>
41
+ {
42
+ flowView.setFlowData(pFlowData);
43
+ flowView.autoLayout();
44
+ flowView.zoomToFit();
45
+ });
46
+ ```
47
+
48
+ ### Layout button
49
+
50
+ ```javascript
51
+ document.getElementById('auto-layout-btn').addEventListener('click', () =>
52
+ {
53
+ flowView.autoLayout();
54
+ flowView.zoomToFit();
55
+ });
56
+ ```
57
+
58
+ ## Grid Snap
59
+
60
+ When `EnableGridSnap` is `true`, the auto-layout algorithm snaps node positions to the nearest grid point based on `GridSnapSize`:
61
+
62
+ ```javascript
63
+ _Pict.addView('MyFlow',
64
+ {
65
+ EnableGridSnap: true,
66
+ GridSnapSize: 20
67
+ },
68
+ libPictSectionFlow);
69
+
70
+ // Auto-layout will snap to 20px grid
71
+ flowView.autoLayout();
72
+ ```
73
+
74
+ ## See Also
75
+
76
+ - [setZoom / zoomToFit](setZoom.md) — Fit the result in the viewport
77
+ - [saveLayout / restoreLayout](saveLayout.md) — Persist spatial arrangements
@@ -0,0 +1,112 @@
1
+ # getFlowData / setFlowData
2
+
3
+ Get or replace the entire flow state. `getFlowData` returns a deep clone so mutations do not affect the live state. `setFlowData` replaces the flow data and triggers a full re-render.
4
+
5
+ ## Signatures
6
+
7
+ ```javascript
8
+ let tmpFlowData = flowView.getFlowData();
9
+ flowView.setFlowData(pFlowData);
10
+ ```
11
+
12
+ ## getFlowData
13
+
14
+ ### Parameters
15
+
16
+ None.
17
+
18
+ ### Returns
19
+
20
+ A deep clone of the complete flow state:
21
+
22
+ ```javascript
23
+ {
24
+ Nodes: [ /* ... */ ],
25
+ Connections: [ /* ... */ ],
26
+ OpenPanels: [ /* ... */ ],
27
+ SavedLayouts: [ /* ... */ ],
28
+ ViewState:
29
+ {
30
+ PanX: 0,
31
+ PanY: 0,
32
+ Zoom: 1,
33
+ SelectedNodeHash: null,
34
+ SelectedConnectionHash: null,
35
+ SelectedTetherHash: null
36
+ }
37
+ }
38
+ ```
39
+
40
+ ## setFlowData
41
+
42
+ ### Parameters
43
+
44
+ | Parameter | Type | Required | Description |
45
+ |-----------|------|----------|-------------|
46
+ | `pFlowData` | object | Yes | Complete flow data structure |
47
+
48
+ ### Events Fired
49
+
50
+ - `onFlowChanged` — with the new flow data
51
+
52
+ ## Examples
53
+
54
+ ### Save flow state to a server
55
+
56
+ ```javascript
57
+ let tmpFlowData = flowView.getFlowData();
58
+
59
+ fetch('/api/flows/my-flow',
60
+ {
61
+ method: 'PUT',
62
+ headers: { 'Content-Type': 'application/json' },
63
+ body: JSON.stringify(tmpFlowData)
64
+ });
65
+ ```
66
+
67
+ ### Load flow state from a server
68
+
69
+ ```javascript
70
+ fetch('/api/flows/my-flow')
71
+ .then((pResponse) => pResponse.json())
72
+ .then((pFlowData) =>
73
+ {
74
+ flowView.setFlowData(pFlowData);
75
+ });
76
+ ```
77
+
78
+ ### Clone a flow
79
+
80
+ ```javascript
81
+ let tmpOriginal = flowView.getFlowData();
82
+
83
+ // Modify the clone without affecting the original
84
+ tmpOriginal.Nodes.forEach((pNode) =>
85
+ {
86
+ pNode.X += 200;
87
+ });
88
+
89
+ flowView.setFlowData(tmpOriginal);
90
+ ```
91
+
92
+ ### Inspect flow statistics
93
+
94
+ ```javascript
95
+ let tmpData = flowView.getFlowData();
96
+
97
+ console.log('Nodes:', tmpData.Nodes.length);
98
+ console.log('Connections:', tmpData.Connections.length);
99
+ console.log('Open Panels:', tmpData.OpenPanels.length);
100
+ console.log('Saved Layouts:', tmpData.SavedLayouts.length);
101
+ console.log('Zoom:', tmpData.ViewState.Zoom);
102
+ ```
103
+
104
+ ## Related Methods
105
+
106
+ - `getNode(pNodeHash)` — Retrieve a single node by hash
107
+ - `getConnection(pConnectionHash)` — Retrieve a single connection by hash
108
+
109
+ ## See Also
110
+
111
+ - [marshalToView / marshalFromView](marshalToView.md) — AppData two-way binding
112
+ - [addNode](addNode.md) — Add individual nodes