pict-section-flow 0.0.2 → 0.0.3
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 +11 -0
- package/docs/README.md +51 -0
- package/example_applications/simple_cards/source/Pict-Application-FlowExample.js +105 -0
- package/example_applications/simple_cards/source/cards/FlowCard-Comment.js +36 -0
- package/example_applications/simple_cards/source/cards/FlowCard-DataPreview.js +42 -0
- package/example_applications/simple_cards/source/cards/FlowCard-Each.js +1 -1
- package/example_applications/simple_cards/source/cards/FlowCard-FileRead.js +1 -1
- package/example_applications/simple_cards/source/cards/FlowCard-FileWrite.js +1 -1
- package/example_applications/simple_cards/source/cards/FlowCard-GetValue.js +1 -1
- package/example_applications/simple_cards/source/cards/FlowCard-IfThenElse.js +1 -1
- package/example_applications/simple_cards/source/cards/FlowCard-LogValues.js +1 -1
- package/example_applications/simple_cards/source/cards/FlowCard-SetValue.js +1 -1
- package/example_applications/simple_cards/source/cards/FlowCard-Sparkline.js +98 -0
- package/example_applications/simple_cards/source/cards/FlowCard-StatusMonitor.js +44 -0
- package/example_applications/simple_cards/source/cards/FlowCard-Switch.js +1 -1
- package/example_applications/simple_cards/source/views/PictView-FlowExample-MainWorkspace.js +9 -1
- package/package.json +2 -2
- package/source/Pict-Section-Flow.js +8 -1
- package/source/PictFlowCard.js +49 -1
- package/source/providers/PictProvider-Flow-CSS.js +1440 -0
- package/source/providers/PictProvider-Flow-ConnectorShapes.js +413 -0
- package/source/providers/PictProvider-Flow-Geometry.js +43 -0
- package/source/providers/PictProvider-Flow-Icons.js +335 -0
- package/source/providers/PictProvider-Flow-Layouts.js +214 -2
- package/source/providers/PictProvider-Flow-NodeTypes.js +30 -7
- package/source/providers/PictProvider-Flow-Noise.js +241 -0
- package/source/providers/PictProvider-Flow-PanelChrome.js +19 -0
- package/source/providers/PictProvider-Flow-Theme.js +755 -0
- package/source/services/PictService-Flow-ConnectionRenderer.js +95 -32
- package/source/services/PictService-Flow-PanelManager.js +188 -0
- package/source/services/PictService-Flow-SelectionManager.js +109 -0
- package/source/services/PictService-Flow-Tether.js +52 -25
- package/source/services/PictService-Flow-ViewportManager.js +176 -0
- package/source/views/PictView-Flow-FloatingToolbar.js +352 -0
- package/source/views/PictView-Flow-Node.js +654 -169
- package/source/views/PictView-Flow-PropertiesPanel.js +176 -1
- package/source/views/PictView-Flow-Toolbar.js +846 -379
- package/source/views/PictView-Flow.js +279 -671
|
@@ -5,6 +5,9 @@ const libPictServiceFlowConnectionRenderer = require('../services/PictService-Fl
|
|
|
5
5
|
const libPictServiceFlowTether = require('../services/PictService-Flow-Tether.js');
|
|
6
6
|
const libPictServiceFlowLayout = require('../services/PictService-Flow-Layout.js');
|
|
7
7
|
const libPictServiceFlowPathGenerator = require('../services/PictService-Flow-PathGenerator.js');
|
|
8
|
+
const libPictServiceFlowViewportManager = require('../services/PictService-Flow-ViewportManager.js');
|
|
9
|
+
const libPictServiceFlowSelectionManager = require('../services/PictService-Flow-SelectionManager.js');
|
|
10
|
+
const libPictServiceFlowPanelManager = require('../services/PictService-Flow-PanelManager.js');
|
|
8
11
|
|
|
9
12
|
const libPictProviderFlowNodeTypes = require('../providers/PictProvider-Flow-NodeTypes.js');
|
|
10
13
|
const libPictProviderFlowEventHandler = require('../providers/PictProvider-Flow-EventHandler.js');
|
|
@@ -12,9 +15,15 @@ const libPictProviderFlowLayouts = require('../providers/PictProvider-Flow-Layou
|
|
|
12
15
|
const libPictProviderFlowSVGHelpers = require('../providers/PictProvider-Flow-SVGHelpers.js');
|
|
13
16
|
const libPictProviderFlowGeometry = require('../providers/PictProvider-Flow-Geometry.js');
|
|
14
17
|
const libPictProviderFlowPanelChrome = require('../providers/PictProvider-Flow-PanelChrome.js');
|
|
18
|
+
const libPictProviderFlowCSS = require('../providers/PictProvider-Flow-CSS.js');
|
|
19
|
+
const libPictProviderFlowIcons = require('../providers/PictProvider-Flow-Icons.js');
|
|
20
|
+
const libPictProviderFlowConnectorShapes = require('../providers/PictProvider-Flow-ConnectorShapes.js');
|
|
21
|
+
const libPictProviderFlowTheme = require('../providers/PictProvider-Flow-Theme.js');
|
|
22
|
+
const libPictProviderFlowNoise = require('../providers/PictProvider-Flow-Noise.js');
|
|
15
23
|
|
|
16
24
|
const libPictViewFlowNode = require('./PictView-Flow-Node.js');
|
|
17
25
|
const libPictViewFlowToolbar = require('./PictView-Flow-Toolbar.js');
|
|
26
|
+
const libPictViewFlowFloatingToolbar = require('./PictView-Flow-FloatingToolbar.js');
|
|
18
27
|
const libPictViewFlowPropertiesPanel = require('./PictView-Flow-PropertiesPanel.js');
|
|
19
28
|
|
|
20
29
|
const libPictFlowCardPropertiesPanel = require('../PictFlowCardPropertiesPanel.js');
|
|
@@ -52,398 +61,25 @@ const _DefaultConfiguration =
|
|
|
52
61
|
DefaultNodeWidth: 180,
|
|
53
62
|
DefaultNodeHeight: 80,
|
|
54
63
|
|
|
55
|
-
CSS:
|
|
56
|
-
.pict-flow-container {
|
|
57
|
-
position: relative;
|
|
58
|
-
width: 100%;
|
|
59
|
-
height: 100%;
|
|
60
|
-
min-height: 400px;
|
|
61
|
-
overflow: hidden;
|
|
62
|
-
background-color: #fafafa;
|
|
63
|
-
border: 1px solid #e0e0e0;
|
|
64
|
-
border-radius: 4px;
|
|
65
|
-
display: flex;
|
|
66
|
-
flex-direction: column;
|
|
67
|
-
}
|
|
68
|
-
.pict-flow-svg-container {
|
|
69
|
-
flex: 1;
|
|
70
|
-
min-height: 0;
|
|
71
|
-
position: relative;
|
|
72
|
-
}
|
|
73
|
-
.pict-flow-svg {
|
|
74
|
-
width: 100%;
|
|
75
|
-
height: 100%;
|
|
76
|
-
cursor: grab;
|
|
77
|
-
user-select: none;
|
|
78
|
-
-webkit-user-select: none;
|
|
79
|
-
}
|
|
80
|
-
.pict-flow-svg.panning {
|
|
81
|
-
cursor: grabbing;
|
|
82
|
-
}
|
|
83
|
-
.pict-flow-svg.connecting {
|
|
84
|
-
cursor: crosshair;
|
|
85
|
-
}
|
|
86
|
-
.pict-flow-grid-pattern line {
|
|
87
|
-
stroke: #e8e8e8;
|
|
88
|
-
stroke-width: 0.5;
|
|
89
|
-
}
|
|
90
|
-
.pict-flow-node {
|
|
91
|
-
cursor: pointer;
|
|
92
|
-
}
|
|
93
|
-
.pict-flow-node:hover .pict-flow-node-body {
|
|
94
|
-
filter: brightness(0.97);
|
|
95
|
-
}
|
|
96
|
-
.pict-flow-node.selected .pict-flow-node-body {
|
|
97
|
-
stroke: #3498db;
|
|
98
|
-
stroke-width: 2.5;
|
|
99
|
-
}
|
|
100
|
-
.pict-flow-node.dragging {
|
|
101
|
-
opacity: 0.85;
|
|
102
|
-
cursor: grabbing;
|
|
103
|
-
}
|
|
104
|
-
.pict-flow-node-body {
|
|
105
|
-
fill: #ffffff;
|
|
106
|
-
stroke: #bdc3c7;
|
|
107
|
-
stroke-width: 1.5;
|
|
108
|
-
rx: 6;
|
|
109
|
-
ry: 6;
|
|
110
|
-
transition: filter 0.15s;
|
|
111
|
-
}
|
|
112
|
-
.pict-flow-node-title-bar {
|
|
113
|
-
fill: #2c3e50;
|
|
114
|
-
rx: 6;
|
|
115
|
-
ry: 6;
|
|
116
|
-
}
|
|
117
|
-
.pict-flow-node-title-bar-bottom {
|
|
118
|
-
fill: #2c3e50;
|
|
119
|
-
}
|
|
120
|
-
.pict-flow-node-title {
|
|
121
|
-
fill: #ffffff;
|
|
122
|
-
font-size: 12px;
|
|
123
|
-
font-weight: 700;
|
|
124
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
125
|
-
pointer-events: none;
|
|
126
|
-
}
|
|
127
|
-
.pict-flow-node-type-label {
|
|
128
|
-
fill: #95a5a6;
|
|
129
|
-
font-size: 10px;
|
|
130
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
131
|
-
pointer-events: none;
|
|
132
|
-
}
|
|
133
|
-
.pict-flow-port {
|
|
134
|
-
cursor: crosshair;
|
|
135
|
-
transition: r 0.15s;
|
|
136
|
-
}
|
|
137
|
-
.pict-flow-port.input {
|
|
138
|
-
fill: #3498db;
|
|
139
|
-
stroke: #2980b9;
|
|
140
|
-
stroke-width: 1.5;
|
|
141
|
-
}
|
|
142
|
-
.pict-flow-port.output {
|
|
143
|
-
fill: #2ecc71;
|
|
144
|
-
stroke: #27ae60;
|
|
145
|
-
stroke-width: 1.5;
|
|
146
|
-
}
|
|
147
|
-
.pict-flow-port:hover {
|
|
148
|
-
r: 7;
|
|
149
|
-
}
|
|
150
|
-
.pict-flow-port-label {
|
|
151
|
-
fill: #7f8c8d;
|
|
152
|
-
font-size: 9px;
|
|
153
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
154
|
-
pointer-events: none;
|
|
155
|
-
}
|
|
156
|
-
.pict-flow-connection {
|
|
157
|
-
fill: none;
|
|
158
|
-
stroke: #95a5a6;
|
|
159
|
-
stroke-width: 2;
|
|
160
|
-
cursor: pointer;
|
|
161
|
-
transition: stroke 0.15s;
|
|
162
|
-
}
|
|
163
|
-
.pict-flow-connection:hover {
|
|
164
|
-
stroke: #7f8c8d;
|
|
165
|
-
stroke-width: 3;
|
|
166
|
-
}
|
|
167
|
-
.pict-flow-connection.selected {
|
|
168
|
-
stroke: #3498db;
|
|
169
|
-
stroke-width: 3;
|
|
170
|
-
}
|
|
171
|
-
.pict-flow-connection-hitarea {
|
|
172
|
-
fill: none;
|
|
173
|
-
stroke: transparent;
|
|
174
|
-
stroke-width: 12;
|
|
175
|
-
cursor: pointer;
|
|
176
|
-
}
|
|
177
|
-
.pict-flow-drag-connection {
|
|
178
|
-
fill: none;
|
|
179
|
-
stroke: #3498db;
|
|
180
|
-
stroke-width: 2;
|
|
181
|
-
stroke-dasharray: 6 3;
|
|
182
|
-
pointer-events: none;
|
|
183
|
-
}
|
|
184
|
-
.pict-flow-node-decision .pict-flow-node-body {
|
|
185
|
-
fill: #fff9e6;
|
|
186
|
-
stroke: #f39c12;
|
|
187
|
-
}
|
|
188
|
-
.pict-flow-node-start .pict-flow-node-body {
|
|
189
|
-
fill: #eafaf1;
|
|
190
|
-
stroke: #27ae60;
|
|
191
|
-
rx: 25;
|
|
192
|
-
ry: 25;
|
|
193
|
-
}
|
|
194
|
-
.pict-flow-node-end .pict-flow-node-body {
|
|
195
|
-
fill: #fdedec;
|
|
196
|
-
stroke: #e74c3c;
|
|
197
|
-
rx: 25;
|
|
198
|
-
ry: 25;
|
|
199
|
-
}
|
|
200
|
-
.pict-flow-connection-handle {
|
|
201
|
-
fill: #ffffff;
|
|
202
|
-
stroke: #3498db;
|
|
203
|
-
stroke-width: 2;
|
|
204
|
-
cursor: grab;
|
|
205
|
-
transition: r 0.15s;
|
|
206
|
-
filter: drop-shadow(0 1px 2px rgba(0,0,0,0.2));
|
|
207
|
-
}
|
|
208
|
-
.pict-flow-connection-handle:hover {
|
|
209
|
-
r: 8;
|
|
210
|
-
stroke-width: 2.5;
|
|
211
|
-
}
|
|
212
|
-
.pict-flow-connection-handle-midpoint {
|
|
213
|
-
fill: #ffffff;
|
|
214
|
-
stroke: #e67e22;
|
|
215
|
-
stroke-width: 2;
|
|
216
|
-
cursor: grab;
|
|
217
|
-
transition: r 0.15s;
|
|
218
|
-
filter: drop-shadow(0 1px 2px rgba(0,0,0,0.2));
|
|
219
|
-
}
|
|
220
|
-
.pict-flow-connection-handle-midpoint:hover {
|
|
221
|
-
r: 8;
|
|
222
|
-
stroke-width: 2.5;
|
|
223
|
-
}
|
|
224
|
-
.pict-flow-tether-line {
|
|
225
|
-
fill: none;
|
|
226
|
-
stroke: #95a5a6;
|
|
227
|
-
stroke-width: 1.5;
|
|
228
|
-
stroke-dasharray: 6 4;
|
|
229
|
-
pointer-events: visibleStroke;
|
|
230
|
-
cursor: pointer;
|
|
231
|
-
}
|
|
232
|
-
.pict-flow-tether-line.selected {
|
|
233
|
-
stroke: #3498db;
|
|
234
|
-
stroke-width: 2;
|
|
235
|
-
}
|
|
236
|
-
.pict-flow-tether-hitarea {
|
|
237
|
-
fill: none;
|
|
238
|
-
stroke: transparent;
|
|
239
|
-
stroke-width: 10;
|
|
240
|
-
cursor: pointer;
|
|
241
|
-
}
|
|
242
|
-
.pict-flow-tether-handle {
|
|
243
|
-
fill: #ffffff;
|
|
244
|
-
stroke: #3498db;
|
|
245
|
-
stroke-width: 2;
|
|
246
|
-
cursor: grab;
|
|
247
|
-
transition: r 0.15s;
|
|
248
|
-
filter: drop-shadow(0 1px 2px rgba(0,0,0,0.2));
|
|
249
|
-
}
|
|
250
|
-
.pict-flow-tether-handle:hover {
|
|
251
|
-
r: 8;
|
|
252
|
-
stroke-width: 2.5;
|
|
253
|
-
}
|
|
254
|
-
.pict-flow-tether-handle-midpoint {
|
|
255
|
-
fill: #ffffff;
|
|
256
|
-
stroke: #e67e22;
|
|
257
|
-
stroke-width: 2;
|
|
258
|
-
cursor: grab;
|
|
259
|
-
transition: r 0.15s;
|
|
260
|
-
filter: drop-shadow(0 1px 2px rgba(0,0,0,0.2));
|
|
261
|
-
}
|
|
262
|
-
.pict-flow-tether-handle-midpoint:hover {
|
|
263
|
-
r: 8;
|
|
264
|
-
stroke-width: 2.5;
|
|
265
|
-
}
|
|
266
|
-
.pict-flow-node-panel-indicator {
|
|
267
|
-
fill: #3498db;
|
|
268
|
-
stroke: #2980b9;
|
|
269
|
-
stroke-width: 1;
|
|
270
|
-
cursor: pointer;
|
|
271
|
-
}
|
|
272
|
-
.pict-flow-node-panel-indicator:hover {
|
|
273
|
-
fill: #2980b9;
|
|
274
|
-
}
|
|
275
|
-
.pict-flow-panel-foreign-object {
|
|
276
|
-
overflow: visible;
|
|
277
|
-
}
|
|
278
|
-
.pict-flow-panel {
|
|
279
|
-
background: #ffffff;
|
|
280
|
-
border: 1px solid #bdc3c7;
|
|
281
|
-
border-radius: 6px;
|
|
282
|
-
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
|
|
283
|
-
display: flex;
|
|
284
|
-
flex-direction: column;
|
|
285
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
286
|
-
font-size: 13px;
|
|
287
|
-
overflow: hidden;
|
|
288
|
-
width: 100%;
|
|
289
|
-
height: 100%;
|
|
290
|
-
box-sizing: border-box;
|
|
291
|
-
}
|
|
292
|
-
.pict-flow-panel-titlebar {
|
|
293
|
-
display: flex;
|
|
294
|
-
align-items: center;
|
|
295
|
-
justify-content: space-between;
|
|
296
|
-
padding: 6px 10px;
|
|
297
|
-
background: #ecf0f1;
|
|
298
|
-
border-bottom: 1px solid #d5dbdb;
|
|
299
|
-
cursor: grab;
|
|
300
|
-
user-select: none;
|
|
301
|
-
-webkit-user-select: none;
|
|
302
|
-
flex-shrink: 0;
|
|
303
|
-
}
|
|
304
|
-
.pict-flow-panel-titlebar.dragging {
|
|
305
|
-
cursor: grabbing;
|
|
306
|
-
}
|
|
307
|
-
.pict-flow-panel-title-text {
|
|
308
|
-
font-weight: 600;
|
|
309
|
-
font-size: 12px;
|
|
310
|
-
color: #2c3e50;
|
|
311
|
-
white-space: nowrap;
|
|
312
|
-
overflow: hidden;
|
|
313
|
-
text-overflow: ellipsis;
|
|
314
|
-
}
|
|
315
|
-
.pict-flow-panel-close-btn {
|
|
316
|
-
cursor: pointer;
|
|
317
|
-
color: #95a5a6;
|
|
318
|
-
font-size: 14px;
|
|
319
|
-
line-height: 1;
|
|
320
|
-
padding: 2px 4px;
|
|
321
|
-
border: none;
|
|
322
|
-
background: none;
|
|
323
|
-
}
|
|
324
|
-
.pict-flow-panel-close-btn:hover {
|
|
325
|
-
color: #e74c3c;
|
|
326
|
-
}
|
|
327
|
-
.pict-flow-panel-body {
|
|
328
|
-
flex: 1;
|
|
329
|
-
overflow: auto;
|
|
330
|
-
padding: 8px;
|
|
331
|
-
}
|
|
332
|
-
.pict-flow-fullscreen {
|
|
333
|
-
position: fixed;
|
|
334
|
-
top: 0;
|
|
335
|
-
left: 0;
|
|
336
|
-
width: 100vw;
|
|
337
|
-
height: 100vh;
|
|
338
|
-
z-index: 9999;
|
|
339
|
-
border-radius: 0;
|
|
340
|
-
border: none;
|
|
341
|
-
min-height: 100vh;
|
|
342
|
-
}
|
|
343
|
-
.pict-flow-fullscreen .pict-flow-svg {
|
|
344
|
-
min-height: calc(100vh - 50px);
|
|
345
|
-
}
|
|
346
|
-
.pict-flow-info-panel {
|
|
347
|
-
padding: 4px;
|
|
348
|
-
font-size: 12px;
|
|
349
|
-
line-height: 1.5;
|
|
350
|
-
color: #2c3e50;
|
|
351
|
-
}
|
|
352
|
-
.pict-flow-info-panel-header {
|
|
353
|
-
font-size: 14px;
|
|
354
|
-
font-weight: 600;
|
|
355
|
-
margin-bottom: 4px;
|
|
356
|
-
}
|
|
357
|
-
.pict-flow-info-panel-header.with-icon {
|
|
358
|
-
font-size: 16px;
|
|
359
|
-
}
|
|
360
|
-
.pict-flow-info-panel-description {
|
|
361
|
-
font-size: 11px;
|
|
362
|
-
color: #7f8c8d;
|
|
363
|
-
margin-bottom: 8px;
|
|
364
|
-
}
|
|
365
|
-
.pict-flow-info-panel-badges {
|
|
366
|
-
margin-bottom: 8px;
|
|
367
|
-
}
|
|
368
|
-
.pict-flow-info-panel-badge {
|
|
369
|
-
display: inline-block;
|
|
370
|
-
padding: 1px 6px;
|
|
371
|
-
border-radius: 3px;
|
|
372
|
-
font-size: 10px;
|
|
373
|
-
margin-right: 4px;
|
|
374
|
-
}
|
|
375
|
-
.pict-flow-info-panel-badge.category {
|
|
376
|
-
background: #ecf0f1;
|
|
377
|
-
color: #7f8c8d;
|
|
378
|
-
}
|
|
379
|
-
.pict-flow-info-panel-badge.code {
|
|
380
|
-
background: #eaf2f8;
|
|
381
|
-
color: #2980b9;
|
|
382
|
-
font-family: monospace;
|
|
383
|
-
}
|
|
384
|
-
.pict-flow-info-panel-section {
|
|
385
|
-
margin-bottom: 6px;
|
|
386
|
-
}
|
|
387
|
-
.pict-flow-info-panel-section-title {
|
|
388
|
-
font-size: 10px;
|
|
389
|
-
font-weight: 700;
|
|
390
|
-
text-transform: uppercase;
|
|
391
|
-
letter-spacing: 0.5px;
|
|
392
|
-
color: #95a5a6;
|
|
393
|
-
margin-bottom: 2px;
|
|
394
|
-
}
|
|
395
|
-
.pict-flow-info-panel-port {
|
|
396
|
-
padding: 2px 6px;
|
|
397
|
-
background: #f8f9fa;
|
|
398
|
-
margin-bottom: 2px;
|
|
399
|
-
font-size: 11px;
|
|
400
|
-
}
|
|
401
|
-
.pict-flow-info-panel-port.input {
|
|
402
|
-
border-left: 3px solid #3498db;
|
|
403
|
-
}
|
|
404
|
-
.pict-flow-info-panel-port.output {
|
|
405
|
-
border-left: 3px solid #2ecc71;
|
|
406
|
-
}
|
|
407
|
-
.pict-flow-info-panel-port-constraint {
|
|
408
|
-
color: #95a5a6;
|
|
409
|
-
font-size: 10px;
|
|
410
|
-
}
|
|
411
|
-
`,
|
|
64
|
+
CSS: false,
|
|
412
65
|
|
|
413
66
|
Templates:
|
|
414
67
|
[
|
|
415
68
|
{
|
|
416
69
|
Hash: 'Flow-PanelChrome-Template',
|
|
417
|
-
Template: /*html*/`<div class="pict-flow-panel" xmlns="http://www.w3.org/1999/xhtml"><div class="pict-flow-panel-titlebar" data-element-type="panel-titlebar" data-panel-hash="{~D:Record.Hash~}"><span class="pict-flow-panel-title-text">{~D:Record.Title~}</span><span class="pict-flow-panel-close-btn" data-element-type="panel-close" data-panel-hash="{~D:Record.Hash~}"
|
|
70
|
+
Template: /*html*/`<div class="pict-flow-panel" xmlns="http://www.w3.org/1999/xhtml"><div class="pict-flow-panel-titlebar" data-element-type="panel-titlebar" data-panel-hash="{~D:Record.Hash~}"><span class="pict-flow-panel-title-text">{~D:Record.Title~}</span><span class="pict-flow-panel-close-btn" data-element-type="panel-close" data-panel-hash="{~D:Record.Hash~}"><span class="pict-flow-panel-close-icon"></span></span></div><div class="pict-flow-panel-body" data-panel-hash="{~D:Record.Hash~}"></div><div class="pict-flow-panel-node-props" data-panel-hash="{~D:Record.Hash~}"><div class="pict-flow-panel-node-props-header" data-element-type="node-props-toggle" data-panel-hash="{~D:Record.Hash~}"><span class="pict-flow-panel-node-props-chevron">▶</span><span class="pict-flow-panel-node-props-title">Node Properties</span></div><div class="pict-flow-panel-node-props-body" style="display:none;"></div></div></div>`
|
|
418
71
|
},
|
|
419
72
|
{
|
|
420
73
|
Hash: 'Flow-Container-Template',
|
|
421
74
|
Template: /*html*/`
|
|
422
75
|
<div class="pict-flow-container" id="Flow-Wrapper-{~D:Record.ViewIdentifier~}">
|
|
423
76
|
<div id="Flow-Toolbar-{~D:Record.ViewIdentifier~}"></div>
|
|
77
|
+
<div id="Flow-FloatingToolbar-Container-{~D:Record.ViewIdentifier~}" style="display:none;position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:100;"></div>
|
|
424
78
|
<div class="pict-flow-svg-container" id="Flow-SVG-Container-{~D:Record.ViewIdentifier~}">
|
|
425
79
|
<svg class="pict-flow-svg"
|
|
426
80
|
id="Flow-SVG-{~D:Record.ViewIdentifier~}"
|
|
427
81
|
xmlns="http://www.w3.org/2000/svg">
|
|
428
82
|
<defs>
|
|
429
|
-
<marker id="flow-arrowhead-{~D:Record.ViewIdentifier~}"
|
|
430
|
-
markerWidth="5" markerHeight="7"
|
|
431
|
-
refX="7.5" refY="3.5"
|
|
432
|
-
orient="auto" markerUnits="strokeWidth">
|
|
433
|
-
<polygon points="0 0, 5 3.5, 0 7" fill="#95a5a6" />
|
|
434
|
-
</marker>
|
|
435
|
-
<marker id="flow-arrowhead-selected-{~D:Record.ViewIdentifier~}"
|
|
436
|
-
markerWidth="5" markerHeight="7"
|
|
437
|
-
refX="7.5" refY="3.5"
|
|
438
|
-
orient="auto" markerUnits="strokeWidth">
|
|
439
|
-
<polygon points="0 0, 5 3.5, 0 7" fill="#3498db" />
|
|
440
|
-
</marker>
|
|
441
|
-
<marker id="flow-tether-arrowhead-{~D:Record.ViewIdentifier~}"
|
|
442
|
-
markerWidth="4" markerHeight="6"
|
|
443
|
-
refX="6" refY="3"
|
|
444
|
-
orient="auto" markerUnits="strokeWidth">
|
|
445
|
-
<polygon points="0 0, 4 3, 0 6" fill="#95a5a6" />
|
|
446
|
-
</marker>
|
|
447
83
|
<pattern id="flow-grid-{~D:Record.ViewIdentifier~}"
|
|
448
84
|
width="20" height="20" patternUnits="userSpaceOnUse">
|
|
449
85
|
<line x1="20" y1="0" x2="20" y2="20" class="pict-flow-grid-pattern" />
|
|
@@ -507,6 +143,18 @@ class PictViewFlow extends libPictView
|
|
|
507
143
|
{
|
|
508
144
|
this.fable.addServiceType('PictServiceFlowPathGenerator', libPictServiceFlowPathGenerator);
|
|
509
145
|
}
|
|
146
|
+
if (!this.fable.servicesMap.hasOwnProperty('PictServiceFlowViewportManager'))
|
|
147
|
+
{
|
|
148
|
+
this.fable.addServiceType('PictServiceFlowViewportManager', libPictServiceFlowViewportManager);
|
|
149
|
+
}
|
|
150
|
+
if (!this.fable.servicesMap.hasOwnProperty('PictServiceFlowSelectionManager'))
|
|
151
|
+
{
|
|
152
|
+
this.fable.addServiceType('PictServiceFlowSelectionManager', libPictServiceFlowSelectionManager);
|
|
153
|
+
}
|
|
154
|
+
if (!this.fable.servicesMap.hasOwnProperty('PictServiceFlowPanelManager'))
|
|
155
|
+
{
|
|
156
|
+
this.fable.addServiceType('PictServiceFlowPanelManager', libPictServiceFlowPanelManager);
|
|
157
|
+
}
|
|
510
158
|
if (!this.fable.servicesMap.hasOwnProperty('PictProviderFlowSVGHelpers'))
|
|
511
159
|
{
|
|
512
160
|
this.fable.addServiceType('PictProviderFlowSVGHelpers', libPictProviderFlowSVGHelpers);
|
|
@@ -519,6 +167,26 @@ class PictViewFlow extends libPictView
|
|
|
519
167
|
{
|
|
520
168
|
this.fable.addServiceType('PictProviderFlowPanelChrome', libPictProviderFlowPanelChrome);
|
|
521
169
|
}
|
|
170
|
+
if (!this.fable.servicesMap.hasOwnProperty('PictProviderFlowCSS'))
|
|
171
|
+
{
|
|
172
|
+
this.fable.addServiceType('PictProviderFlowCSS', libPictProviderFlowCSS);
|
|
173
|
+
}
|
|
174
|
+
if (!this.fable.servicesMap.hasOwnProperty('PictProviderFlowIcons'))
|
|
175
|
+
{
|
|
176
|
+
this.fable.addServiceType('PictProviderFlowIcons', libPictProviderFlowIcons);
|
|
177
|
+
}
|
|
178
|
+
if (!this.fable.servicesMap.hasOwnProperty('PictProviderFlowConnectorShapes'))
|
|
179
|
+
{
|
|
180
|
+
this.fable.addServiceType('PictProviderFlowConnectorShapes', libPictProviderFlowConnectorShapes);
|
|
181
|
+
}
|
|
182
|
+
if (!this.fable.servicesMap.hasOwnProperty('PictProviderFlowTheme'))
|
|
183
|
+
{
|
|
184
|
+
this.fable.addServiceType('PictProviderFlowTheme', libPictProviderFlowTheme);
|
|
185
|
+
}
|
|
186
|
+
if (!this.fable.servicesMap.hasOwnProperty('PictProviderFlowNoise'))
|
|
187
|
+
{
|
|
188
|
+
this.fable.addServiceType('PictProviderFlowNoise', libPictProviderFlowNoise);
|
|
189
|
+
}
|
|
522
190
|
if (!this.fable.servicesMap.hasOwnProperty('PictProviderFlowNodeTypes'))
|
|
523
191
|
{
|
|
524
192
|
this.fable.addServiceType('PictProviderFlowNodeTypes', libPictProviderFlowNodeTypes);
|
|
@@ -539,6 +207,10 @@ class PictViewFlow extends libPictView
|
|
|
539
207
|
{
|
|
540
208
|
this.fable.addServiceType('PictViewFlowToolbar', libPictViewFlowToolbar);
|
|
541
209
|
}
|
|
210
|
+
if (!this.fable.servicesMap.hasOwnProperty('PictViewFlowFloatingToolbar'))
|
|
211
|
+
{
|
|
212
|
+
this.fable.addServiceType('PictViewFlowFloatingToolbar', libPictViewFlowFloatingToolbar);
|
|
213
|
+
}
|
|
542
214
|
if (!this.fable.servicesMap.hasOwnProperty('PictViewFlowPropertiesPanel'))
|
|
543
215
|
{
|
|
544
216
|
this.fable.addServiceType('PictViewFlowPropertiesPanel', libPictViewFlowPropertiesPanel);
|
|
@@ -592,6 +264,14 @@ class PictViewFlow extends libPictView
|
|
|
592
264
|
this._TetherService = null;
|
|
593
265
|
this._LayoutService = null;
|
|
594
266
|
this._PathGenerator = null;
|
|
267
|
+
this._ViewportManager = null;
|
|
268
|
+
this._SelectionManager = null;
|
|
269
|
+
this._PanelManager = null;
|
|
270
|
+
this._CSSProvider = null;
|
|
271
|
+
this._IconProvider = null;
|
|
272
|
+
this._ConnectorShapesProvider = null;
|
|
273
|
+
this._ThemeProvider = null;
|
|
274
|
+
this._NoiseProvider = null;
|
|
595
275
|
this._SVGHelperProvider = null;
|
|
596
276
|
this._GeometryProvider = null;
|
|
597
277
|
this._PanelChromeProvider = null;
|
|
@@ -602,8 +282,6 @@ class PictViewFlow extends libPictView
|
|
|
602
282
|
this._ToolbarView = null;
|
|
603
283
|
this._PropertiesPanelView = null;
|
|
604
284
|
|
|
605
|
-
this._IsFullscreen = false;
|
|
606
|
-
|
|
607
285
|
this.initialRenderComplete = false;
|
|
608
286
|
}
|
|
609
287
|
|
|
@@ -617,6 +295,12 @@ class PictViewFlow extends libPictView
|
|
|
617
295
|
return this._FlowData.ViewState;
|
|
618
296
|
}
|
|
619
297
|
|
|
298
|
+
// Backward-compatible getter for InteractionManager direct access
|
|
299
|
+
get _IsFullscreen()
|
|
300
|
+
{
|
|
301
|
+
return this._ViewportManager ? this._ViewportManager._IsFullscreen : false;
|
|
302
|
+
}
|
|
303
|
+
|
|
620
304
|
/**
|
|
621
305
|
* Override render to pass view options as the template record,
|
|
622
306
|
* so template expressions like {~D:Record.ViewIdentifier~} resolve correctly.
|
|
@@ -640,6 +324,31 @@ class PictViewFlow extends libPictView
|
|
|
640
324
|
{
|
|
641
325
|
super.onBeforeInitialize();
|
|
642
326
|
|
|
327
|
+
// Instantiate theme and noise providers (before CSS so theme state is available)
|
|
328
|
+
this._ThemeProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowTheme', { FlowView: this });
|
|
329
|
+
this._NoiseProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowNoise');
|
|
330
|
+
|
|
331
|
+
// Apply initial theme from options
|
|
332
|
+
if (this.options.Theme)
|
|
333
|
+
{
|
|
334
|
+
this._ThemeProvider.setTheme(this.options.Theme);
|
|
335
|
+
}
|
|
336
|
+
if (typeof this.options.NoiseLevel === 'number')
|
|
337
|
+
{
|
|
338
|
+
this._ThemeProvider.setNoiseLevel(this.options.NoiseLevel);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Instantiate and register the centralized CSS provider
|
|
342
|
+
this._CSSProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowCSS', { FlowView: this });
|
|
343
|
+
this._CSSProvider.registerCSS();
|
|
344
|
+
|
|
345
|
+
// Instantiate the SVG icon provider
|
|
346
|
+
this._IconProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowIcons', { FlowView: this });
|
|
347
|
+
this._IconProvider.registerIconTemplates();
|
|
348
|
+
|
|
349
|
+
// Instantiate the connector shapes provider
|
|
350
|
+
this._ConnectorShapesProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowConnectorShapes', { FlowView: this });
|
|
351
|
+
|
|
643
352
|
// Instantiate shared utility providers first (used by services below)
|
|
644
353
|
this._SVGHelperProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowSVGHelpers');
|
|
645
354
|
this._GeometryProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowGeometry');
|
|
@@ -651,11 +360,15 @@ class PictViewFlow extends libPictView
|
|
|
651
360
|
this._ConnectionRenderer = this.fable.instantiateServiceProviderWithoutRegistration('PictServiceFlowConnectionRenderer', { FlowView: this });
|
|
652
361
|
this._TetherService = this.fable.instantiateServiceProviderWithoutRegistration('PictServiceFlowTether', { FlowView: this });
|
|
653
362
|
this._LayoutService = this.fable.instantiateServiceProviderWithoutRegistration('PictServiceFlowLayout', { FlowView: this });
|
|
363
|
+
this._ViewportManager = this.fable.instantiateServiceProviderWithoutRegistration('PictServiceFlowViewportManager', { FlowView: this });
|
|
364
|
+
this._SelectionManager = this.fable.instantiateServiceProviderWithoutRegistration('PictServiceFlowSelectionManager', { FlowView: this });
|
|
365
|
+
this._PanelManager = this.fable.instantiateServiceProviderWithoutRegistration('PictServiceFlowPanelManager', { FlowView: this });
|
|
654
366
|
|
|
655
367
|
// Instantiate providers, passing any additional node types from view options
|
|
656
368
|
this._NodeTypeProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowNodeTypes', { FlowView: this, AdditionalNodeTypes: this.options.NodeTypes });
|
|
657
369
|
this._EventHandlerProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowEventHandler', { FlowView: this });
|
|
658
370
|
this._LayoutProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowLayouts', { FlowView: this });
|
|
371
|
+
this._LayoutProvider.loadPersistedLayouts();
|
|
659
372
|
|
|
660
373
|
return super.onBeforeInitialize();
|
|
661
374
|
}
|
|
@@ -713,6 +426,36 @@ class PictViewFlow extends libPictView
|
|
|
713
426
|
this._PanelsLayer = tmpPanelsElements[0];
|
|
714
427
|
}
|
|
715
428
|
|
|
429
|
+
// Initialize theme and noise providers (fallback if not already created)
|
|
430
|
+
if (!this._ThemeProvider)
|
|
431
|
+
{
|
|
432
|
+
this._ThemeProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowTheme', { FlowView: this });
|
|
433
|
+
}
|
|
434
|
+
if (!this._NoiseProvider)
|
|
435
|
+
{
|
|
436
|
+
this._NoiseProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowNoise');
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Initialize CSS provider (fallback if not already created)
|
|
440
|
+
if (!this._CSSProvider)
|
|
441
|
+
{
|
|
442
|
+
this._CSSProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowCSS', { FlowView: this });
|
|
443
|
+
this._CSSProvider.registerCSS();
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Initialize icon provider (fallback if not already created)
|
|
447
|
+
if (!this._IconProvider)
|
|
448
|
+
{
|
|
449
|
+
this._IconProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowIcons', { FlowView: this });
|
|
450
|
+
this._IconProvider.registerIconTemplates();
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Initialize connector shapes provider (fallback if not already created)
|
|
454
|
+
if (!this._ConnectorShapesProvider)
|
|
455
|
+
{
|
|
456
|
+
this._ConnectorShapesProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowConnectorShapes', { FlowView: this });
|
|
457
|
+
}
|
|
458
|
+
|
|
716
459
|
// Initialize shared utility providers (used by services below)
|
|
717
460
|
if (!this._SVGHelperProvider)
|
|
718
461
|
{
|
|
@@ -748,6 +491,18 @@ class PictViewFlow extends libPictView
|
|
|
748
491
|
{
|
|
749
492
|
this._LayoutService = this.fable.instantiateServiceProviderWithoutRegistration('PictServiceFlowLayout', { FlowView: this });
|
|
750
493
|
}
|
|
494
|
+
if (!this._ViewportManager)
|
|
495
|
+
{
|
|
496
|
+
this._ViewportManager = this.fable.instantiateServiceProviderWithoutRegistration('PictServiceFlowViewportManager', { FlowView: this });
|
|
497
|
+
}
|
|
498
|
+
if (!this._SelectionManager)
|
|
499
|
+
{
|
|
500
|
+
this._SelectionManager = this.fable.instantiateServiceProviderWithoutRegistration('PictServiceFlowSelectionManager', { FlowView: this });
|
|
501
|
+
}
|
|
502
|
+
if (!this._PanelManager)
|
|
503
|
+
{
|
|
504
|
+
this._PanelManager = this.fable.instantiateServiceProviderWithoutRegistration('PictServiceFlowPanelManager', { FlowView: this });
|
|
505
|
+
}
|
|
751
506
|
if (!this._NodeTypeProvider)
|
|
752
507
|
{
|
|
753
508
|
this._NodeTypeProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowNodeTypes', { FlowView: this, AdditionalNodeTypes: this.options.NodeTypes });
|
|
@@ -759,6 +514,25 @@ class PictViewFlow extends libPictView
|
|
|
759
514
|
if (!this._LayoutProvider)
|
|
760
515
|
{
|
|
761
516
|
this._LayoutProvider = this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowLayouts', { FlowView: this });
|
|
517
|
+
this._LayoutProvider.loadPersistedLayouts();
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Inject marker defs via the connector shapes provider
|
|
521
|
+
// Note: insertAdjacentHTML does not work on SVG elements (wrong namespace),
|
|
522
|
+
// so we parse via a temporary <svg> element to ensure SVG namespace.
|
|
523
|
+
if (this._ConnectorShapesProvider && this._SVGElement)
|
|
524
|
+
{
|
|
525
|
+
let tmpDefs = this._SVGElement.querySelector('defs');
|
|
526
|
+
if (tmpDefs)
|
|
527
|
+
{
|
|
528
|
+
let tmpMarkerMarkup = this._ConnectorShapesProvider.generateMarkerDefs(tmpViewIdentifier);
|
|
529
|
+
let tmpTempSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
530
|
+
tmpTempSVG.innerHTML = tmpMarkerMarkup;
|
|
531
|
+
while (tmpTempSVG.firstChild)
|
|
532
|
+
{
|
|
533
|
+
tmpDefs.appendChild(tmpTempSVG.firstChild);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
762
536
|
}
|
|
763
537
|
|
|
764
538
|
// Setup the toolbar if enabled
|
|
@@ -890,6 +664,12 @@ class PictViewFlow extends libPictView
|
|
|
890
664
|
)
|
|
891
665
|
};
|
|
892
666
|
|
|
667
|
+
// Merge any browser-persisted layouts into the newly loaded data
|
|
668
|
+
if (this._LayoutProvider)
|
|
669
|
+
{
|
|
670
|
+
this._LayoutProvider.loadPersistedLayouts();
|
|
671
|
+
}
|
|
672
|
+
|
|
893
673
|
if (this.initialRenderComplete)
|
|
894
674
|
{
|
|
895
675
|
this.renderFlow();
|
|
@@ -1107,18 +887,7 @@ class PictViewFlow extends libPictView
|
|
|
1107
887
|
*/
|
|
1108
888
|
selectNode(pNodeHash)
|
|
1109
889
|
{
|
|
1110
|
-
|
|
1111
|
-
this._FlowData.ViewState.SelectedNodeHash = pNodeHash;
|
|
1112
|
-
this._FlowData.ViewState.SelectedConnectionHash = null;
|
|
1113
|
-
this._FlowData.ViewState.SelectedTetherHash = null;
|
|
1114
|
-
|
|
1115
|
-
this.renderFlow();
|
|
1116
|
-
|
|
1117
|
-
if (this._EventHandlerProvider && pNodeHash !== tmpPreviousSelection)
|
|
1118
|
-
{
|
|
1119
|
-
let tmpNode = pNodeHash ? this._FlowData.Nodes.find((pNode) => pNode.Hash === pNodeHash) : null;
|
|
1120
|
-
this._EventHandlerProvider.fireEvent('onNodeSelected', tmpNode);
|
|
1121
|
-
}
|
|
890
|
+
return this._SelectionManager.selectNode(pNodeHash);
|
|
1122
891
|
}
|
|
1123
892
|
|
|
1124
893
|
/**
|
|
@@ -1127,18 +896,7 @@ class PictViewFlow extends libPictView
|
|
|
1127
896
|
*/
|
|
1128
897
|
selectConnection(pConnectionHash)
|
|
1129
898
|
{
|
|
1130
|
-
|
|
1131
|
-
this._FlowData.ViewState.SelectedConnectionHash = pConnectionHash;
|
|
1132
|
-
this._FlowData.ViewState.SelectedNodeHash = null;
|
|
1133
|
-
this._FlowData.ViewState.SelectedTetherHash = null;
|
|
1134
|
-
|
|
1135
|
-
this.renderFlow();
|
|
1136
|
-
|
|
1137
|
-
if (this._EventHandlerProvider && pConnectionHash !== tmpPreviousSelection)
|
|
1138
|
-
{
|
|
1139
|
-
let tmpConnection = pConnectionHash ? this._FlowData.Connections.find((pConn) => pConn.Hash === pConnectionHash) : null;
|
|
1140
|
-
this._EventHandlerProvider.fireEvent('onConnectionSelected', tmpConnection);
|
|
1141
|
-
}
|
|
899
|
+
return this._SelectionManager.selectConnection(pConnectionHash);
|
|
1142
900
|
}
|
|
1143
901
|
|
|
1144
902
|
/**
|
|
@@ -1146,10 +904,7 @@ class PictViewFlow extends libPictView
|
|
|
1146
904
|
*/
|
|
1147
905
|
deselectAll()
|
|
1148
906
|
{
|
|
1149
|
-
this.
|
|
1150
|
-
this._FlowData.ViewState.SelectedConnectionHash = null;
|
|
1151
|
-
this._FlowData.ViewState.SelectedTetherHash = null;
|
|
1152
|
-
this.renderFlow();
|
|
907
|
+
return this._SelectionManager.deselectAll();
|
|
1153
908
|
}
|
|
1154
909
|
|
|
1155
910
|
/**
|
|
@@ -1158,15 +913,7 @@ class PictViewFlow extends libPictView
|
|
|
1158
913
|
*/
|
|
1159
914
|
deleteSelected()
|
|
1160
915
|
{
|
|
1161
|
-
|
|
1162
|
-
{
|
|
1163
|
-
return this.removeNode(this._FlowData.ViewState.SelectedNodeHash);
|
|
1164
|
-
}
|
|
1165
|
-
if (this._FlowData.ViewState.SelectedConnectionHash)
|
|
1166
|
-
{
|
|
1167
|
-
return this.removeConnection(this._FlowData.ViewState.SelectedConnectionHash);
|
|
1168
|
-
}
|
|
1169
|
-
return false;
|
|
916
|
+
return this._SelectionManager.deleteSelected();
|
|
1170
917
|
}
|
|
1171
918
|
|
|
1172
919
|
/**
|
|
@@ -1174,11 +921,7 @@ class PictViewFlow extends libPictView
|
|
|
1174
921
|
*/
|
|
1175
922
|
updateViewportTransform()
|
|
1176
923
|
{
|
|
1177
|
-
|
|
1178
|
-
let tmpVS = this._FlowData.ViewState;
|
|
1179
|
-
this._ViewportElement.setAttribute('transform',
|
|
1180
|
-
`translate(${tmpVS.PanX}, ${tmpVS.PanY}) scale(${tmpVS.Zoom})`
|
|
1181
|
-
);
|
|
924
|
+
return this._ViewportManager.updateViewportTransform();
|
|
1182
925
|
}
|
|
1183
926
|
|
|
1184
927
|
/**
|
|
@@ -1189,19 +932,7 @@ class PictViewFlow extends libPictView
|
|
|
1189
932
|
*/
|
|
1190
933
|
setZoom(pZoom, pFocusX, pFocusY)
|
|
1191
934
|
{
|
|
1192
|
-
|
|
1193
|
-
let tmpOldZoom = this._FlowData.ViewState.Zoom;
|
|
1194
|
-
|
|
1195
|
-
if (typeof pFocusX === 'number' && typeof pFocusY === 'number')
|
|
1196
|
-
{
|
|
1197
|
-
// Zoom toward focus point
|
|
1198
|
-
let tmpVS = this._FlowData.ViewState;
|
|
1199
|
-
tmpVS.PanX = pFocusX - (pFocusX - tmpVS.PanX) * (tmpNewZoom / tmpOldZoom);
|
|
1200
|
-
tmpVS.PanY = pFocusY - (pFocusY - tmpVS.PanY) * (tmpNewZoom / tmpOldZoom);
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
this._FlowData.ViewState.Zoom = tmpNewZoom;
|
|
1204
|
-
this.updateViewportTransform();
|
|
935
|
+
return this._ViewportManager.setZoom(pZoom, pFocusX, pFocusY);
|
|
1205
936
|
}
|
|
1206
937
|
|
|
1207
938
|
/**
|
|
@@ -1209,39 +940,7 @@ class PictViewFlow extends libPictView
|
|
|
1209
940
|
*/
|
|
1210
941
|
zoomToFit()
|
|
1211
942
|
{
|
|
1212
|
-
|
|
1213
|
-
if (!this._SVGElement) return;
|
|
1214
|
-
|
|
1215
|
-
let tmpMinX = Infinity, tmpMinY = Infinity;
|
|
1216
|
-
let tmpMaxX = -Infinity, tmpMaxY = -Infinity;
|
|
1217
|
-
|
|
1218
|
-
for (let i = 0; i < this._FlowData.Nodes.length; i++)
|
|
1219
|
-
{
|
|
1220
|
-
let tmpNode = this._FlowData.Nodes[i];
|
|
1221
|
-
tmpMinX = Math.min(tmpMinX, tmpNode.X);
|
|
1222
|
-
tmpMinY = Math.min(tmpMinY, tmpNode.Y);
|
|
1223
|
-
tmpMaxX = Math.max(tmpMaxX, tmpNode.X + tmpNode.Width);
|
|
1224
|
-
tmpMaxY = Math.max(tmpMaxY, tmpNode.Y + tmpNode.Height);
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
let tmpPadding = 50;
|
|
1228
|
-
let tmpFlowWidth = tmpMaxX - tmpMinX + tmpPadding * 2;
|
|
1229
|
-
let tmpFlowHeight = tmpMaxY - tmpMinY + tmpPadding * 2;
|
|
1230
|
-
|
|
1231
|
-
let tmpSVGRect = this._SVGElement.getBoundingClientRect();
|
|
1232
|
-
let tmpScaleX = tmpSVGRect.width / tmpFlowWidth;
|
|
1233
|
-
let tmpScaleY = tmpSVGRect.height / tmpFlowHeight;
|
|
1234
|
-
let tmpZoom = Math.min(tmpScaleX, tmpScaleY, 1.0); // Don't zoom in past 1.0
|
|
1235
|
-
tmpZoom = Math.max(this.options.MinZoom, Math.min(this.options.MaxZoom, tmpZoom));
|
|
1236
|
-
|
|
1237
|
-
let tmpCenterX = (tmpMinX + tmpMaxX) / 2;
|
|
1238
|
-
let tmpCenterY = (tmpMinY + tmpMaxY) / 2;
|
|
1239
|
-
|
|
1240
|
-
this._FlowData.ViewState.Zoom = tmpZoom;
|
|
1241
|
-
this._FlowData.ViewState.PanX = (tmpSVGRect.width / 2) - (tmpCenterX * tmpZoom);
|
|
1242
|
-
this._FlowData.ViewState.PanY = (tmpSVGRect.height / 2) - (tmpCenterY * tmpZoom);
|
|
1243
|
-
|
|
1244
|
-
this.updateViewportTransform();
|
|
943
|
+
return this._ViewportManager.zoomToFit();
|
|
1245
944
|
}
|
|
1246
945
|
|
|
1247
946
|
/**
|
|
@@ -1269,41 +968,129 @@ class PictViewFlow extends libPictView
|
|
|
1269
968
|
*/
|
|
1270
969
|
toggleFullscreen()
|
|
1271
970
|
{
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
if (tmpContainerElements.length < 1) return this._IsFullscreen;
|
|
971
|
+
return this._ViewportManager.toggleFullscreen();
|
|
972
|
+
}
|
|
1275
973
|
|
|
1276
|
-
|
|
974
|
+
/**
|
|
975
|
+
* Exit fullscreen mode if currently active.
|
|
976
|
+
*/
|
|
977
|
+
exitFullscreen()
|
|
978
|
+
{
|
|
979
|
+
return this._ViewportManager.exitFullscreen();
|
|
980
|
+
}
|
|
1277
981
|
|
|
1278
|
-
|
|
982
|
+
// ── Theme API ────────────────────────────────────────────────────────
|
|
1279
983
|
|
|
1280
|
-
|
|
984
|
+
/**
|
|
985
|
+
* Switch the active theme and re-render.
|
|
986
|
+
* @param {string} pThemeKey - Theme key (e.g. 'default', 'sketch', 'blueprint', 'mono', 'retro-80s', 'retro-90s')
|
|
987
|
+
*/
|
|
988
|
+
setTheme(pThemeKey)
|
|
989
|
+
{
|
|
990
|
+
if (!this._ThemeProvider)
|
|
991
|
+
{
|
|
992
|
+
this.log.warn('PictSectionFlow setTheme: ThemeProvider not available');
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
let tmpApplied = this._ThemeProvider.setTheme(pThemeKey);
|
|
997
|
+
if (!tmpApplied) return;
|
|
998
|
+
|
|
999
|
+
// Re-register CSS with the new theme overrides
|
|
1000
|
+
if (this._CSSProvider)
|
|
1281
1001
|
{
|
|
1282
|
-
|
|
1002
|
+
this._CSSProvider.registerCSS();
|
|
1283
1003
|
}
|
|
1284
|
-
|
|
1004
|
+
|
|
1005
|
+
// Re-inject marker defs (arrowhead colors may have changed)
|
|
1006
|
+
this._reinjectMarkerDefs();
|
|
1007
|
+
|
|
1008
|
+
// Full re-render
|
|
1009
|
+
if (this.initialRenderComplete)
|
|
1285
1010
|
{
|
|
1286
|
-
|
|
1011
|
+
this.renderFlow();
|
|
1287
1012
|
}
|
|
1288
1013
|
|
|
1289
|
-
|
|
1014
|
+
if (this._EventHandlerProvider)
|
|
1015
|
+
{
|
|
1016
|
+
this._EventHandlerProvider.fireEvent('onThemeChanged', pThemeKey);
|
|
1017
|
+
}
|
|
1290
1018
|
}
|
|
1291
1019
|
|
|
1292
1020
|
/**
|
|
1293
|
-
*
|
|
1021
|
+
* Set the noise level (0 to 1) and re-render.
|
|
1022
|
+
* @param {number} pLevel - 0 = precise, 1 = maximum wobble
|
|
1294
1023
|
*/
|
|
1295
|
-
|
|
1024
|
+
setNoiseLevel(pLevel)
|
|
1025
|
+
{
|
|
1026
|
+
if (!this._ThemeProvider)
|
|
1027
|
+
{
|
|
1028
|
+
this.log.warn('PictSectionFlow setNoiseLevel: ThemeProvider not available');
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
this._ThemeProvider.setNoiseLevel(pLevel);
|
|
1033
|
+
|
|
1034
|
+
// Full re-render to apply new noise
|
|
1035
|
+
if (this.initialRenderComplete)
|
|
1036
|
+
{
|
|
1037
|
+
this.renderFlow();
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
/**
|
|
1042
|
+
* Get the current noise level (0 to 1).
|
|
1043
|
+
* @returns {number}
|
|
1044
|
+
*/
|
|
1045
|
+
getNoiseLevel()
|
|
1046
|
+
{
|
|
1047
|
+
if (this._ThemeProvider)
|
|
1048
|
+
{
|
|
1049
|
+
return this._ThemeProvider.getNoiseLevel();
|
|
1050
|
+
}
|
|
1051
|
+
return 0;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
/**
|
|
1055
|
+
* Get the active theme key.
|
|
1056
|
+
* @returns {string}
|
|
1057
|
+
*/
|
|
1058
|
+
getThemeKey()
|
|
1059
|
+
{
|
|
1060
|
+
if (this._ThemeProvider)
|
|
1061
|
+
{
|
|
1062
|
+
return this._ThemeProvider.getActiveThemeKey();
|
|
1063
|
+
}
|
|
1064
|
+
return 'default';
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
/**
|
|
1068
|
+
* Re-inject SVG marker definitions (arrowheads).
|
|
1069
|
+
* Called after a theme switch to update arrowhead colors.
|
|
1070
|
+
*/
|
|
1071
|
+
_reinjectMarkerDefs()
|
|
1296
1072
|
{
|
|
1297
|
-
if (!this.
|
|
1073
|
+
if (!this._ConnectorShapesProvider || !this._SVGElement) return;
|
|
1298
1074
|
|
|
1299
1075
|
let tmpViewIdentifier = this.options.ViewIdentifier;
|
|
1300
|
-
let
|
|
1301
|
-
if (
|
|
1076
|
+
let tmpDefs = this._SVGElement.querySelector('defs');
|
|
1077
|
+
if (!tmpDefs) return;
|
|
1078
|
+
|
|
1079
|
+
// Remove existing marker elements
|
|
1080
|
+
let tmpExistingMarkers = tmpDefs.querySelectorAll('marker');
|
|
1081
|
+
for (let i = 0; i < tmpExistingMarkers.length; i++)
|
|
1302
1082
|
{
|
|
1303
|
-
|
|
1083
|
+
tmpExistingMarkers[i].remove();
|
|
1304
1084
|
}
|
|
1305
1085
|
|
|
1306
|
-
|
|
1086
|
+
// Re-generate and inject
|
|
1087
|
+
let tmpMarkerMarkup = this._ConnectorShapesProvider.generateMarkerDefs(tmpViewIdentifier);
|
|
1088
|
+
let tmpTempSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
1089
|
+
tmpTempSVG.innerHTML = tmpMarkerMarkup;
|
|
1090
|
+
while (tmpTempSVG.firstChild)
|
|
1091
|
+
{
|
|
1092
|
+
tmpDefs.appendChild(tmpTempSVG.firstChild);
|
|
1093
|
+
}
|
|
1307
1094
|
}
|
|
1308
1095
|
|
|
1309
1096
|
/**
|
|
@@ -1332,18 +1119,7 @@ class PictViewFlow extends libPictView
|
|
|
1332
1119
|
*/
|
|
1333
1120
|
selectTether(pPanelHash)
|
|
1334
1121
|
{
|
|
1335
|
-
|
|
1336
|
-
this._FlowData.ViewState.SelectedTetherHash = pPanelHash;
|
|
1337
|
-
this._FlowData.ViewState.SelectedNodeHash = null;
|
|
1338
|
-
this._FlowData.ViewState.SelectedConnectionHash = null;
|
|
1339
|
-
|
|
1340
|
-
this.renderFlow();
|
|
1341
|
-
|
|
1342
|
-
if (this._EventHandlerProvider && pPanelHash !== tmpPreviousSelection)
|
|
1343
|
-
{
|
|
1344
|
-
let tmpPanel = pPanelHash ? this._FlowData.OpenPanels.find((pPanel) => pPanel.Hash === pPanelHash) : null;
|
|
1345
|
-
this._EventHandlerProvider.fireEvent('onTetherSelected', tmpPanel);
|
|
1346
|
-
}
|
|
1122
|
+
return this._SelectionManager.selectTether(pPanelHash);
|
|
1347
1123
|
}
|
|
1348
1124
|
|
|
1349
1125
|
/**
|
|
@@ -1552,40 +1328,9 @@ class PictViewFlow extends libPictView
|
|
|
1552
1328
|
|
|
1553
1329
|
let tmpTitleBarHeight = (this._NodeView && this._NodeView.options.NodeTitleBarHeight) || 28;
|
|
1554
1330
|
|
|
1555
|
-
let
|
|
1331
|
+
let tmpLocal = this._GeometryProvider.getPortLocalPosition(tmpPort.Side, tmpPortIndex, tmpPortCount, tmpNode.Width, tmpNode.Height, tmpTitleBarHeight);
|
|
1556
1332
|
|
|
1557
|
-
|
|
1558
|
-
{
|
|
1559
|
-
case 'left':
|
|
1560
|
-
{
|
|
1561
|
-
// Distribute ports in the body area below the title bar
|
|
1562
|
-
let tmpBodyHeight = tmpNode.Height - tmpTitleBarHeight;
|
|
1563
|
-
tmpX = tmpNode.X;
|
|
1564
|
-
tmpY = tmpNode.Y + tmpTitleBarHeight + ((tmpPortIndex + 1) / (tmpPortCount + 1)) * tmpBodyHeight;
|
|
1565
|
-
break;
|
|
1566
|
-
}
|
|
1567
|
-
case 'right':
|
|
1568
|
-
{
|
|
1569
|
-
let tmpBodyHeight = tmpNode.Height - tmpTitleBarHeight;
|
|
1570
|
-
tmpX = tmpNode.X + tmpNode.Width;
|
|
1571
|
-
tmpY = tmpNode.Y + tmpTitleBarHeight + ((tmpPortIndex + 1) / (tmpPortCount + 1)) * tmpBodyHeight;
|
|
1572
|
-
break;
|
|
1573
|
-
}
|
|
1574
|
-
case 'top':
|
|
1575
|
-
tmpX = tmpNode.X + ((tmpPortIndex + 1) / (tmpPortCount + 1)) * tmpNode.Width;
|
|
1576
|
-
tmpY = tmpNode.Y;
|
|
1577
|
-
break;
|
|
1578
|
-
case 'bottom':
|
|
1579
|
-
tmpX = tmpNode.X + ((tmpPortIndex + 1) / (tmpPortCount + 1)) * tmpNode.Width;
|
|
1580
|
-
tmpY = tmpNode.Y + tmpNode.Height;
|
|
1581
|
-
break;
|
|
1582
|
-
default:
|
|
1583
|
-
tmpX = tmpNode.X + tmpNode.Width;
|
|
1584
|
-
tmpY = tmpNode.Y + tmpNode.Height / 2;
|
|
1585
|
-
break;
|
|
1586
|
-
}
|
|
1587
|
-
|
|
1588
|
-
return { x: tmpX, y: tmpY, side: tmpPort.Side || 'right' };
|
|
1333
|
+
return { x: tmpNode.X + tmpLocal.x, y: tmpNode.Y + tmpLocal.y, side: tmpPort.Side || 'right' };
|
|
1589
1334
|
}
|
|
1590
1335
|
|
|
1591
1336
|
/**
|
|
@@ -1596,29 +1341,7 @@ class PictViewFlow extends libPictView
|
|
|
1596
1341
|
*/
|
|
1597
1342
|
screenToSVGCoords(pScreenX, pScreenY)
|
|
1598
1343
|
{
|
|
1599
|
-
|
|
1600
|
-
{
|
|
1601
|
-
return { x: pScreenX, y: pScreenY };
|
|
1602
|
-
}
|
|
1603
|
-
|
|
1604
|
-
let tmpPoint = this._SVGElement.createSVGPoint();
|
|
1605
|
-
tmpPoint.x = pScreenX;
|
|
1606
|
-
tmpPoint.y = pScreenY;
|
|
1607
|
-
|
|
1608
|
-
let tmpCTM = this._SVGElement.getScreenCTM();
|
|
1609
|
-
if (tmpCTM)
|
|
1610
|
-
{
|
|
1611
|
-
let tmpInverse = tmpCTM.inverse();
|
|
1612
|
-
let tmpTransformed = tmpPoint.matrixTransform(tmpInverse);
|
|
1613
|
-
// Account for viewport pan/zoom
|
|
1614
|
-
let tmpVS = this._FlowData.ViewState;
|
|
1615
|
-
return {
|
|
1616
|
-
x: (tmpTransformed.x - tmpVS.PanX) / tmpVS.Zoom,
|
|
1617
|
-
y: (tmpTransformed.y - tmpVS.PanY) / tmpVS.Zoom
|
|
1618
|
-
};
|
|
1619
|
-
}
|
|
1620
|
-
|
|
1621
|
-
return { x: pScreenX, y: pScreenY };
|
|
1344
|
+
return this._ViewportManager.screenToSVGCoords(pScreenX, pScreenY);
|
|
1622
1345
|
}
|
|
1623
1346
|
|
|
1624
1347
|
/**
|
|
@@ -1773,59 +1496,7 @@ class PictViewFlow extends libPictView
|
|
|
1773
1496
|
*/
|
|
1774
1497
|
openPanel(pNodeHash)
|
|
1775
1498
|
{
|
|
1776
|
-
|
|
1777
|
-
if (!tmpNode) return false;
|
|
1778
|
-
|
|
1779
|
-
let tmpNodeTypeConfig = this._NodeTypeProvider.getNodeType(tmpNode.Type);
|
|
1780
|
-
if (!tmpNodeTypeConfig) return false;
|
|
1781
|
-
|
|
1782
|
-
// Check if a panel is already open for this node
|
|
1783
|
-
let tmpExisting = this._FlowData.OpenPanels.find((pPanel) => pPanel.NodeHash === pNodeHash);
|
|
1784
|
-
if (tmpExisting) return tmpExisting;
|
|
1785
|
-
|
|
1786
|
-
let tmpPanelConfig = tmpNodeTypeConfig.PropertiesPanel;
|
|
1787
|
-
let tmpPanelHash = `panel-${this.fable.getUUID()}`;
|
|
1788
|
-
let tmpWidth, tmpHeight, tmpPanelType, tmpTitle;
|
|
1789
|
-
|
|
1790
|
-
if (tmpPanelConfig)
|
|
1791
|
-
{
|
|
1792
|
-
tmpWidth = tmpPanelConfig.DefaultWidth || 300;
|
|
1793
|
-
tmpHeight = tmpPanelConfig.DefaultHeight || 200;
|
|
1794
|
-
tmpPanelType = tmpPanelConfig.PanelType || 'Base';
|
|
1795
|
-
tmpTitle = tmpPanelConfig.Title || tmpNodeTypeConfig.Label || 'Properties';
|
|
1796
|
-
}
|
|
1797
|
-
else
|
|
1798
|
-
{
|
|
1799
|
-
// No PropertiesPanel configured — open an auto-generated info panel
|
|
1800
|
-
tmpWidth = 240;
|
|
1801
|
-
tmpHeight = 180;
|
|
1802
|
-
tmpPanelType = 'Info';
|
|
1803
|
-
tmpTitle = tmpNodeTypeConfig.Label || tmpNode.Title || 'Node Info';
|
|
1804
|
-
}
|
|
1805
|
-
|
|
1806
|
-
let tmpPanelData =
|
|
1807
|
-
{
|
|
1808
|
-
Hash: tmpPanelHash,
|
|
1809
|
-
NodeHash: pNodeHash,
|
|
1810
|
-
PanelType: tmpPanelType,
|
|
1811
|
-
Title: tmpTitle,
|
|
1812
|
-
X: tmpNode.X + tmpNode.Width + 30,
|
|
1813
|
-
Y: tmpNode.Y,
|
|
1814
|
-
Width: tmpWidth,
|
|
1815
|
-
Height: tmpHeight
|
|
1816
|
-
};
|
|
1817
|
-
|
|
1818
|
-
this._FlowData.OpenPanels.push(tmpPanelData);
|
|
1819
|
-
this.renderFlow();
|
|
1820
|
-
this.marshalFromView();
|
|
1821
|
-
|
|
1822
|
-
if (this._EventHandlerProvider)
|
|
1823
|
-
{
|
|
1824
|
-
this._EventHandlerProvider.fireEvent('onPanelOpened', tmpPanelData);
|
|
1825
|
-
this._EventHandlerProvider.fireEvent('onFlowChanged', this._FlowData);
|
|
1826
|
-
}
|
|
1827
|
-
|
|
1828
|
-
return tmpPanelData;
|
|
1499
|
+
return this._PanelManager.openPanel(pNodeHash);
|
|
1829
1500
|
}
|
|
1830
1501
|
|
|
1831
1502
|
/**
|
|
@@ -1835,27 +1506,7 @@ class PictViewFlow extends libPictView
|
|
|
1835
1506
|
*/
|
|
1836
1507
|
closePanel(pPanelHash)
|
|
1837
1508
|
{
|
|
1838
|
-
|
|
1839
|
-
if (tmpIndex < 0) return false;
|
|
1840
|
-
|
|
1841
|
-
let tmpRemovedPanel = this._FlowData.OpenPanels.splice(tmpIndex, 1)[0];
|
|
1842
|
-
|
|
1843
|
-
// Clean up the panel instance
|
|
1844
|
-
if (this._PropertiesPanelView)
|
|
1845
|
-
{
|
|
1846
|
-
this._PropertiesPanelView.destroyPanel(pPanelHash);
|
|
1847
|
-
}
|
|
1848
|
-
|
|
1849
|
-
this.renderFlow();
|
|
1850
|
-
this.marshalFromView();
|
|
1851
|
-
|
|
1852
|
-
if (this._EventHandlerProvider)
|
|
1853
|
-
{
|
|
1854
|
-
this._EventHandlerProvider.fireEvent('onPanelClosed', tmpRemovedPanel);
|
|
1855
|
-
this._EventHandlerProvider.fireEvent('onFlowChanged', this._FlowData);
|
|
1856
|
-
}
|
|
1857
|
-
|
|
1858
|
-
return true;
|
|
1509
|
+
return this._PanelManager.closePanel(pPanelHash);
|
|
1859
1510
|
}
|
|
1860
1511
|
|
|
1861
1512
|
/**
|
|
@@ -1865,23 +1516,7 @@ class PictViewFlow extends libPictView
|
|
|
1865
1516
|
*/
|
|
1866
1517
|
closePanelForNode(pNodeHash)
|
|
1867
1518
|
{
|
|
1868
|
-
|
|
1869
|
-
if (tmpPanelsToClose.length === 0) return false;
|
|
1870
|
-
|
|
1871
|
-
for (let i = 0; i < tmpPanelsToClose.length; i++)
|
|
1872
|
-
{
|
|
1873
|
-
let tmpIndex = this._FlowData.OpenPanels.indexOf(tmpPanelsToClose[i]);
|
|
1874
|
-
if (tmpIndex >= 0)
|
|
1875
|
-
{
|
|
1876
|
-
this._FlowData.OpenPanels.splice(tmpIndex, 1);
|
|
1877
|
-
}
|
|
1878
|
-
if (this._PropertiesPanelView)
|
|
1879
|
-
{
|
|
1880
|
-
this._PropertiesPanelView.destroyPanel(tmpPanelsToClose[i].Hash);
|
|
1881
|
-
}
|
|
1882
|
-
}
|
|
1883
|
-
|
|
1884
|
-
return true;
|
|
1519
|
+
return this._PanelManager.closePanelForNode(pNodeHash);
|
|
1885
1520
|
}
|
|
1886
1521
|
|
|
1887
1522
|
/**
|
|
@@ -1891,13 +1526,7 @@ class PictViewFlow extends libPictView
|
|
|
1891
1526
|
*/
|
|
1892
1527
|
togglePanel(pNodeHash)
|
|
1893
1528
|
{
|
|
1894
|
-
|
|
1895
|
-
if (tmpExisting)
|
|
1896
|
-
{
|
|
1897
|
-
this.closePanel(tmpExisting.Hash);
|
|
1898
|
-
return false;
|
|
1899
|
-
}
|
|
1900
|
-
return this.openPanel(pNodeHash);
|
|
1529
|
+
return this._PanelManager.togglePanel(pNodeHash);
|
|
1901
1530
|
}
|
|
1902
1531
|
|
|
1903
1532
|
/**
|
|
@@ -1908,28 +1537,7 @@ class PictViewFlow extends libPictView
|
|
|
1908
1537
|
*/
|
|
1909
1538
|
updatePanelPosition(pPanelHash, pX, pY)
|
|
1910
1539
|
{
|
|
1911
|
-
|
|
1912
|
-
if (!tmpPanel) return;
|
|
1913
|
-
|
|
1914
|
-
tmpPanel.X = pX;
|
|
1915
|
-
tmpPanel.Y = pY;
|
|
1916
|
-
|
|
1917
|
-
// Reset tether handle positions when panel moves
|
|
1918
|
-
this._resetHandlesForPanel(pPanelHash);
|
|
1919
|
-
|
|
1920
|
-
// Update the foreignObject position directly for smooth dragging
|
|
1921
|
-
if (this._PanelsLayer)
|
|
1922
|
-
{
|
|
1923
|
-
let tmpFO = this._PanelsLayer.querySelector(`[data-panel-hash="${pPanelHash}"]`);
|
|
1924
|
-
if (tmpFO)
|
|
1925
|
-
{
|
|
1926
|
-
tmpFO.setAttribute('x', String(pX));
|
|
1927
|
-
tmpFO.setAttribute('y', String(pY));
|
|
1928
|
-
}
|
|
1929
|
-
}
|
|
1930
|
-
|
|
1931
|
-
// Update the tether for this panel
|
|
1932
|
-
this._renderTethersForNode(tmpPanel.NodeHash);
|
|
1540
|
+
return this._PanelManager.updatePanelPosition(pPanelHash, pX, pY);
|
|
1933
1541
|
}
|
|
1934
1542
|
}
|
|
1935
1543
|
|