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,528 @@
1
+ # Implementation Reference
2
+
3
+ Complete API reference for Pict-Section-Flow. This document covers every public method on the main `PictViewFlow` class and the key internal services and providers developers interact with.
4
+
5
+ ## PictViewFlow — Main View API
6
+
7
+ The primary class exported by `pict-section-flow`. Extends `pict-view`.
8
+
9
+ ### Configuration
10
+
11
+ ```javascript
12
+ const libPictSectionFlow = require('pict-section-flow');
13
+
14
+ _Pict.addView('MyFlow',
15
+ {
16
+ ViewIdentifier: 'Pict-Flow',
17
+ DefaultDestinationAddress: '#flow-container',
18
+ FlowDataAddress: 'AppData.MyFlow',
19
+
20
+ EnableToolbar: true,
21
+ EnablePanning: true,
22
+ EnableZooming: true,
23
+ EnableNodeDragging: true,
24
+ EnableConnectionCreation: true,
25
+ EnableGridSnap: false,
26
+ GridSnapSize: 20,
27
+
28
+ MinZoom: 0.1,
29
+ MaxZoom: 5.0,
30
+ ZoomStep: 0.1,
31
+
32
+ DefaultNodeType: 'default',
33
+ DefaultNodeWidth: 180,
34
+ DefaultNodeHeight: 80,
35
+
36
+ Theme: 'default'
37
+ },
38
+ libPictSectionFlow);
39
+ ```
40
+
41
+ | Option | Type | Default | Description |
42
+ |--------|------|---------|-------------|
43
+ | `ViewIdentifier` | string | `'Pict-Flow'` | Unique identifier for debugging and DOM IDs |
44
+ | `DefaultDestinationAddress` | string | `'#Flow-Container'` | CSS selector for the container element |
45
+ | `FlowDataAddress` | string/false | `false` | AppData path for two-way binding |
46
+ | `EnableToolbar` | boolean | `true` | Show the toolbar UI |
47
+ | `EnablePanning` | boolean | `true` | Allow canvas panning |
48
+ | `EnableZooming` | boolean | `true` | Allow canvas zooming |
49
+ | `EnableNodeDragging` | boolean | `true` | Allow node repositioning |
50
+ | `EnableConnectionCreation` | boolean | `true` | Allow creating port-to-port connections |
51
+ | `EnableGridSnap` | boolean | `false` | Snap node positions to grid |
52
+ | `GridSnapSize` | number | `20` | Grid cell size in pixels |
53
+ | `MinZoom` | number | `0.1` | Minimum zoom level |
54
+ | `MaxZoom` | number | `5.0` | Maximum zoom level |
55
+ | `ZoomStep` | number | `0.1` | Zoom increment per scroll tick |
56
+ | `DefaultNodeType` | string | `'default'` | Node type when none specified |
57
+ | `DefaultNodeWidth` | number | `180` | Default node width in pixels |
58
+ | `DefaultNodeHeight` | number | `80` | Default node height in pixels |
59
+ | `Theme` | string | `'default'` | Active theme key |
60
+
61
+ ---
62
+
63
+ ## Data Management Methods
64
+
65
+ ### addNode(pType, pX, pY, pTitle, pData)
66
+
67
+ Create a new node on the canvas.
68
+
69
+ | Parameter | Type | Description |
70
+ |-----------|------|-------------|
71
+ | `pType` | string | Node type key (e.g. `'start'`, `'default'`, or a custom card code) |
72
+ | `pX` | number | X coordinate in SVG space |
73
+ | `pY` | number | Y coordinate in SVG space |
74
+ | `pTitle` | string | Display title |
75
+ | `pData` | object | Optional custom data attached to the node |
76
+
77
+ **Returns:** Node object with `Hash`, `Ports`, `Type`, etc.
78
+
79
+ ### removeNode(pNodeHash)
80
+
81
+ Delete a node and all its connections.
82
+
83
+ | Parameter | Type | Description |
84
+ |-----------|------|-------------|
85
+ | `pNodeHash` | string | Hash of the node to remove |
86
+
87
+ **Returns:** `boolean` — `true` if the node was found and removed.
88
+
89
+ ### addConnection(pSourceNode, pSourcePort, pTargetNode, pTargetPort, pData)
90
+
91
+ Connect two ports.
92
+
93
+ | Parameter | Type | Description |
94
+ |-----------|------|-------------|
95
+ | `pSourceNode` | string | Source node hash |
96
+ | `pSourcePort` | string | Source port hash |
97
+ | `pTargetNode` | string | Target node hash |
98
+ | `pTargetPort` | string | Target port hash |
99
+ | `pData` | object | Optional connection data (e.g. `{ LineMode: 'orthogonal' }`) |
100
+
101
+ **Returns:** Connection object, or `false` if validation failed.
102
+
103
+ ### removeConnection(pConnectionHash)
104
+
105
+ Delete a connection.
106
+
107
+ | Parameter | Type | Description |
108
+ |-----------|------|-------------|
109
+ | `pConnectionHash` | string | Hash of the connection to remove |
110
+
111
+ **Returns:** `boolean` — `true` if the connection was found and removed.
112
+
113
+ ### getFlowData()
114
+
115
+ Get a deep clone of the complete flow state.
116
+
117
+ **Returns:** `{ Nodes, Connections, OpenPanels, SavedLayouts, ViewState }`
118
+
119
+ ### setFlowData(pFlowData)
120
+
121
+ Replace the entire flow state and re-render.
122
+
123
+ | Parameter | Type | Description |
124
+ |-----------|------|-------------|
125
+ | `pFlowData` | object | Complete flow data structure |
126
+
127
+ ### getNode(pNodeHash)
128
+
129
+ Retrieve a node object by hash.
130
+
131
+ **Returns:** Node object or `undefined`.
132
+
133
+ ### getConnection(pConnectionHash)
134
+
135
+ Retrieve a connection object by hash.
136
+
137
+ **Returns:** Connection object or `undefined`.
138
+
139
+ ### marshalToView()
140
+
141
+ Load flow data from the AppData address specified in `FlowDataAddress` and render.
142
+
143
+ ### marshalFromView()
144
+
145
+ Write the current flow data back to the AppData address specified in `FlowDataAddress`.
146
+
147
+ ---
148
+
149
+ ## Selection Methods
150
+
151
+ ### selectNode(pNodeHash)
152
+
153
+ Select a node. Pass `null` to deselect.
154
+
155
+ ### selectConnection(pConnectionHash)
156
+
157
+ Select a connection. Pass `null` to deselect.
158
+
159
+ ### selectTether(pPanelHash)
160
+
161
+ Select a tether line. Pass `null` to deselect.
162
+
163
+ ### deselectAll()
164
+
165
+ Clear all selections (node, connection, and tether).
166
+
167
+ ### deleteSelected()
168
+
169
+ Delete the currently selected node or connection.
170
+
171
+ **Returns:** `boolean` — `true` if something was deleted.
172
+
173
+ ---
174
+
175
+ ## Viewport Methods
176
+
177
+ ### setZoom(pZoom, pFocusX, pFocusY)
178
+
179
+ Set the zoom level with an optional focus point.
180
+
181
+ | Parameter | Type | Description |
182
+ |-----------|------|-------------|
183
+ | `pZoom` | number | Target zoom level (clamped to MinZoom..MaxZoom) |
184
+ | `pFocusX` | number | Optional X focus point in SVG space |
185
+ | `pFocusY` | number | Optional Y focus point in SVG space |
186
+
187
+ ### zoomToFit()
188
+
189
+ Automatically adjust pan and zoom to fit all nodes in the viewport.
190
+
191
+ ### updateViewportTransform()
192
+
193
+ Apply the current pan/zoom state to the SVG viewport group. Called automatically after pan/zoom changes.
194
+
195
+ ### toggleFullscreen()
196
+
197
+ Toggle fullscreen overlay mode.
198
+
199
+ **Returns:** `boolean` — the new fullscreen state.
200
+
201
+ ### exitFullscreen()
202
+
203
+ Exit fullscreen mode.
204
+
205
+ ### screenToSVGCoords(pScreenX, pScreenY)
206
+
207
+ Convert screen pixel coordinates to SVG coordinate space.
208
+
209
+ **Returns:** `{ x, y }`
210
+
211
+ ### autoLayout()
212
+
213
+ Run the topological auto-layout algorithm to arrange nodes automatically.
214
+
215
+ ---
216
+
217
+ ## Panel Methods
218
+
219
+ ### openPanel(pNodeHash)
220
+
221
+ Open a properties panel for a node.
222
+
223
+ **Returns:** Panel data object, or `false` if the node has no panel configuration.
224
+
225
+ ### closePanel(pPanelHash)
226
+
227
+ Close a panel by its hash.
228
+
229
+ **Returns:** `boolean`
230
+
231
+ ### closePanelForNode(pNodeHash)
232
+
233
+ Close all panels associated with a node.
234
+
235
+ **Returns:** `boolean`
236
+
237
+ ### togglePanel(pNodeHash)
238
+
239
+ Toggle a node's panel open or closed.
240
+
241
+ **Returns:** Panel data object or `false`.
242
+
243
+ ### updatePanelPosition(pPanelHash, pX, pY)
244
+
245
+ Move a panel to new coordinates.
246
+
247
+ ---
248
+
249
+ ## Theming Methods
250
+
251
+ ### setTheme(pThemeKey)
252
+
253
+ Switch to a registered theme and re-render.
254
+
255
+ | Parameter | Type | Description |
256
+ |-----------|------|-------------|
257
+ | `pThemeKey` | string | Theme key (e.g. `'default'`, `'sketch'`, `'blueprint'`) |
258
+
259
+ ### setNoiseLevel(pLevel)
260
+
261
+ Set the hand-drawn noise level.
262
+
263
+ | Parameter | Type | Description |
264
+ |-----------|------|-------------|
265
+ | `pLevel` | number | 0 (precise) to 1 (wobbly) |
266
+
267
+ ### getNoiseLevel()
268
+
269
+ **Returns:** Current noise level (number).
270
+
271
+ ### getThemeKey()
272
+
273
+ **Returns:** Active theme key (string).
274
+
275
+ ---
276
+
277
+ ## Rendering Methods
278
+
279
+ ### renderFlow()
280
+
281
+ Full re-render of all nodes, connections, panels, and tethers.
282
+
283
+ ### updateNodePosition(pNodeHash, pX, pY)
284
+
285
+ Update a node's position during drag. Performs selective re-rendering of only the affected elements for smooth performance.
286
+
287
+ ### getPortPosition(pNodeHash, pPortHash)
288
+
289
+ Get the absolute SVG coordinates of a port's center.
290
+
291
+ **Returns:** `{ x, y }`
292
+
293
+ ---
294
+
295
+ ## Connection Handle Methods
296
+
297
+ ### updateConnectionHandle(pConnectionHash, pHandleType, pX, pY)
298
+
299
+ Update a bezier control point on a connection.
300
+
301
+ ### addConnectionHandle(pConnectionHash, pX, pY)
302
+
303
+ Add a new control point to a connection.
304
+
305
+ ### removeConnectionHandle(pConnectionHash, pIndex)
306
+
307
+ Remove a control point from a connection.
308
+
309
+ ### updateTetherHandle(pPanelHash, pHandleType, pX, pY)
310
+
311
+ Update a bezier control point on a tether line.
312
+
313
+ ---
314
+
315
+ ## Internal Service Accessors
316
+
317
+ Developers access services and providers through underscore-prefixed properties on the flow view instance:
318
+
319
+ | Property | Service/Provider |
320
+ |----------|-----------------|
321
+ | `_DataManager` | Node and connection CRUD |
322
+ | `_RenderManager` | Rendering orchestration |
323
+ | `_SelectionManager` | Selection state |
324
+ | `_ViewportManager` | Pan, zoom, fullscreen |
325
+ | `_PanelManager` | Panel lifecycle |
326
+ | `_InteractionManager` | Event handling |
327
+ | `_LayoutService` | Grid snap, auto-layout |
328
+ | `_ConnectionRenderer` | Bezier/orthogonal drawing |
329
+ | `_NodeTypeProvider` | Node type registry |
330
+ | `_EventHandlerProvider` | Custom event hooks |
331
+ | `_LayoutProvider` | Layout persistence |
332
+ | `_ThemeProvider` | Theme system |
333
+ | `_CSSProvider` | CSS generation and injection |
334
+ | `_GeometryProvider` | Port positioning math |
335
+ | `_NoiseProvider` | Hand-drawn effects |
336
+ | `_SVGHelperProvider` | SVG DOM utilities |
337
+ | `_ConnectorShapesProvider` | Arrowhead marker definitions |
338
+ | `_IconProvider` | Icon templates |
339
+ | `_PanelChromeProvider` | Panel UI template |
340
+
341
+ ---
342
+
343
+ ## EventHandler Provider API
344
+
345
+ ### registerHandler(pEventName, pHandler, pHandlerHash)
346
+
347
+ Register a callback for a named event.
348
+
349
+ | Parameter | Type | Description |
350
+ |-----------|------|-------------|
351
+ | `pEventName` | string | Event name (see list below) |
352
+ | `pHandler` | function | Callback function |
353
+ | `pHandlerHash` | string | Optional unique identifier for removal |
354
+
355
+ **Returns:** Handler hash (string).
356
+
357
+ ### removeHandler(pEventName, pHandlerHash)
358
+
359
+ Remove a previously registered handler.
360
+
361
+ **Returns:** `boolean`
362
+
363
+ ### fireEvent(pEventName, pData)
364
+
365
+ Fire all handlers for a named event.
366
+
367
+ ### Supported Events
368
+
369
+ | Event | Payload | Fired When |
370
+ |-------|---------|------------|
371
+ | `onNodeSelected` | Node object | A node is selected |
372
+ | `onNodeAdded` | Node object | A node is created |
373
+ | `onNodeRemoved` | Node object | A node is deleted |
374
+ | `onNodeMoved` | Node object | A node's position changes |
375
+ | `onConnectionSelected` | Connection object | A connection is selected |
376
+ | `onConnectionCreated` | Connection object | A connection is created |
377
+ | `onConnectionRemoved` | Connection object | A connection is deleted |
378
+ | `onConnectionHandleMoved` | Connection object | A bezier handle is dragged |
379
+ | `onConnectionModeChanged` | Connection object | Line mode switches (bezier/orthogonal) |
380
+ | `onPanelOpened` | Panel data | A properties panel opens |
381
+ | `onPanelClosed` | Panel data | A properties panel closes |
382
+ | `onPanelMoved` | Panel data | A panel is dragged |
383
+ | `onTetherSelected` | Panel data | A tether line is selected |
384
+ | `onTetherHandleMoved` | Panel data | A tether handle is dragged |
385
+ | `onTetherModeChanged` | Panel data | Tether mode switches |
386
+ | `onLayoutSaved` | Layout data | A layout is saved |
387
+ | `onLayoutRestored` | Layout data | A layout is restored |
388
+ | `onLayoutDeleted` | Layout data | A layout is deleted |
389
+ | `onFlowChanged` | Flow data | Any structural change to the flow |
390
+ | `onThemeChanged` | Theme key | The active theme changes |
391
+
392
+ ---
393
+
394
+ ## NodeTypes Provider API
395
+
396
+ ### registerNodeType(pNodeTypeConfig)
397
+
398
+ Register a new node type.
399
+
400
+ | Parameter | Type | Description |
401
+ |-----------|------|-------------|
402
+ | `pNodeTypeConfig` | object | Node type configuration (see PictFlowCard docs) |
403
+
404
+ **Returns:** `boolean`
405
+
406
+ ### removeNodeType(pTypeHash)
407
+
408
+ Unregister a node type.
409
+
410
+ **Returns:** `boolean`
411
+
412
+ ### getNodeType(pTypeHash)
413
+
414
+ Retrieve a node type configuration by hash.
415
+
416
+ **Returns:** Node type config object, or the default type if not found.
417
+
418
+ ### getNodeTypes()
419
+
420
+ **Returns:** Map of all registered node types.
421
+
422
+ ### getNodeTypeList()
423
+
424
+ **Returns:** Array of registered type hashes.
425
+
426
+ ### getEnabledCards()
427
+
428
+ **Returns:** Array of card configurations where `Enabled` is `true`.
429
+
430
+ ### getCardsByCategory()
431
+
432
+ **Returns:** Object mapping category names to arrays of card configurations.
433
+
434
+ ---
435
+
436
+ ## Theme Provider API
437
+
438
+ ### registerTheme(pThemeKey, pThemeConfig)
439
+
440
+ Register a named theme.
441
+
442
+ | Parameter | Type | Description |
443
+ |-----------|------|-------------|
444
+ | `pThemeKey` | string | Unique theme identifier |
445
+ | `pThemeConfig` | object | Theme configuration (see below) |
446
+
447
+ **Theme config shape:**
448
+
449
+ ```javascript
450
+ {
451
+ Key: 'dark',
452
+ Label: 'Dark Mode',
453
+ CSSVariables:
454
+ {
455
+ '--pf-canvas-bg': '#1a1a2e',
456
+ '--pf-node-body-fill': '#16213e'
457
+ },
458
+ AdditionalCSS: '/* Extra rules */',
459
+ NodeBodyMode: 'rect',
460
+ NoiseConfig: { Enabled: true, Amount: 0.5 },
461
+ ConnectionConfig: { StrokeDashArray: '5,5' }
462
+ }
463
+ ```
464
+
465
+ ### setTheme(pThemeKey)
466
+
467
+ Activate a registered theme and re-render.
468
+
469
+ **Returns:** `boolean` — `true` if the theme was found and activated.
470
+
471
+ ### getActiveTheme()
472
+
473
+ **Returns:** Active theme configuration object.
474
+
475
+ ### getActiveThemeKey()
476
+
477
+ **Returns:** Active theme key string.
478
+
479
+ ### Built-in Themes
480
+
481
+ | Key | Label | Style |
482
+ |-----|-------|-------|
483
+ | `default` | Modern | Clean, professional |
484
+ | `sketch` | Sketch | Hand-drawn, informal |
485
+ | `blueprint` | Blueprint | Technical blueprint |
486
+ | `mono` | Monochrome | Black and white |
487
+ | `retro-80s` | Retro 80s | Neon retro |
488
+ | `retro-90s` | Retro 90s | Vaporwave |
489
+
490
+ ---
491
+
492
+ ## Layouts Provider API
493
+
494
+ ### saveLayout(pName)
495
+
496
+ Save the current spatial arrangement.
497
+
498
+ **Returns:** Layout data object.
499
+
500
+ ### restoreLayout(pLayoutHash)
501
+
502
+ Restore a previously saved layout.
503
+
504
+ **Returns:** `boolean`
505
+
506
+ ### deleteLayout(pLayoutHash)
507
+
508
+ Delete a saved layout.
509
+
510
+ **Returns:** `boolean`
511
+
512
+ ### loadPersistedLayouts()
513
+
514
+ Load layouts from the storage backend (localStorage by default).
515
+
516
+ ### getLayouts()
517
+
518
+ **Returns:** Array of saved layout objects.
519
+
520
+ ### Storage Hooks
521
+
522
+ Override these methods to use a custom storage backend:
523
+
524
+ | Method | Signature | Description |
525
+ |--------|-----------|-------------|
526
+ | `storageWrite` | `(pLayouts, fCallback)` | Persist layouts |
527
+ | `storageRead` | `(fCallback)` | Load layouts |
528
+ | `storageDelete` | `(fCallback)` | Clear all layouts |
@@ -0,0 +1,117 @@
1
+ # Layout Persistence
2
+
3
+ Pict-Section-Flow can save and restore spatial arrangements of nodes and panels independently of the flow data itself. This lets users maintain multiple views of the same flow graph.
4
+
5
+ ## How It Works
6
+
7
+ A **layout** captures the position, size, and viewport state of a flow diagram at a point in time. It does not store the flow's logical content (nodes, connections, data) — only where things are on screen.
8
+
9
+ Each saved layout contains:
10
+
11
+ | Property | Description |
12
+ |----------|-------------|
13
+ | `Hash` | Unique identifier for the layout |
14
+ | `Name` | Display name chosen by the user |
15
+ | `CreatedAt` | ISO 8601 timestamp |
16
+ | `NodePositions` | Map of node hash to `{ X, Y, Width, Height }` |
17
+ | `PanelPositions` | Map of node hash to `{ X, Y, Width, Height }` |
18
+ | `ViewState` | `{ PanX, PanY, Zoom }` |
19
+
20
+ ## Default Behavior: localStorage
21
+
22
+ Saved layouts persist to `localStorage` by default, keyed by the flow view identifier (e.g. `pict-flow-layouts-MyFlowDiagram`). Layouts survive page refreshes without any configuration.
23
+
24
+ ```javascript
25
+ // Save the current layout
26
+ flowView._LayoutProvider.saveLayout('My Layout');
27
+
28
+ // List all saved layouts
29
+ let tmpLayouts = flowView._LayoutProvider.getLayouts();
30
+
31
+ // Restore a layout
32
+ flowView._LayoutProvider.restoreLayout(tmpLayouts[0].Hash);
33
+
34
+ // Delete a layout
35
+ flowView._LayoutProvider.deleteLayout(tmpLayouts[0].Hash);
36
+ ```
37
+
38
+ ## Overriding Storage (e.g. REST API)
39
+
40
+ The `LayoutProvider` exposes three hookable storage methods that follow the `fCallback(pError, pResult)` convention. Replace them on the instance to use any backend:
41
+
42
+ ```javascript
43
+ // After your flow view is initialized:
44
+ let layoutProvider = flowView._LayoutProvider;
45
+
46
+ // Persist layouts to a server
47
+ layoutProvider.storageWrite = function(pLayouts, fCallback)
48
+ {
49
+ fetch('/api/my-flow/layouts',
50
+ {
51
+ method: 'PUT',
52
+ headers: { 'Content-Type': 'application/json' },
53
+ body: JSON.stringify(pLayouts)
54
+ })
55
+ .then(() => fCallback(null))
56
+ .catch((pError) => fCallback(pError));
57
+ };
58
+
59
+ // Load layouts from a server
60
+ layoutProvider.storageRead = function(fCallback)
61
+ {
62
+ fetch('/api/my-flow/layouts')
63
+ .then((pResponse) => pResponse.json())
64
+ .then((pLayouts) => fCallback(null, pLayouts))
65
+ .catch((pError) => fCallback(pError, []));
66
+ };
67
+
68
+ // Delete all layouts on the server
69
+ layoutProvider.storageDelete = function(fCallback)
70
+ {
71
+ fetch('/api/my-flow/layouts', { method: 'DELETE' })
72
+ .then(() => fCallback(null))
73
+ .catch((pError) => fCallback(pError));
74
+ };
75
+
76
+ // Load from the new backend now that hooks are set
77
+ layoutProvider.loadPersistedLayouts();
78
+ ```
79
+
80
+ ## Configuration Options
81
+
82
+ - **`StorageKey`** (string) — Override the localStorage key. Passed via options when instantiating the provider.
83
+ - **`StorageKey: false`** — Disable localStorage persistence entirely (useful when using only a remote backend).
84
+
85
+ ## Events
86
+
87
+ The layout system fires events you can hook into:
88
+
89
+ ```javascript
90
+ flowView._EventHandlerProvider.registerHandler('onLayoutSaved',
91
+ (pLayoutData) =>
92
+ {
93
+ console.log('Layout saved:', pLayoutData.Name);
94
+ });
95
+
96
+ flowView._EventHandlerProvider.registerHandler('onLayoutRestored',
97
+ (pLayoutData) =>
98
+ {
99
+ console.log('Layout restored:', pLayoutData.Name);
100
+ });
101
+
102
+ flowView._EventHandlerProvider.registerHandler('onLayoutDeleted',
103
+ (pLayoutData) =>
104
+ {
105
+ console.log('Layout deleted:', pLayoutData.Name);
106
+ });
107
+ ```
108
+
109
+ ## Restore Behavior
110
+
111
+ When a layout is restored, the provider:
112
+
113
+ 1. Positions each node whose hash appears in `NodePositions`
114
+ 2. Positions each panel whose node hash appears in `PanelPositions`
115
+ 3. Applies the saved `ViewState` (pan and zoom)
116
+ 4. Any nodes that exist in the flow but not in the layout remain in their current position
117
+ 5. Triggers a full re-render