@babylonjs/shared-ui-components 5.45.1 → 5.46.0

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.
@@ -23,398 +23,608 @@ export var FramePortPosition;
23
23
  FramePortPosition[FramePortPosition["Bottom"] = 2] = "Bottom";
24
24
  })(FramePortPosition || (FramePortPosition = {}));
25
25
  export class GraphFrame {
26
- constructor(candidate, canvas, doNotCaptureNodes = false) {
27
- this._collapsedWidth = 200;
28
- this._x = 0;
29
- this._y = 0;
30
- this._gridAlignedX = 0;
31
- this._gridAlignedY = 0;
32
- this._nodes = [];
33
- this._mouseStartPointX = null;
34
- this._mouseStartPointY = null;
35
- this._onNodeLinkDisposedObservers = [];
36
- this._isCollapsed = false;
37
- this._frameInPorts = [];
38
- this._frameOutPorts = [];
39
- this._controlledPorts = []; // Ports on Nodes that are shown on outside of frame
40
- this._exposedInPorts = [];
41
- this._exposedOutPorts = [];
42
- this._minFrameHeight = 40;
43
- this._minFrameWidth = 220;
44
- this.onExpandStateChanged = new Observable();
45
- this._closeSVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><g id="Layer_2" data-name="Layer 2"><path d="M16,15l5.85,5.84-1,1L15,15.93,9.15,21.78l-1-1L14,15,8.19,9.12l1-1L15,14l5.84-5.84,1,1Z"/></g></svg>`;
46
- this._expandSVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><g id="Layer_2" data-name="Layer 2"><path d="M22.31,7.69V22.31H7.69V7.69ZM21.19,8.81H8.81V21.19H21.19Zm-6.75,6.75H11.06V14.44h3.38V11.06h1.12v3.38h3.38v1.12H15.56v3.38H14.44Z"/></g></svg>`;
47
- this._collapseSVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><g id="Layer_2" data-name="Layer 2"><path d="M22.31,7.69V22.31H7.69V7.69ZM21.19,8.81H8.81V21.19H21.19Zm-2.25,6.75H11.06V14.44h7.88Z"/></g></svg>`;
48
- this._initResizing = (evt) => {
49
- evt.stopPropagation();
50
- this._mouseStartPointX = evt.clientX;
51
- this._mouseStartPointY = evt.clientY;
52
- this._frameIsResizing = true;
53
- };
54
- this._cleanUpResizing = (evt) => {
55
- evt.stopPropagation();
56
- this._frameIsResizing = false;
57
- this._resizingDirection = null;
58
- this._mouseStartPointX = null;
59
- this._mouseStartPointY = null;
60
- this._mouseXLimit = null;
61
- this.refresh();
62
- };
63
- this._updateMinHeightWithComments = () => {
64
- if (this.comments && this.comments.length > 0) {
65
- const minFrameHeightWithComments = this._commentsElement.offsetHeight + 40;
66
- this._minFrameHeight = minFrameHeightWithComments;
67
- }
68
- };
69
- this._onRightHandlePointerDown = (evt) => {
70
- if (this.isCollapsed) {
71
- return;
72
- }
73
- this._initResizing(evt);
74
- this._resizingDirection = ResizingDirection.Right;
75
- this._mouseXLimit = evt.clientX - (this.width - this._minFrameWidth);
76
- this._ownerCanvas.hostCanvas.addEventListener("pointerup", this._onRightHandlePointerUp);
77
- this._ownerCanvas.hostCanvas.addEventListener("pointermove", this._onRightHandlePointerMove);
78
- };
79
- this._onRightHandlePointerMove = (evt) => {
80
- const slack = (this.element.offsetWidth - this._minFrameWidth) * this._ownerCanvas.zoom;
81
- const xLimit = this._mouseStartPointX - slack;
82
- this._moveRightHandle(evt, xLimit);
83
- };
84
- this._moveRightHandle = (evt, xLimit) => {
85
- // tslint:disable-next-line: no-this-assignment
86
- if (this._mouseXLimit) {
87
- if (!this._isResizingRight() || this._mouseStartPointX === null || this._mouseStartPointY === null || evt.clientX < xLimit) {
88
- return;
26
+ get id() {
27
+ return this._id;
28
+ }
29
+ get isCollapsed() {
30
+ return this._isCollapsed;
31
+ }
32
+ _createInputPort(port, node) {
33
+ const localPort = FrameNodePort.CreateFrameNodePortElement(port.portData, node, this._inputPortContainer, null, this._ownerCanvas.stateManager, true, GraphFrame._FramePortCounter++, this.id);
34
+ this._frameInPorts.push(localPort);
35
+ port.delegatedPort = localPort;
36
+ this._controlledPorts.push(port);
37
+ port.exposedPortPosition = this._exposedInPorts.findIndex((nodePort) => nodePort === port);
38
+ if (port.exposedPortPosition < 0) {
39
+ this._exposedInPorts.push(port);
40
+ port.exposedPortPosition = this._exposedInPorts.length - 1;
41
+ }
42
+ }
43
+ // Mark ports with FramePortPosition for re-arrangement support
44
+ _markFramePortPositions() {
45
+ // mark FrameInPorts
46
+ if (this._frameInPorts.length == 2) {
47
+ this._frameInPorts[0].framePortPosition = FramePortPosition.Top;
48
+ this._frameInPorts[1].framePortPosition = FramePortPosition.Bottom;
49
+ }
50
+ else {
51
+ for (let i = 0; i < this._frameInPorts.length; i++) {
52
+ const port = this._frameInPorts[i];
53
+ if (i === 0) {
54
+ port.framePortPosition = FramePortPosition.Top;
89
55
  }
90
- if (this._isResizingRight()) {
91
- evt.stopPropagation();
92
- const distanceMouseMoved = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
93
- this._expandRight(distanceMouseMoved, evt.clientX);
94
- this._mouseStartPointX = evt.clientX;
56
+ else if (i === this._frameInPorts.length - 1) {
57
+ port.framePortPosition = FramePortPosition.Bottom;
58
+ }
59
+ else {
60
+ port.framePortPosition = FramePortPosition.Middle;
95
61
  }
96
62
  }
97
- };
98
- this._onRightHandlePointerUp = (evt) => {
99
- if (this._isResizingRight()) {
100
- this.width = parseFloat(this.element.style.width.replace("px", ""));
101
- this._ownerCanvas.hostCanvas.removeEventListener("pointerup", this._onRightHandlePointerUp);
102
- this._ownerCanvas.hostCanvas.removeEventListener("pointermove", this._onRightHandlePointerMove);
103
- this._cleanUpResizing(evt);
104
- }
105
- };
106
- this._onBottomHandlePointerDown = (evt) => {
107
- if (this.isCollapsed) {
108
- return;
109
- }
110
- this._initResizing(evt);
111
- this._resizingDirection = ResizingDirection.Bottom;
112
- this._ownerCanvas.hostCanvas.addEventListener("pointermove", this._onBottomHandlePointerMove);
113
- this._ownerCanvas.hostCanvas.addEventListener("pointerup", this._onBottomHandlePointerUp);
114
- };
115
- this._onBottomHandlePointerMove = (evt) => {
116
- const slack = (this.element.offsetHeight - this._minFrameHeight) * this._ownerCanvas.zoom;
117
- const yLimit = this._mouseStartPointY - slack;
118
- this._moveBottomHandle(evt, yLimit);
119
- };
120
- this._moveBottomHandle = (evt, yLimit) => {
121
- if (this._resizingDirection !== ResizingDirection.Bottom || this._mouseStartPointX === null || this._mouseStartPointY === null || evt.clientY < yLimit) {
122
- return;
123
- }
124
- if (this._resizingDirection === ResizingDirection.Bottom) {
125
- evt.stopPropagation();
126
- const distanceMouseMoved = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
127
- this._expandBottom(distanceMouseMoved);
128
- this._mouseStartPointY = evt.clientY;
63
+ }
64
+ // mark FrameOutPorts
65
+ if (this._frameOutPorts.length == 2) {
66
+ this._frameOutPorts[0].framePortPosition = FramePortPosition.Top;
67
+ this._frameOutPorts[1].framePortPosition = FramePortPosition.Bottom;
68
+ }
69
+ else {
70
+ for (let i = 0; i < this._frameOutPorts.length; i++) {
71
+ const port = this._frameOutPorts[i];
72
+ if (i === 0) {
73
+ port.framePortPosition = FramePortPosition.Top;
74
+ }
75
+ else if (i === this._frameInPorts.length - 1) {
76
+ port.framePortPosition = FramePortPosition.Bottom;
77
+ }
78
+ else {
79
+ port.framePortPosition = FramePortPosition.Middle;
80
+ }
129
81
  }
130
- };
131
- this._onBottomHandlePointerUp = (evt) => {
132
- if (this._resizingDirection === ResizingDirection.Bottom) {
133
- this.height = parseFloat(this.element.style.height.replace("px", ""));
134
- this._ownerCanvas.hostCanvas.removeEventListener("pointermove", this._onBottomHandlePointerMove);
135
- this._ownerCanvas.hostCanvas.removeEventListener("pointerup", this._onBottomHandlePointerUp);
136
- this._cleanUpResizing(evt);
82
+ }
83
+ }
84
+ _createFramePorts() {
85
+ for (const node of this._nodes) {
86
+ node.isVisible = false;
87
+ }
88
+ for (let i = 0; i < this._exposedOutPorts.length;) {
89
+ // Output
90
+ const port = this._exposedOutPorts[i];
91
+ if (port) {
92
+ if (port.node === null || port.node.enclosingFrameId != this.id) {
93
+ if (this._removePortFromExposedWithNode(port, this._exposedOutPorts))
94
+ continue;
95
+ }
96
+ else {
97
+ if (!this._createOutputPorts(port, port.node) && this._removePortFromExposedWithNode(port, this._exposedOutPorts)) {
98
+ continue;
99
+ }
100
+ }
137
101
  }
138
- };
139
- this._onLeftHandlePointerDown = (evt) => {
140
- if (this.isCollapsed) {
141
- return;
102
+ ++i;
103
+ }
104
+ for (let i = 0; i < this._exposedInPorts.length;) {
105
+ // Input
106
+ const port = this._exposedInPorts[i];
107
+ if (!port || port.node === null || port.node.enclosingFrameId != this.id) {
108
+ if (this._removePortFromExposedWithNode(port, this._exposedInPorts)) {
109
+ continue;
110
+ }
142
111
  }
143
- this._initResizing(evt);
144
- this._resizingDirection = ResizingDirection.Left;
145
- this._mouseXLimit = evt.clientX + this.width - this._minFrameWidth;
146
- this._ownerCanvas.hostCanvas.addEventListener("pointerup", this._onLeftHandlePointerUp);
147
- this._ownerCanvas.hostCanvas.addEventListener("pointermove", this._onLeftHandlePointerMove);
148
- };
149
- this._onLeftHandlePointerMove = (evt) => {
150
- const slack = (this.element.offsetWidth - this._minFrameWidth) * this._ownerCanvas.zoom;
151
- const xLimit = this._mouseStartPointX + slack;
152
- this._moveLeftHandle(evt, xLimit);
153
- };
154
- this._moveLeftHandle = (evt, xLimit) => {
155
- if (this._mouseXLimit) {
156
- if (this._resizingDirection !== ResizingDirection.Left || this._mouseStartPointX === null || this._mouseStartPointY === null || evt.clientX > xLimit) {
157
- return;
112
+ else {
113
+ if (!this._createInputPorts(port, port.node) && this._removePortFromExposedWithNode(port, this._exposedInPorts)) {
114
+ continue;
158
115
  }
159
- if (this._resizingDirection === ResizingDirection.Left) {
160
- evt.stopPropagation();
161
- const distanceMouseMoved = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
162
- this._expandLeft(distanceMouseMoved);
163
- this._mouseStartPointX = evt.clientX;
116
+ }
117
+ ++i;
118
+ }
119
+ for (const node of this._nodes) {
120
+ for (const port of node.outputPorts) {
121
+ // Output
122
+ port.exposedPortPosition = this._exposedOutPorts.findIndex((nodePort) => nodePort === port);
123
+ if (port.exposedPortPosition < 0) {
124
+ if (this._createOutputPorts(port, node)) {
125
+ port.node.enclosingFrameId = this.id;
126
+ this._exposedOutPorts.push(port);
127
+ port.exposedPortPosition = this._exposedOutPorts.length - 1;
128
+ }
164
129
  }
165
130
  }
166
- };
167
- this._onLeftHandlePointerUp = (evt) => {
168
- if (this._resizingDirection === ResizingDirection.Left) {
169
- this.x = parseFloat(this.element.style.left.replace("px", ""));
170
- this.width = parseFloat(this.element.style.width.replace("px", ""));
171
- this._ownerCanvas.hostCanvas.removeEventListener("pointerup", this._onLeftHandlePointerUp);
172
- this._ownerCanvas.hostCanvas.removeEventListener("pointermove", this._onLeftHandlePointerMove);
173
- this._cleanUpResizing(evt);
131
+ for (const port of node.inputPorts) {
132
+ // Input
133
+ port.exposedPortPosition = this._exposedInPorts.findIndex((nodePort) => nodePort === port);
134
+ if (port.exposedPortPosition < 0) {
135
+ this._createInputPorts(port, node);
136
+ }
174
137
  }
175
- };
176
- this._onTopHandlePointerDown = (evt) => {
177
- if (this.isCollapsed) {
178
- return;
138
+ }
139
+ }
140
+ _removePortFromExposedWithNode(port, exposedPorts) {
141
+ const index = exposedPorts.findIndex((nodePort) => nodePort === port);
142
+ if (index >= 0) {
143
+ exposedPorts.splice(index, 1);
144
+ if (port) {
145
+ port.exposedPortPosition = -1;
179
146
  }
180
- this._initResizing(evt);
181
- this._resizingDirection = ResizingDirection.Top;
182
- this._ownerCanvas.hostCanvas.addEventListener("pointerup", this._onTopHandlePointerUp);
183
- this._ownerCanvas.hostCanvas.addEventListener("pointermove", this._onTopHandlePointerMove);
184
- };
185
- this._onTopHandlePointerMove = (evt) => {
186
- const slack = (this.element.offsetHeight - this._minFrameHeight) * this._ownerCanvas.zoom;
187
- const yLimit = this._mouseStartPointY + slack;
188
- this._moveTopHandle(evt, yLimit);
189
- };
190
- this._moveTopHandle = (evt, yLimit) => {
191
- if (!this._isResizingTop() || this._mouseStartPointX === null || this._mouseStartPointY === null || evt.clientY > yLimit) {
192
- return;
193
- }
194
- if (this._isResizingTop()) {
195
- evt.stopPropagation();
196
- const distanceMouseMoved = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
197
- this._expandTop(distanceMouseMoved);
198
- this._mouseStartPointY = evt.clientY;
199
- }
200
- };
201
- this._onTopHandlePointerUp = (evt) => {
202
- if (this._isResizingTop()) {
203
- this.y = parseFloat(this.element.style.top.replace("px", ""));
204
- this.height = parseFloat(this.element.style.height.replace("px", ""));
205
- this._ownerCanvas.hostCanvas.removeEventListener("pointerup", this._onTopHandlePointerUp);
206
- this._ownerCanvas.hostCanvas.removeEventListener("pointermove", this._onTopHandlePointerMove);
207
- this._cleanUpResizing(evt);
208
- }
209
- };
210
- this._onTopRightHandlePointerDown = (evt) => {
211
- if (this.isCollapsed) {
212
- return;
213
- }
214
- this._initResizing(evt);
215
- this._resizingDirection = ResizingDirection.TopRight;
216
- this._ownerCanvas.hostCanvas.addEventListener("pointerup", this._onTopRightHandlePointerUp);
217
- this._ownerCanvas.hostCanvas.addEventListener("pointermove", this._onTopRightHandlePointerMove);
218
- };
219
- this._onTopRightHandlePointerMove = (evt) => {
220
- const topSlack = (this.element.offsetHeight - this._minFrameHeight) * this._ownerCanvas.zoom;
221
- const yLimit = this._mouseStartPointY + topSlack;
222
- const rightSlack = (this.element.offsetWidth - this._minFrameWidth) * this._ownerCanvas.zoom;
223
- const xLimit = this._mouseStartPointX - rightSlack;
224
- this._moveTopRightHandle(evt, xLimit, yLimit);
225
- };
226
- this._moveTopRightHandle = (evt, xLimit, yLimit) => {
227
- if (!(this._isResizingTop() && this._isResizingRight()) || this._mouseStartPointX === null || this._mouseStartPointY === null) {
228
- return;
229
- }
230
- if (this._isResizingRight() && this._isResizingTop()) {
231
- evt.stopPropagation();
232
- if (evt.clientY < yLimit && evt.clientX > xLimit) {
233
- // able to move in X and Y
234
- const distanceMouseMovedX = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
235
- this._expandRight(distanceMouseMovedX, evt.clientX);
236
- this._mouseStartPointX = evt.clientX;
237
- const distanceMouseMovedY = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
238
- this._expandTop(distanceMouseMovedY);
239
- this._mouseStartPointY = evt.clientY;
240
- }
241
- else if (evt.clientY > yLimit && evt.clientX > xLimit) {
242
- // able to move in X but not Y
243
- const distanceMouseMovedX = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
244
- this._expandRight(distanceMouseMovedX, evt.clientX);
245
- this._mouseStartPointX = evt.clientX;
246
- }
247
- else if (evt.clientY < yLimit && evt.clientX < xLimit) {
248
- // able to move in Y but not X
249
- const distanceMouseMovedY = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
250
- this._expandTop(distanceMouseMovedY);
251
- this._mouseStartPointY = evt.clientY;
252
- }
253
- }
254
- };
255
- this._onTopRightHandlePointerUp = (evt) => {
256
- evt.stopPropagation();
257
- if (this._resizingDirection === ResizingDirection.TopRight) {
258
- this.y = parseFloat(this.element.style.top.replace("px", ""));
259
- this.height = parseFloat(this.element.style.height.replace("px", ""));
260
- this.width = parseFloat(this.element.style.width.replace("px", ""));
261
- this._ownerCanvas.hostCanvas.removeEventListener("pointerup", this._onTopRightHandlePointerUp);
262
- this._ownerCanvas.hostCanvas.removeEventListener("pointermove", this._onTopRightHandlePointerMove);
263
- this._cleanUpResizing(evt);
264
- }
265
- };
266
- this._onBottomRightHandlePointerDown = (evt) => {
267
- if (this.isCollapsed) {
268
- return;
147
+ return true;
148
+ }
149
+ return false;
150
+ }
151
+ _removePortFromExposedWithLink(nodeLink, exposedPorts) {
152
+ const aPort = exposedPorts.findIndex((nodePort) => nodePort === nodeLink.portA);
153
+ const bPort = exposedPorts.findIndex((nodePort) => nodePort === nodeLink.portB);
154
+ if (aPort >= 0) {
155
+ if (!nodeLink.portA.exposedOnFrame) {
156
+ exposedPorts.splice(aPort, 1);
157
+ nodeLink.portA.exposedPortPosition = -1;
158
+ return true;
269
159
  }
270
- this._initResizing(evt);
271
- this._resizingDirection = ResizingDirection.BottomRight;
272
- this._ownerCanvas.hostCanvas.addEventListener("pointerup", this._onBottomRightHandlePointerUp);
273
- this._ownerCanvas.hostCanvas.addEventListener("pointermove", this._onBottomRightHandlePointerMove);
274
- };
275
- this._onBottomRightHandlePointerMove = (evt) => {
276
- const bottomSlack = (this.element.offsetHeight - this._minFrameHeight) * this._ownerCanvas.zoom;
277
- const yLimit = this._mouseStartPointY - bottomSlack;
278
- const rightSlack = (this.element.offsetWidth - this._minFrameWidth) * this._ownerCanvas.zoom;
279
- const xLimit = this._mouseStartPointX - rightSlack;
280
- this._moveBottomRightHandle(evt, xLimit, yLimit);
281
- };
282
- this._moveBottomRightHandle = (evt, xLimit, yLimit) => {
283
- if (!(this._isResizingBottom() && this._isResizingRight()) || this._mouseStartPointX === null || this._mouseStartPointY === null) {
284
- return;
160
+ }
161
+ else if (bPort >= 0) {
162
+ if (nodeLink.portB && !nodeLink.portB.exposedOnFrame) {
163
+ exposedPorts.splice(bPort, 1);
164
+ nodeLink.portB.exposedPortPosition = -1;
165
+ return true;
285
166
  }
286
- if (this._isResizingRight() && this._isResizingBottom()) {
287
- evt.stopPropagation();
288
- if (evt.clientY > yLimit && evt.clientX > xLimit) {
289
- // able to move in X and Y
290
- const distanceMouseMovedX = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
291
- this._expandRight(distanceMouseMovedX, evt.clientX);
292
- this._mouseStartPointX = evt.clientX;
293
- const distanceMouseMovedY = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
294
- this._expandBottom(distanceMouseMovedY);
295
- this._mouseStartPointY = evt.clientY;
296
- }
297
- else if (evt.clientY < yLimit && evt.clientX > xLimit) {
298
- // able to move in X but not Y
299
- const distanceMouseMovedX = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
300
- this._expandRight(distanceMouseMovedX, evt.clientX);
301
- this._mouseStartPointX = evt.clientX;
302
- }
303
- else if (evt.clientY > yLimit && evt.clientX < xLimit) {
304
- // able to move in Y but not X
305
- const distanceMouseMovedY = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
306
- this._expandBottom(distanceMouseMovedY);
307
- this._mouseStartPointY = evt.clientY;
167
+ }
168
+ return false;
169
+ }
170
+ _createInputPorts(port, node) {
171
+ if (port.portData.isConnected) {
172
+ let portAdded = false;
173
+ for (const link of node.links) {
174
+ if (link.portB === port && this.nodes.indexOf(link.nodeA) === -1) {
175
+ this._createInputPort(port, node);
176
+ link.isVisible = true;
177
+ portAdded = true;
178
+ const onLinkDisposedObserver = link.onDisposedObservable.add((nodeLink) => {
179
+ if (this._removePortFromExposedWithLink(nodeLink, this._exposedInPorts)) {
180
+ this.redrawFramePorts();
181
+ }
182
+ });
183
+ this._onNodeLinkDisposedObservers.push(onLinkDisposedObserver);
308
184
  }
309
185
  }
310
- };
311
- this._onBottomRightHandlePointerUp = (evt) => {
312
- if (this._resizingDirection === ResizingDirection.BottomRight) {
313
- this.height = parseFloat(this.element.style.height.replace("px", ""));
314
- this.width = parseFloat(this.element.style.width.replace("px", ""));
315
- this._ownerCanvas.hostCanvas.removeEventListener("pointerup", this._onBottomRightHandlePointerUp);
316
- this._ownerCanvas.hostCanvas.removeEventListener("pointermove", this._onBottomRightHandlePointerMove);
317
- this._cleanUpResizing(evt);
318
- }
319
- };
320
- //@ts-ignore
321
- this._onBottomLeftHandlePointerDown = (evt) => {
322
- if (this.isCollapsed) {
323
- return;
324
- }
325
- this._initResizing(evt);
326
- this._resizingDirection = ResizingDirection.BottomLeft;
327
- this._mouseXLimit = evt.clientX + this.width - this._minFrameWidth;
328
- this._ownerCanvas.hostCanvas.addEventListener("pointerup", this._onBottomLeftHandlePointerUp);
329
- this._ownerCanvas.hostCanvas.addEventListener("pointermove", this._onBottomLeftHandlePointerMove);
330
- };
331
- this._onBottomLeftHandlePointerMove = (evt) => {
332
- const bottomSlack = (this.element.offsetHeight - this._minFrameHeight) * this._ownerCanvas.zoom;
333
- const yLimit = this._mouseStartPointY - bottomSlack;
334
- const leftSlack = (this.element.offsetWidth - this._minFrameWidth) * this._ownerCanvas.zoom;
335
- const xLimit = this._mouseStartPointX + leftSlack;
336
- this._moveBottomLeftHandle(evt, xLimit, yLimit);
337
- };
338
- this._moveBottomLeftHandle = (evt, xLimit, yLimit) => {
339
- if (!(this._isResizingBottom() && this._isResizingLeft()) || this._mouseStartPointX === null || this._mouseStartPointY === null) {
340
- return;
341
- }
342
- if (this._isResizingLeft() && this._isResizingBottom()) {
343
- evt.stopPropagation();
344
- if (evt.clientY > yLimit && evt.clientX < xLimit) {
345
- // able to move in X and Y
346
- const distanceMouseMovedX = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
347
- this._expandLeft(distanceMouseMovedX);
348
- this._mouseStartPointX = evt.clientX;
349
- const distanceMouseMovedY = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
350
- this._expandBottom(distanceMouseMovedY);
351
- this._mouseStartPointY = evt.clientY;
352
- }
353
- else if (evt.clientY < yLimit && evt.clientX < xLimit) {
354
- // able to move in X but not Y
355
- const distanceMouseMovedX = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
356
- this._expandLeft(distanceMouseMovedX);
357
- this._mouseStartPointX = evt.clientX;
186
+ if (portAdded)
187
+ return true;
188
+ }
189
+ else if (port.exposedOnFrame) {
190
+ this._createInputPort(port, node);
191
+ return true;
192
+ }
193
+ return false;
194
+ }
195
+ _createOutputPorts(port, node) {
196
+ if (port.portData.hasEndpoints) {
197
+ let portAdded = false;
198
+ for (const link of node.links) {
199
+ if (link.portA === port && this.nodes.indexOf(link.nodeB) === -1) {
200
+ let localPort;
201
+ if (!portAdded) {
202
+ portAdded = true;
203
+ localPort = FrameNodePort.CreateFrameNodePortElement(port.portData, link.nodeA, this._outputPortContainer, null, this._ownerCanvas.stateManager, false, GraphFrame._FramePortCounter++, this.id);
204
+ this._frameOutPorts.push(localPort);
205
+ link.isVisible = true;
206
+ const onLinkDisposedObserver = link.onDisposedObservable.add((nodeLink) => {
207
+ if (this._removePortFromExposedWithLink(nodeLink, this._exposedOutPorts)) {
208
+ this.redrawFramePorts();
209
+ }
210
+ });
211
+ this._onNodeLinkDisposedObservers.push(onLinkDisposedObserver);
212
+ }
213
+ else if (this.nodes.indexOf(link.nodeB) === -1) {
214
+ link.isVisible = true;
215
+ localPort = this.ports.filter((p) => p.portData === port.portData)[0];
216
+ }
217
+ else {
218
+ localPort = this.ports.filter((p) => p.portData === port.portData)[0];
219
+ }
220
+ port.delegatedPort = localPort;
221
+ this._controlledPorts.push(port);
358
222
  }
359
- else if (evt.clientY > yLimit && evt.clientX > xLimit) {
360
- // able to move in Y but not X
361
- const distanceMouseMovedY = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
362
- this._expandBottom(distanceMouseMovedY);
363
- this._mouseStartPointY = evt.clientY;
223
+ else if (port.exposedPortPosition >= 0 && !portAdded) {
224
+ const localPort = FrameNodePort.CreateFrameNodePortElement(port.portData, node, this._outputPortContainer, null, this._ownerCanvas.stateManager, false, GraphFrame._FramePortCounter++, this.id);
225
+ this._frameOutPorts.push(localPort);
226
+ port.delegatedPort = localPort;
227
+ this._controlledPorts.push(port);
228
+ portAdded = true;
364
229
  }
365
230
  }
366
- };
367
- this._onBottomLeftHandlePointerUp = (evt) => {
368
- evt.stopPropagation();
369
- if (this._resizingDirection === ResizingDirection.BottomLeft) {
370
- this.height = parseFloat(this.element.style.height.replace("px", ""));
371
- this.x = parseFloat(this.element.style.left.replace("px", ""));
372
- this.width = parseFloat(this.element.style.width.replace("px", ""));
373
- this._ownerCanvas.hostCanvas.removeEventListener("pointerup", this._onBottomLeftHandlePointerUp);
374
- this._ownerCanvas.hostCanvas.removeEventListener("pointermove", this._onBottomLeftHandlePointerMove);
375
- this._cleanUpResizing(evt);
231
+ if (portAdded)
232
+ return true;
233
+ }
234
+ else if (port.exposedOnFrame) {
235
+ const localPort = FrameNodePort.CreateFrameNodePortElement(port.portData, node, this._outputPortContainer, null, this._ownerCanvas.stateManager, false, GraphFrame._FramePortCounter++, this.id);
236
+ this._frameOutPorts.push(localPort);
237
+ port.delegatedPort = localPort;
238
+ this._controlledPorts.push(port);
239
+ return true;
240
+ }
241
+ return false;
242
+ }
243
+ redrawFramePorts() {
244
+ if (!this.isCollapsed) {
245
+ return;
246
+ }
247
+ this._outputPortContainer.innerHTML = "";
248
+ this._inputPortContainer.innerHTML = "";
249
+ this.ports.forEach((framePort) => {
250
+ framePort.dispose();
251
+ });
252
+ this._controlledPorts.forEach((port) => {
253
+ port.delegatedPort = null;
254
+ port.refresh();
255
+ });
256
+ this._frameInPorts = [];
257
+ this._frameOutPorts = [];
258
+ this._controlledPorts = [];
259
+ this._createFramePorts();
260
+ this._markFramePortPositions();
261
+ this.ports.forEach((framePort) => framePort.node._refreshLinks());
262
+ }
263
+ set isCollapsed(value) {
264
+ if (this._isCollapsed === value) {
265
+ return;
266
+ }
267
+ this._isCollapsed = value;
268
+ this._ownerCanvas._frameIsMoving = true;
269
+ // Need to delegate the outside ports to the frame
270
+ if (value) {
271
+ this.element.classList.add(styles.collapsed);
272
+ this.element.classList.remove(styles.expanded);
273
+ this._headerElement.classList.add(styles.collapsedHeader);
274
+ this._moveFrame((this.width - this._collapsedWidth) / 2, 0);
275
+ this._createFramePorts();
276
+ this._markFramePortPositions();
277
+ }
278
+ else {
279
+ this.element.classList.add(styles.expanded);
280
+ this.element.classList.remove(styles.collapsed);
281
+ this._headerElement.classList.remove(styles.collapsedHeader);
282
+ this._outputPortContainer.innerHTML = "";
283
+ this._inputPortContainer.innerHTML = "";
284
+ this._frameInPorts.forEach((p) => {
285
+ p.dispose();
286
+ });
287
+ this._frameOutPorts.forEach((p) => {
288
+ p.dispose();
289
+ });
290
+ this._controlledPorts.forEach((port) => {
291
+ port.delegatedPort = null;
292
+ port.refresh();
293
+ });
294
+ this._frameInPorts = [];
295
+ this._frameOutPorts = [];
296
+ this._controlledPorts = [];
297
+ this._onNodeLinkDisposedObservers = [];
298
+ for (const node of this._nodes) {
299
+ node.isVisible = true;
300
+ }
301
+ this._moveFrame(-(this.width - this._collapsedWidth) / 2, 0);
302
+ }
303
+ this.cleanAccumulation();
304
+ this._ownerCanvas._frameIsMoving = false;
305
+ // UI
306
+ if (this._isCollapsed) {
307
+ this._headerCollapseElement.innerHTML = this._expandSVG;
308
+ this._headerCollapseElement.title = "Expand";
309
+ }
310
+ else {
311
+ this._headerCollapseElement.innerHTML = this._collapseSVG;
312
+ this._headerCollapseElement.title = "Collapse";
313
+ }
314
+ this.onExpandStateChanged.notifyObservers(this);
315
+ }
316
+ get nodes() {
317
+ return this._nodes;
318
+ }
319
+ get ports() {
320
+ return this._frameInPorts.concat(this._frameOutPorts);
321
+ }
322
+ get name() {
323
+ return this._name;
324
+ }
325
+ set name(value) {
326
+ this._name = value;
327
+ this._headerTextElement.innerHTML = value;
328
+ }
329
+ get color() {
330
+ return this._color;
331
+ }
332
+ set color(value) {
333
+ this._color = value;
334
+ this._headerElement.style.background = `rgba(${value.r * 255}, ${value.g * 255}, ${value.b * 255}, 1)`;
335
+ this._headerElement.style.borderColor = `rgba(${value.r * 255}, ${value.g * 255}, ${value.b * 255}, 1)`;
336
+ this.element.style.background = `rgba(${value.r * 255}, ${value.g * 255}, ${value.b * 255}, 0.7)`;
337
+ }
338
+ get x() {
339
+ return this._x;
340
+ }
341
+ set x(value) {
342
+ if (this._x === value) {
343
+ return;
344
+ }
345
+ this._x = value;
346
+ this._gridAlignedX = this._ownerCanvas.getGridPosition(value);
347
+ this.element.style.left = `${this._gridAlignedX}px`;
348
+ }
349
+ get y() {
350
+ return this._y;
351
+ }
352
+ set y(value) {
353
+ if (this._y === value) {
354
+ return;
355
+ }
356
+ this._y = value;
357
+ this._gridAlignedY = this._ownerCanvas.getGridPosition(value);
358
+ this.element.style.top = `${this._gridAlignedY}px`;
359
+ }
360
+ get width() {
361
+ return this._width;
362
+ }
363
+ set width(value) {
364
+ if (this._width === value) {
365
+ return;
366
+ }
367
+ const viableWidth = value > this._minFrameWidth ? value : this._minFrameWidth;
368
+ this._width = viableWidth;
369
+ const gridAlignedRight = this._ownerCanvas.getGridPositionCeil(viableWidth + this._gridAlignedX);
370
+ this.element.style.width = `${gridAlignedRight - this._gridAlignedX}px`;
371
+ }
372
+ get height() {
373
+ return this._height;
374
+ }
375
+ set height(value) {
376
+ if (this._height === value) {
377
+ return;
378
+ }
379
+ this._height = value;
380
+ const gridAlignedBottom = this._ownerCanvas.getGridPositionCeil(value + this._gridAlignedY);
381
+ this.element.style.height = `${gridAlignedBottom - this._gridAlignedY}px`;
382
+ }
383
+ get comments() {
384
+ return this._comments;
385
+ }
386
+ set comments(comments) {
387
+ if (comments && !this._comments && comments.length > 0) {
388
+ this.element.style.gridTemplateRows = "40px min-content 1fr";
389
+ this._borderElement.style.gridRow = "1 / span 3";
390
+ this._portContainer.style.gridRow = "3";
391
+ this._commentsElement.classList.add("has-comments");
392
+ }
393
+ else if (!comments) {
394
+ this.element.style.gridTemplateRows = "40px calc(100% - 40px)";
395
+ this._borderElement.style.gridRow = "1 / span 2";
396
+ this._portContainer.style.gridRow = "2";
397
+ this._commentsElement.classList.remove("has-comments");
398
+ }
399
+ if (comments === "" || (comments && comments.length >= 0)) {
400
+ this._commentsElement.children[0].innerText = comments;
401
+ }
402
+ this.height = this._borderElement.offsetHeight;
403
+ this._comments = comments;
404
+ this._updateMinHeightWithComments();
405
+ }
406
+ constructor(candidate, canvas, doNotCaptureNodes = false) {
407
+ this._collapsedWidth = 200;
408
+ this._x = 0;
409
+ this._y = 0;
410
+ this._gridAlignedX = 0;
411
+ this._gridAlignedY = 0;
412
+ this._nodes = [];
413
+ this._mouseStartPointX = null;
414
+ this._mouseStartPointY = null;
415
+ this._onNodeLinkDisposedObservers = [];
416
+ this._isCollapsed = false;
417
+ this._frameInPorts = [];
418
+ this._frameOutPorts = [];
419
+ this._controlledPorts = []; // Ports on Nodes that are shown on outside of frame
420
+ this._exposedInPorts = [];
421
+ this._exposedOutPorts = [];
422
+ this._minFrameHeight = 40;
423
+ this._minFrameWidth = 220;
424
+ this.onExpandStateChanged = new Observable();
425
+ this._closeSVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><g id="Layer_2" data-name="Layer 2"><path d="M16,15l5.85,5.84-1,1L15,15.93,9.15,21.78l-1-1L14,15,8.19,9.12l1-1L15,14l5.84-5.84,1,1Z"/></g></svg>`;
426
+ this._expandSVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><g id="Layer_2" data-name="Layer 2"><path d="M22.31,7.69V22.31H7.69V7.69ZM21.19,8.81H8.81V21.19H21.19Zm-6.75,6.75H11.06V14.44h3.38V11.06h1.12v3.38h3.38v1.12H15.56v3.38H14.44Z"/></g></svg>`;
427
+ this._collapseSVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><g id="Layer_2" data-name="Layer 2"><path d="M22.31,7.69V22.31H7.69V7.69ZM21.19,8.81H8.81V21.19H21.19Zm-2.25,6.75H11.06V14.44h7.88Z"/></g></svg>`;
428
+ this._initResizing = (evt) => {
429
+ evt.stopPropagation();
430
+ this._mouseStartPointX = evt.clientX;
431
+ this._mouseStartPointY = evt.clientY;
432
+ this._frameIsResizing = true;
433
+ };
434
+ this._cleanUpResizing = (evt) => {
435
+ evt.stopPropagation();
436
+ this._frameIsResizing = false;
437
+ this._resizingDirection = null;
438
+ this._mouseStartPointX = null;
439
+ this._mouseStartPointY = null;
440
+ this._mouseXLimit = null;
441
+ this.refresh();
442
+ };
443
+ this._updateMinHeightWithComments = () => {
444
+ if (this.comments && this.comments.length > 0) {
445
+ const minFrameHeightWithComments = this._commentsElement.offsetHeight + 40;
446
+ this._minFrameHeight = minFrameHeightWithComments;
376
447
  }
377
448
  };
378
- //@ts-ignore
379
- this._onTopLeftHandlePointerDown = (evt) => {
449
+ this._onRightHandlePointerDown = (evt) => {
380
450
  if (this.isCollapsed) {
381
451
  return;
382
452
  }
383
453
  this._initResizing(evt);
384
- this._resizingDirection = ResizingDirection.TopLeft;
385
- this._mouseXLimit = evt.clientX + this.width - this._minFrameWidth;
386
- this._ownerCanvas.hostCanvas.addEventListener("pointerup", this._onTopLeftHandlePointerUp);
387
- this._ownerCanvas.hostCanvas.addEventListener("pointermove", this._onTopLeftHandlePointerMove);
454
+ this._resizingDirection = ResizingDirection.Right;
455
+ this._mouseXLimit = evt.clientX - (this.width - this._minFrameWidth);
456
+ this._ownerCanvas.hostCanvas.addEventListener("pointerup", this._onRightHandlePointerUp);
457
+ this._ownerCanvas.hostCanvas.addEventListener("pointermove", this._onRightHandlePointerMove);
388
458
  };
389
- this._onTopLeftHandlePointerMove = (evt) => {
390
- const topSlack = (this.element.offsetHeight - this._minFrameHeight) * this._ownerCanvas.zoom;
391
- const yLimit = this._mouseStartPointY + topSlack;
392
- const leftSlack = (this.element.offsetWidth - this._minFrameWidth) * this._ownerCanvas.zoom;
393
- const xLimit = this._mouseStartPointX + leftSlack;
394
- this._moveTopLeftHandle(evt, xLimit, yLimit);
459
+ this._onRightHandlePointerMove = (evt) => {
460
+ const slack = (this.element.offsetWidth - this._minFrameWidth) * this._ownerCanvas.zoom;
461
+ const xLimit = this._mouseStartPointX - slack;
462
+ this._moveRightHandle(evt, xLimit);
395
463
  };
396
- this._moveTopLeftHandle = (evt, xLimit, yLimit) => {
397
- if (!(this._isResizingTop() && this._isResizingLeft()) || this._mouseStartPointX === null || this._mouseStartPointY === null) {
398
- return;
399
- }
400
- if (this._isResizingLeft() && this._isResizingTop()) {
401
- evt.stopPropagation();
402
- if (evt.clientY < yLimit && evt.clientX < xLimit) {
403
- // able to move in X and Y
404
- const distanceMouseMovedX = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
405
- this._expandLeft(distanceMouseMovedX);
406
- this._mouseStartPointX = evt.clientX;
407
- const distanceMouseMovedY = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
464
+ this._moveRightHandle = (evt, xLimit) => {
465
+ // tslint:disable-next-line: no-this-assignment
466
+ if (this._mouseXLimit) {
467
+ if (!this._isResizingRight() || this._mouseStartPointX === null || this._mouseStartPointY === null || evt.clientX < xLimit) {
468
+ return;
469
+ }
470
+ if (this._isResizingRight()) {
471
+ evt.stopPropagation();
472
+ const distanceMouseMoved = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
473
+ this._expandRight(distanceMouseMoved, evt.clientX);
474
+ this._mouseStartPointX = evt.clientX;
475
+ }
476
+ }
477
+ };
478
+ this._onRightHandlePointerUp = (evt) => {
479
+ if (this._isResizingRight()) {
480
+ this.width = parseFloat(this.element.style.width.replace("px", ""));
481
+ this._ownerCanvas.hostCanvas.removeEventListener("pointerup", this._onRightHandlePointerUp);
482
+ this._ownerCanvas.hostCanvas.removeEventListener("pointermove", this._onRightHandlePointerMove);
483
+ this._cleanUpResizing(evt);
484
+ }
485
+ };
486
+ this._onBottomHandlePointerDown = (evt) => {
487
+ if (this.isCollapsed) {
488
+ return;
489
+ }
490
+ this._initResizing(evt);
491
+ this._resizingDirection = ResizingDirection.Bottom;
492
+ this._ownerCanvas.hostCanvas.addEventListener("pointermove", this._onBottomHandlePointerMove);
493
+ this._ownerCanvas.hostCanvas.addEventListener("pointerup", this._onBottomHandlePointerUp);
494
+ };
495
+ this._onBottomHandlePointerMove = (evt) => {
496
+ const slack = (this.element.offsetHeight - this._minFrameHeight) * this._ownerCanvas.zoom;
497
+ const yLimit = this._mouseStartPointY - slack;
498
+ this._moveBottomHandle(evt, yLimit);
499
+ };
500
+ this._moveBottomHandle = (evt, yLimit) => {
501
+ if (this._resizingDirection !== ResizingDirection.Bottom || this._mouseStartPointX === null || this._mouseStartPointY === null || evt.clientY < yLimit) {
502
+ return;
503
+ }
504
+ if (this._resizingDirection === ResizingDirection.Bottom) {
505
+ evt.stopPropagation();
506
+ const distanceMouseMoved = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
507
+ this._expandBottom(distanceMouseMoved);
508
+ this._mouseStartPointY = evt.clientY;
509
+ }
510
+ };
511
+ this._onBottomHandlePointerUp = (evt) => {
512
+ if (this._resizingDirection === ResizingDirection.Bottom) {
513
+ this.height = parseFloat(this.element.style.height.replace("px", ""));
514
+ this._ownerCanvas.hostCanvas.removeEventListener("pointermove", this._onBottomHandlePointerMove);
515
+ this._ownerCanvas.hostCanvas.removeEventListener("pointerup", this._onBottomHandlePointerUp);
516
+ this._cleanUpResizing(evt);
517
+ }
518
+ };
519
+ this._onLeftHandlePointerDown = (evt) => {
520
+ if (this.isCollapsed) {
521
+ return;
522
+ }
523
+ this._initResizing(evt);
524
+ this._resizingDirection = ResizingDirection.Left;
525
+ this._mouseXLimit = evt.clientX + this.width - this._minFrameWidth;
526
+ this._ownerCanvas.hostCanvas.addEventListener("pointerup", this._onLeftHandlePointerUp);
527
+ this._ownerCanvas.hostCanvas.addEventListener("pointermove", this._onLeftHandlePointerMove);
528
+ };
529
+ this._onLeftHandlePointerMove = (evt) => {
530
+ const slack = (this.element.offsetWidth - this._minFrameWidth) * this._ownerCanvas.zoom;
531
+ const xLimit = this._mouseStartPointX + slack;
532
+ this._moveLeftHandle(evt, xLimit);
533
+ };
534
+ this._moveLeftHandle = (evt, xLimit) => {
535
+ if (this._mouseXLimit) {
536
+ if (this._resizingDirection !== ResizingDirection.Left || this._mouseStartPointX === null || this._mouseStartPointY === null || evt.clientX > xLimit) {
537
+ return;
538
+ }
539
+ if (this._resizingDirection === ResizingDirection.Left) {
540
+ evt.stopPropagation();
541
+ const distanceMouseMoved = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
542
+ this._expandLeft(distanceMouseMoved);
543
+ this._mouseStartPointX = evt.clientX;
544
+ }
545
+ }
546
+ };
547
+ this._onLeftHandlePointerUp = (evt) => {
548
+ if (this._resizingDirection === ResizingDirection.Left) {
549
+ this.x = parseFloat(this.element.style.left.replace("px", ""));
550
+ this.width = parseFloat(this.element.style.width.replace("px", ""));
551
+ this._ownerCanvas.hostCanvas.removeEventListener("pointerup", this._onLeftHandlePointerUp);
552
+ this._ownerCanvas.hostCanvas.removeEventListener("pointermove", this._onLeftHandlePointerMove);
553
+ this._cleanUpResizing(evt);
554
+ }
555
+ };
556
+ this._onTopHandlePointerDown = (evt) => {
557
+ if (this.isCollapsed) {
558
+ return;
559
+ }
560
+ this._initResizing(evt);
561
+ this._resizingDirection = ResizingDirection.Top;
562
+ this._ownerCanvas.hostCanvas.addEventListener("pointerup", this._onTopHandlePointerUp);
563
+ this._ownerCanvas.hostCanvas.addEventListener("pointermove", this._onTopHandlePointerMove);
564
+ };
565
+ this._onTopHandlePointerMove = (evt) => {
566
+ const slack = (this.element.offsetHeight - this._minFrameHeight) * this._ownerCanvas.zoom;
567
+ const yLimit = this._mouseStartPointY + slack;
568
+ this._moveTopHandle(evt, yLimit);
569
+ };
570
+ this._moveTopHandle = (evt, yLimit) => {
571
+ if (!this._isResizingTop() || this._mouseStartPointX === null || this._mouseStartPointY === null || evt.clientY > yLimit) {
572
+ return;
573
+ }
574
+ if (this._isResizingTop()) {
575
+ evt.stopPropagation();
576
+ const distanceMouseMoved = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
577
+ this._expandTop(distanceMouseMoved);
578
+ this._mouseStartPointY = evt.clientY;
579
+ }
580
+ };
581
+ this._onTopHandlePointerUp = (evt) => {
582
+ if (this._isResizingTop()) {
583
+ this.y = parseFloat(this.element.style.top.replace("px", ""));
584
+ this.height = parseFloat(this.element.style.height.replace("px", ""));
585
+ this._ownerCanvas.hostCanvas.removeEventListener("pointerup", this._onTopHandlePointerUp);
586
+ this._ownerCanvas.hostCanvas.removeEventListener("pointermove", this._onTopHandlePointerMove);
587
+ this._cleanUpResizing(evt);
588
+ }
589
+ };
590
+ this._onTopRightHandlePointerDown = (evt) => {
591
+ if (this.isCollapsed) {
592
+ return;
593
+ }
594
+ this._initResizing(evt);
595
+ this._resizingDirection = ResizingDirection.TopRight;
596
+ this._ownerCanvas.hostCanvas.addEventListener("pointerup", this._onTopRightHandlePointerUp);
597
+ this._ownerCanvas.hostCanvas.addEventListener("pointermove", this._onTopRightHandlePointerMove);
598
+ };
599
+ this._onTopRightHandlePointerMove = (evt) => {
600
+ const topSlack = (this.element.offsetHeight - this._minFrameHeight) * this._ownerCanvas.zoom;
601
+ const yLimit = this._mouseStartPointY + topSlack;
602
+ const rightSlack = (this.element.offsetWidth - this._minFrameWidth) * this._ownerCanvas.zoom;
603
+ const xLimit = this._mouseStartPointX - rightSlack;
604
+ this._moveTopRightHandle(evt, xLimit, yLimit);
605
+ };
606
+ this._moveTopRightHandle = (evt, xLimit, yLimit) => {
607
+ if (!(this._isResizingTop() && this._isResizingRight()) || this._mouseStartPointX === null || this._mouseStartPointY === null) {
608
+ return;
609
+ }
610
+ if (this._isResizingRight() && this._isResizingTop()) {
611
+ evt.stopPropagation();
612
+ if (evt.clientY < yLimit && evt.clientX > xLimit) {
613
+ // able to move in X and Y
614
+ const distanceMouseMovedX = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
615
+ this._expandRight(distanceMouseMovedX, evt.clientX);
616
+ this._mouseStartPointX = evt.clientX;
617
+ const distanceMouseMovedY = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
408
618
  this._expandTop(distanceMouseMovedY);
409
619
  this._mouseStartPointY = evt.clientY;
410
620
  }
411
- else if (evt.clientY > yLimit && evt.clientX < xLimit) {
621
+ else if (evt.clientY > yLimit && evt.clientX > xLimit) {
412
622
  // able to move in X but not Y
413
623
  const distanceMouseMovedX = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
414
- this._expandLeft(distanceMouseMovedX);
624
+ this._expandRight(distanceMouseMovedX, evt.clientX);
415
625
  this._mouseStartPointX = evt.clientX;
416
626
  }
417
- else if (evt.clientY < yLimit && evt.clientX > xLimit) {
627
+ else if (evt.clientY < yLimit && evt.clientX < xLimit) {
418
628
  // able to move in Y but not X
419
629
  const distanceMouseMovedY = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
420
630
  this._expandTop(distanceMouseMovedY);
@@ -422,546 +632,336 @@ export class GraphFrame {
422
632
  }
423
633
  }
424
634
  };
425
- this._onTopLeftHandlePointerUp = (evt) => {
635
+ this._onTopRightHandlePointerUp = (evt) => {
426
636
  evt.stopPropagation();
427
- if (this._resizingDirection === ResizingDirection.TopLeft) {
637
+ if (this._resizingDirection === ResizingDirection.TopRight) {
428
638
  this.y = parseFloat(this.element.style.top.replace("px", ""));
429
639
  this.height = parseFloat(this.element.style.height.replace("px", ""));
430
- this.x = parseFloat(this.element.style.left.replace("px", ""));
431
640
  this.width = parseFloat(this.element.style.width.replace("px", ""));
432
- this._ownerCanvas.hostCanvas.removeEventListener("pointerup", this._onTopLeftHandlePointerUp);
433
- this._ownerCanvas.hostCanvas.removeEventListener("pointermove", this._onTopLeftHandlePointerMove);
641
+ this._ownerCanvas.hostCanvas.removeEventListener("pointerup", this._onTopRightHandlePointerUp);
642
+ this._ownerCanvas.hostCanvas.removeEventListener("pointermove", this._onTopRightHandlePointerMove);
434
643
  this._cleanUpResizing(evt);
435
644
  }
436
645
  };
437
- this._id = GraphFrame._FrameCounter++;
438
- this._ownerCanvas = canvas;
439
- const root = canvas.frameContainer;
440
- this.element = root.ownerDocument.createElement("div");
441
- this.element.classList.add(commonStyles["frame-box"]);
442
- root.appendChild(this.element);
443
- this._headerElement = root.ownerDocument.createElement("div");
444
- this._headerElement.classList.add(styles["frame-box-header"]);
445
- this._headerElement.addEventListener("dblclick", () => {
446
- this.isCollapsed = !this.isCollapsed;
447
- });
448
- this.element.appendChild(this._headerElement);
449
- this._borderElement = root.ownerDocument.createElement("div");
450
- this._borderElement.classList.add(styles["frame-box-border"]);
451
- this.element.appendChild(this._borderElement);
452
- this.element.classList.add(styles.expanded);
453
- // add resizing side handles
454
- const rightHandle = root.ownerDocument.createElement("div");
455
- rightHandle.className = styles["right-handle"];
456
- this.element.appendChild(rightHandle);
457
- rightHandle.addEventListener("pointerdown", this._onRightHandlePointerDown);
458
- const leftHandle = root.ownerDocument.createElement("div");
459
- leftHandle.className = styles["left-handle"];
460
- this.element.appendChild(leftHandle);
461
- leftHandle.addEventListener("pointerdown", this._onLeftHandlePointerDown);
462
- const bottomHandle = root.ownerDocument.createElement("div");
463
- bottomHandle.className = styles["bottom-handle"];
464
- this.element.appendChild(bottomHandle);
465
- bottomHandle.addEventListener("pointerdown", this._onBottomHandlePointerDown);
466
- const topHandle = root.ownerDocument.createElement("div");
467
- topHandle.className = styles["top-handle"];
468
- this.element.appendChild(topHandle);
469
- topHandle.addEventListener("pointerdown", this._onTopHandlePointerDown);
470
- const topRightCornerHandle = root.ownerDocument.createElement("div");
471
- topRightCornerHandle.className = ClassNames({ "right-handle": true, "top-right-corner-handle": true }, styles);
472
- this.element.appendChild(topRightCornerHandle);
473
- topRightCornerHandle.addEventListener("pointerdown", this._onTopRightHandlePointerDown);
474
- const bottomRightCornerHandle = root.ownerDocument.createElement("div");
475
- bottomRightCornerHandle.className = ClassNames({ "right-handle": true, "bottom-right-corner-handle": true }, styles);
476
- this.element.appendChild(bottomRightCornerHandle);
477
- bottomRightCornerHandle.addEventListener("pointerdown", this._onBottomRightHandlePointerDown);
478
- const topLeftCornerHandle = root.ownerDocument.createElement("div");
479
- topLeftCornerHandle.className = ClassNames({ "left-handle": true, "top-left-corner-handle": true }, styles);
480
- this.element.appendChild(topLeftCornerHandle);
481
- topLeftCornerHandle.addEventListener("pointerdown", this._onTopLeftHandlePointerDown);
482
- const bottomLeftCornerHandle = root.ownerDocument.createElement("div");
483
- bottomLeftCornerHandle.className = ClassNames({ "left-handle": true, "bottom-left-corner-handle": true }, styles);
484
- this.element.appendChild(bottomLeftCornerHandle);
485
- bottomLeftCornerHandle.addEventListener("pointerdown", this._onBottomLeftHandlePointerDown);
486
- // add header elements
487
- this._headerTextElement = root.ownerDocument.createElement("div");
488
- this._headerTextElement.classList.add(styles["frame-box-header-title"]);
489
- this._headerElement.appendChild(this._headerTextElement);
490
- this._headerCollapseElement = root.ownerDocument.createElement("div");
491
- this._headerCollapseElement.classList.add(styles["frame-box-header-collapse"]);
492
- this._headerCollapseElement.classList.add(styles["frame-box-header-button"]);
493
- this._headerCollapseElement.title = "Collapse";
494
- this._headerCollapseElement.ondragstart = () => false;
495
- this._headerCollapseElement.addEventListener("pointerdown", (evt) => {
496
- this._headerCollapseElement.classList.add("down");
497
- evt.stopPropagation();
498
- });
499
- this._headerCollapseElement.addEventListener("pointerup", (evt) => {
500
- evt.stopPropagation();
501
- this._headerCollapseElement.classList.remove("down");
502
- this.isCollapsed = !this.isCollapsed;
503
- });
504
- this._headerCollapseElement.innerHTML = this._collapseSVG;
505
- this._headerElement.appendChild(this._headerCollapseElement);
506
- this._headerCloseElement = root.ownerDocument.createElement("div");
507
- this._headerCloseElement.classList.add(styles["frame-box-header-close"]);
508
- this._headerCloseElement.classList.add(styles["frame-box-header-button"]);
509
- this._headerCloseElement.title = "Close";
510
- this._headerCloseElement.ondragstart = () => false;
511
- this._headerCloseElement.addEventListener("pointerdown", (evt) => {
512
- evt.stopPropagation();
513
- });
514
- this._headerCloseElement.addEventListener("pointerup", (evt) => {
515
- evt.stopPropagation();
516
- this.dispose();
517
- });
518
- this._headerCloseElement.innerHTML = this._closeSVG;
519
- this._headerElement.appendChild(this._headerCloseElement);
520
- this._portContainer = root.ownerDocument.createElement("div");
521
- this._portContainer.classList.add(styles["port-container"]);
522
- this.element.appendChild(this._portContainer);
523
- this._outputPortContainer = root.ownerDocument.createElement("div");
524
- this._outputPortContainer.classList.add(commonStyles["outputsContainer"]);
525
- this._portContainer.appendChild(this._outputPortContainer);
526
- this._inputPortContainer = root.ownerDocument.createElement("div");
527
- this._inputPortContainer.classList.add(commonStyles["inputsContainer"]);
528
- this._portContainer.appendChild(this._inputPortContainer);
529
- this.name = "Frame";
530
- this.color = Color3.FromInts(72, 72, 72);
531
- if (candidate) {
532
- this.x = parseFloat(candidate.style.left.replace("px", ""));
533
- this.y = parseFloat(candidate.style.top.replace("px", ""));
534
- this.width = parseFloat(candidate.style.width.replace("px", ""));
535
- this.height = parseFloat(candidate.style.height.replace("px", ""));
536
- this.cleanAccumulation();
537
- }
538
- this._headerTextElement.addEventListener("pointerdown", (evt) => this._onDown(evt));
539
- this._headerTextElement.addEventListener("pointerup", (evt) => this._onUp(evt));
540
- this._headerTextElement.addEventListener("pointermove", (evt) => this._onMove(evt));
541
- this._onSelectionChangedObserver = canvas.stateManager.onSelectionChangedObservable.add(() => {
542
- if (this._ownerCanvas.selectedFrames.indexOf(this) !== -1) {
543
- this._borderElement.classList.add(styles["selected"]);
544
- }
545
- else {
546
- this._borderElement.classList.remove(styles["selected"]);
547
- }
548
- });
549
- canvas.stateManager.onSelectionBoxMoved.add((rect1) => {
550
- const rect2 = this.element.getBoundingClientRect();
551
- const overlap = !(rect1.right < rect2.left || rect1.left > rect2.right || rect1.bottom < rect2.top || rect1.top > rect2.bottom);
552
- if (overlap) {
553
- canvas.stateManager.onSelectionChangedObservable.notifyObservers({ selection: this, forceKeepSelection: true, marqueeSelection: true });
554
- }
555
- });
556
- this._onGraphNodeRemovalObserver = canvas.stateManager.onGraphNodeRemovalObservable.add((node) => {
557
- // remove node from this._nodes
558
- const index = this._nodes.indexOf(node);
559
- if (index === -1) {
646
+ this._onBottomRightHandlePointerDown = (evt) => {
647
+ if (this.isCollapsed) {
560
648
  return;
561
649
  }
562
- else {
563
- node.enclosingFrameId = -1;
564
- this._nodes.splice(index, 1);
565
- }
566
- });
567
- this._onExposePortOnFrameObserver = canvas.stateManager.onExposePortOnFrameObservable.add((node) => {
568
- if (this.nodes.indexOf(node) === -1) {
650
+ this._initResizing(evt);
651
+ this._resizingDirection = ResizingDirection.BottomRight;
652
+ this._ownerCanvas.hostCanvas.addEventListener("pointerup", this._onBottomRightHandlePointerUp);
653
+ this._ownerCanvas.hostCanvas.addEventListener("pointermove", this._onBottomRightHandlePointerMove);
654
+ };
655
+ this._onBottomRightHandlePointerMove = (evt) => {
656
+ const bottomSlack = (this.element.offsetHeight - this._minFrameHeight) * this._ownerCanvas.zoom;
657
+ const yLimit = this._mouseStartPointY - bottomSlack;
658
+ const rightSlack = (this.element.offsetWidth - this._minFrameWidth) * this._ownerCanvas.zoom;
659
+ const xLimit = this._mouseStartPointX - rightSlack;
660
+ this._moveBottomRightHandle(evt, xLimit, yLimit);
661
+ };
662
+ this._moveBottomRightHandle = (evt, xLimit, yLimit) => {
663
+ if (!(this._isResizingBottom() && this._isResizingRight()) || this._mouseStartPointX === null || this._mouseStartPointY === null) {
569
664
  return;
570
665
  }
571
- this.redrawFramePorts();
572
- });
573
- this._commentsElement = document.createElement("div");
574
- this._commentsElement.className = styles["frame-comments"];
575
- this._commentsElement.style.color = "white";
576
- this._commentsElement.style.fontSize = "16px";
577
- const commentSpan = document.createElement("span");
578
- commentSpan.className = styles["frame-comment-span"];
579
- this._commentsElement.appendChild(commentSpan);
580
- this.element.appendChild(this._commentsElement);
581
- // Get nodes
582
- if (!doNotCaptureNodes) {
583
- this.refresh();
584
- }
585
- }
586
- get id() {
587
- return this._id;
588
- }
589
- get isCollapsed() {
590
- return this._isCollapsed;
591
- }
592
- _createInputPort(port, node) {
593
- const localPort = FrameNodePort.CreateFrameNodePortElement(port.portData, node, this._inputPortContainer, null, this._ownerCanvas.stateManager, true, GraphFrame._FramePortCounter++, this.id);
594
- this._frameInPorts.push(localPort);
595
- port.delegatedPort = localPort;
596
- this._controlledPorts.push(port);
597
- port.exposedPortPosition = this._exposedInPorts.findIndex((nodePort) => nodePort === port);
598
- if (port.exposedPortPosition < 0) {
599
- this._exposedInPorts.push(port);
600
- port.exposedPortPosition = this._exposedInPorts.length - 1;
601
- }
602
- }
603
- // Mark ports with FramePortPosition for re-arrangement support
604
- _markFramePortPositions() {
605
- // mark FrameInPorts
606
- if (this._frameInPorts.length == 2) {
607
- this._frameInPorts[0].framePortPosition = FramePortPosition.Top;
608
- this._frameInPorts[1].framePortPosition = FramePortPosition.Bottom;
609
- }
610
- else {
611
- for (let i = 0; i < this._frameInPorts.length; i++) {
612
- const port = this._frameInPorts[i];
613
- if (i === 0) {
614
- port.framePortPosition = FramePortPosition.Top;
666
+ if (this._isResizingRight() && this._isResizingBottom()) {
667
+ evt.stopPropagation();
668
+ if (evt.clientY > yLimit && evt.clientX > xLimit) {
669
+ // able to move in X and Y
670
+ const distanceMouseMovedX = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
671
+ this._expandRight(distanceMouseMovedX, evt.clientX);
672
+ this._mouseStartPointX = evt.clientX;
673
+ const distanceMouseMovedY = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
674
+ this._expandBottom(distanceMouseMovedY);
675
+ this._mouseStartPointY = evt.clientY;
615
676
  }
616
- else if (i === this._frameInPorts.length - 1) {
617
- port.framePortPosition = FramePortPosition.Bottom;
677
+ else if (evt.clientY < yLimit && evt.clientX > xLimit) {
678
+ // able to move in X but not Y
679
+ const distanceMouseMovedX = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
680
+ this._expandRight(distanceMouseMovedX, evt.clientX);
681
+ this._mouseStartPointX = evt.clientX;
618
682
  }
619
- else {
620
- port.framePortPosition = FramePortPosition.Middle;
683
+ else if (evt.clientY > yLimit && evt.clientX < xLimit) {
684
+ // able to move in Y but not X
685
+ const distanceMouseMovedY = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
686
+ this._expandBottom(distanceMouseMovedY);
687
+ this._mouseStartPointY = evt.clientY;
621
688
  }
622
689
  }
623
- }
624
- // mark FrameOutPorts
625
- if (this._frameOutPorts.length == 2) {
626
- this._frameOutPorts[0].framePortPosition = FramePortPosition.Top;
627
- this._frameOutPorts[1].framePortPosition = FramePortPosition.Bottom;
628
- }
629
- else {
630
- for (let i = 0; i < this._frameOutPorts.length; i++) {
631
- const port = this._frameOutPorts[i];
632
- if (i === 0) {
633
- port.framePortPosition = FramePortPosition.Top;
634
- }
635
- else if (i === this._frameInPorts.length - 1) {
636
- port.framePortPosition = FramePortPosition.Bottom;
637
- }
638
- else {
639
- port.framePortPosition = FramePortPosition.Middle;
640
- }
690
+ };
691
+ this._onBottomRightHandlePointerUp = (evt) => {
692
+ if (this._resizingDirection === ResizingDirection.BottomRight) {
693
+ this.height = parseFloat(this.element.style.height.replace("px", ""));
694
+ this.width = parseFloat(this.element.style.width.replace("px", ""));
695
+ this._ownerCanvas.hostCanvas.removeEventListener("pointerup", this._onBottomRightHandlePointerUp);
696
+ this._ownerCanvas.hostCanvas.removeEventListener("pointermove", this._onBottomRightHandlePointerMove);
697
+ this._cleanUpResizing(evt);
641
698
  }
642
- }
643
- }
644
- _createFramePorts() {
645
- for (const node of this._nodes) {
646
- node.isVisible = false;
647
- }
648
- for (let i = 0; i < this._exposedOutPorts.length;) {
649
- // Output
650
- const port = this._exposedOutPorts[i];
651
- if (port) {
652
- if (port.node === null || port.node.enclosingFrameId != this.id) {
653
- if (this._removePortFromExposedWithNode(port, this._exposedOutPorts))
654
- continue;
655
- }
656
- else {
657
- if (!this._createOutputPorts(port, port.node) && this._removePortFromExposedWithNode(port, this._exposedOutPorts)) {
658
- continue;
659
- }
660
- }
699
+ };
700
+ //@ts-ignore
701
+ this._onBottomLeftHandlePointerDown = (evt) => {
702
+ if (this.isCollapsed) {
703
+ return;
661
704
  }
662
- ++i;
663
- }
664
- for (let i = 0; i < this._exposedInPorts.length;) {
665
- // Input
666
- const port = this._exposedInPorts[i];
667
- if (!port || port.node === null || port.node.enclosingFrameId != this.id) {
668
- if (this._removePortFromExposedWithNode(port, this._exposedInPorts)) {
669
- continue;
670
- }
705
+ this._initResizing(evt);
706
+ this._resizingDirection = ResizingDirection.BottomLeft;
707
+ this._mouseXLimit = evt.clientX + this.width - this._minFrameWidth;
708
+ this._ownerCanvas.hostCanvas.addEventListener("pointerup", this._onBottomLeftHandlePointerUp);
709
+ this._ownerCanvas.hostCanvas.addEventListener("pointermove", this._onBottomLeftHandlePointerMove);
710
+ };
711
+ this._onBottomLeftHandlePointerMove = (evt) => {
712
+ const bottomSlack = (this.element.offsetHeight - this._minFrameHeight) * this._ownerCanvas.zoom;
713
+ const yLimit = this._mouseStartPointY - bottomSlack;
714
+ const leftSlack = (this.element.offsetWidth - this._minFrameWidth) * this._ownerCanvas.zoom;
715
+ const xLimit = this._mouseStartPointX + leftSlack;
716
+ this._moveBottomLeftHandle(evt, xLimit, yLimit);
717
+ };
718
+ this._moveBottomLeftHandle = (evt, xLimit, yLimit) => {
719
+ if (!(this._isResizingBottom() && this._isResizingLeft()) || this._mouseStartPointX === null || this._mouseStartPointY === null) {
720
+ return;
671
721
  }
672
- else {
673
- if (!this._createInputPorts(port, port.node) && this._removePortFromExposedWithNode(port, this._exposedInPorts)) {
674
- continue;
722
+ if (this._isResizingLeft() && this._isResizingBottom()) {
723
+ evt.stopPropagation();
724
+ if (evt.clientY > yLimit && evt.clientX < xLimit) {
725
+ // able to move in X and Y
726
+ const distanceMouseMovedX = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
727
+ this._expandLeft(distanceMouseMovedX);
728
+ this._mouseStartPointX = evt.clientX;
729
+ const distanceMouseMovedY = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
730
+ this._expandBottom(distanceMouseMovedY);
731
+ this._mouseStartPointY = evt.clientY;
675
732
  }
676
- }
677
- ++i;
678
- }
679
- for (const node of this._nodes) {
680
- for (const port of node.outputPorts) {
681
- // Output
682
- port.exposedPortPosition = this._exposedOutPorts.findIndex((nodePort) => nodePort === port);
683
- if (port.exposedPortPosition < 0) {
684
- if (this._createOutputPorts(port, node)) {
685
- port.node.enclosingFrameId = this.id;
686
- this._exposedOutPorts.push(port);
687
- port.exposedPortPosition = this._exposedOutPorts.length - 1;
688
- }
733
+ else if (evt.clientY < yLimit && evt.clientX < xLimit) {
734
+ // able to move in X but not Y
735
+ const distanceMouseMovedX = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
736
+ this._expandLeft(distanceMouseMovedX);
737
+ this._mouseStartPointX = evt.clientX;
689
738
  }
690
- }
691
- for (const port of node.inputPorts) {
692
- // Input
693
- port.exposedPortPosition = this._exposedInPorts.findIndex((nodePort) => nodePort === port);
694
- if (port.exposedPortPosition < 0) {
695
- this._createInputPorts(port, node);
739
+ else if (evt.clientY > yLimit && evt.clientX > xLimit) {
740
+ // able to move in Y but not X
741
+ const distanceMouseMovedY = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
742
+ this._expandBottom(distanceMouseMovedY);
743
+ this._mouseStartPointY = evt.clientY;
696
744
  }
697
745
  }
698
- }
699
- }
700
- _removePortFromExposedWithNode(port, exposedPorts) {
701
- const index = exposedPorts.findIndex((nodePort) => nodePort === port);
702
- if (index >= 0) {
703
- exposedPorts.splice(index, 1);
704
- if (port) {
705
- port.exposedPortPosition = -1;
706
- }
707
- return true;
708
- }
709
- return false;
710
- }
711
- _removePortFromExposedWithLink(nodeLink, exposedPorts) {
712
- const aPort = exposedPorts.findIndex((nodePort) => nodePort === nodeLink.portA);
713
- const bPort = exposedPorts.findIndex((nodePort) => nodePort === nodeLink.portB);
714
- if (aPort >= 0) {
715
- if (!nodeLink.portA.exposedOnFrame) {
716
- exposedPorts.splice(aPort, 1);
717
- nodeLink.portA.exposedPortPosition = -1;
718
- return true;
746
+ };
747
+ this._onBottomLeftHandlePointerUp = (evt) => {
748
+ evt.stopPropagation();
749
+ if (this._resizingDirection === ResizingDirection.BottomLeft) {
750
+ this.height = parseFloat(this.element.style.height.replace("px", ""));
751
+ this.x = parseFloat(this.element.style.left.replace("px", ""));
752
+ this.width = parseFloat(this.element.style.width.replace("px", ""));
753
+ this._ownerCanvas.hostCanvas.removeEventListener("pointerup", this._onBottomLeftHandlePointerUp);
754
+ this._ownerCanvas.hostCanvas.removeEventListener("pointermove", this._onBottomLeftHandlePointerMove);
755
+ this._cleanUpResizing(evt);
719
756
  }
720
- }
721
- else if (bPort >= 0) {
722
- if (nodeLink.portB && !nodeLink.portB.exposedOnFrame) {
723
- exposedPorts.splice(bPort, 1);
724
- nodeLink.portB.exposedPortPosition = -1;
725
- return true;
757
+ };
758
+ //@ts-ignore
759
+ this._onTopLeftHandlePointerDown = (evt) => {
760
+ if (this.isCollapsed) {
761
+ return;
726
762
  }
727
- }
728
- return false;
729
- }
730
- _createInputPorts(port, node) {
731
- if (port.portData.isConnected) {
732
- let portAdded = false;
733
- for (const link of node.links) {
734
- if (link.portB === port && this.nodes.indexOf(link.nodeA) === -1) {
735
- this._createInputPort(port, node);
736
- link.isVisible = true;
737
- portAdded = true;
738
- const onLinkDisposedObserver = link.onDisposedObservable.add((nodeLink) => {
739
- if (this._removePortFromExposedWithLink(nodeLink, this._exposedInPorts)) {
740
- this.redrawFramePorts();
741
- }
742
- });
743
- this._onNodeLinkDisposedObservers.push(onLinkDisposedObserver);
744
- }
763
+ this._initResizing(evt);
764
+ this._resizingDirection = ResizingDirection.TopLeft;
765
+ this._mouseXLimit = evt.clientX + this.width - this._minFrameWidth;
766
+ this._ownerCanvas.hostCanvas.addEventListener("pointerup", this._onTopLeftHandlePointerUp);
767
+ this._ownerCanvas.hostCanvas.addEventListener("pointermove", this._onTopLeftHandlePointerMove);
768
+ };
769
+ this._onTopLeftHandlePointerMove = (evt) => {
770
+ const topSlack = (this.element.offsetHeight - this._minFrameHeight) * this._ownerCanvas.zoom;
771
+ const yLimit = this._mouseStartPointY + topSlack;
772
+ const leftSlack = (this.element.offsetWidth - this._minFrameWidth) * this._ownerCanvas.zoom;
773
+ const xLimit = this._mouseStartPointX + leftSlack;
774
+ this._moveTopLeftHandle(evt, xLimit, yLimit);
775
+ };
776
+ this._moveTopLeftHandle = (evt, xLimit, yLimit) => {
777
+ if (!(this._isResizingTop() && this._isResizingLeft()) || this._mouseStartPointX === null || this._mouseStartPointY === null) {
778
+ return;
745
779
  }
746
- if (portAdded)
747
- return true;
748
- }
749
- else if (port.exposedOnFrame) {
750
- this._createInputPort(port, node);
751
- return true;
752
- }
753
- return false;
754
- }
755
- _createOutputPorts(port, node) {
756
- if (port.portData.hasEndpoints) {
757
- let portAdded = false;
758
- for (const link of node.links) {
759
- if (link.portA === port && this.nodes.indexOf(link.nodeB) === -1) {
760
- let localPort;
761
- if (!portAdded) {
762
- portAdded = true;
763
- localPort = FrameNodePort.CreateFrameNodePortElement(port.portData, link.nodeA, this._outputPortContainer, null, this._ownerCanvas.stateManager, false, GraphFrame._FramePortCounter++, this.id);
764
- this._frameOutPorts.push(localPort);
765
- link.isVisible = true;
766
- const onLinkDisposedObserver = link.onDisposedObservable.add((nodeLink) => {
767
- if (this._removePortFromExposedWithLink(nodeLink, this._exposedOutPorts)) {
768
- this.redrawFramePorts();
769
- }
770
- });
771
- this._onNodeLinkDisposedObservers.push(onLinkDisposedObserver);
772
- }
773
- else if (this.nodes.indexOf(link.nodeB) === -1) {
774
- link.isVisible = true;
775
- localPort = this.ports.filter((p) => p.portData === port.portData)[0];
776
- }
777
- else {
778
- localPort = this.ports.filter((p) => p.portData === port.portData)[0];
779
- }
780
- port.delegatedPort = localPort;
781
- this._controlledPorts.push(port);
780
+ if (this._isResizingLeft() && this._isResizingTop()) {
781
+ evt.stopPropagation();
782
+ if (evt.clientY < yLimit && evt.clientX < xLimit) {
783
+ // able to move in X and Y
784
+ const distanceMouseMovedX = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
785
+ this._expandLeft(distanceMouseMovedX);
786
+ this._mouseStartPointX = evt.clientX;
787
+ const distanceMouseMovedY = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
788
+ this._expandTop(distanceMouseMovedY);
789
+ this._mouseStartPointY = evt.clientY;
782
790
  }
783
- else if (port.exposedPortPosition >= 0 && !portAdded) {
784
- const localPort = FrameNodePort.CreateFrameNodePortElement(port.portData, node, this._outputPortContainer, null, this._ownerCanvas.stateManager, false, GraphFrame._FramePortCounter++, this.id);
785
- this._frameOutPorts.push(localPort);
786
- port.delegatedPort = localPort;
787
- this._controlledPorts.push(port);
788
- portAdded = true;
791
+ else if (evt.clientY > yLimit && evt.clientX < xLimit) {
792
+ // able to move in X but not Y
793
+ const distanceMouseMovedX = (evt.clientX - this._mouseStartPointX) / this._ownerCanvas.zoom;
794
+ this._expandLeft(distanceMouseMovedX);
795
+ this._mouseStartPointX = evt.clientX;
796
+ }
797
+ else if (evt.clientY < yLimit && evt.clientX > xLimit) {
798
+ // able to move in Y but not X
799
+ const distanceMouseMovedY = (evt.clientY - this._mouseStartPointY) / this._ownerCanvas.zoom;
800
+ this._expandTop(distanceMouseMovedY);
801
+ this._mouseStartPointY = evt.clientY;
789
802
  }
790
803
  }
791
- if (portAdded)
792
- return true;
793
- }
794
- else if (port.exposedOnFrame) {
795
- const localPort = FrameNodePort.CreateFrameNodePortElement(port.portData, node, this._outputPortContainer, null, this._ownerCanvas.stateManager, false, GraphFrame._FramePortCounter++, this.id);
796
- this._frameOutPorts.push(localPort);
797
- port.delegatedPort = localPort;
798
- this._controlledPorts.push(port);
799
- return true;
800
- }
801
- return false;
802
- }
803
- redrawFramePorts() {
804
- if (!this.isCollapsed) {
805
- return;
806
- }
807
- this._outputPortContainer.innerHTML = "";
808
- this._inputPortContainer.innerHTML = "";
809
- this.ports.forEach((framePort) => {
810
- framePort.dispose();
804
+ };
805
+ this._onTopLeftHandlePointerUp = (evt) => {
806
+ evt.stopPropagation();
807
+ if (this._resizingDirection === ResizingDirection.TopLeft) {
808
+ this.y = parseFloat(this.element.style.top.replace("px", ""));
809
+ this.height = parseFloat(this.element.style.height.replace("px", ""));
810
+ this.x = parseFloat(this.element.style.left.replace("px", ""));
811
+ this.width = parseFloat(this.element.style.width.replace("px", ""));
812
+ this._ownerCanvas.hostCanvas.removeEventListener("pointerup", this._onTopLeftHandlePointerUp);
813
+ this._ownerCanvas.hostCanvas.removeEventListener("pointermove", this._onTopLeftHandlePointerMove);
814
+ this._cleanUpResizing(evt);
815
+ }
816
+ };
817
+ this._id = GraphFrame._FrameCounter++;
818
+ this._ownerCanvas = canvas;
819
+ const root = canvas.frameContainer;
820
+ this.element = root.ownerDocument.createElement("div");
821
+ this.element.classList.add(commonStyles["frame-box"]);
822
+ root.appendChild(this.element);
823
+ this._headerElement = root.ownerDocument.createElement("div");
824
+ this._headerElement.classList.add(styles["frame-box-header"]);
825
+ this._headerElement.addEventListener("dblclick", () => {
826
+ this.isCollapsed = !this.isCollapsed;
811
827
  });
812
- this._controlledPorts.forEach((port) => {
813
- port.delegatedPort = null;
814
- port.refresh();
828
+ this.element.appendChild(this._headerElement);
829
+ this._borderElement = root.ownerDocument.createElement("div");
830
+ this._borderElement.classList.add(styles["frame-box-border"]);
831
+ this.element.appendChild(this._borderElement);
832
+ this.element.classList.add(styles.expanded);
833
+ // add resizing side handles
834
+ const rightHandle = root.ownerDocument.createElement("div");
835
+ rightHandle.className = styles["right-handle"];
836
+ this.element.appendChild(rightHandle);
837
+ rightHandle.addEventListener("pointerdown", this._onRightHandlePointerDown);
838
+ const leftHandle = root.ownerDocument.createElement("div");
839
+ leftHandle.className = styles["left-handle"];
840
+ this.element.appendChild(leftHandle);
841
+ leftHandle.addEventListener("pointerdown", this._onLeftHandlePointerDown);
842
+ const bottomHandle = root.ownerDocument.createElement("div");
843
+ bottomHandle.className = styles["bottom-handle"];
844
+ this.element.appendChild(bottomHandle);
845
+ bottomHandle.addEventListener("pointerdown", this._onBottomHandlePointerDown);
846
+ const topHandle = root.ownerDocument.createElement("div");
847
+ topHandle.className = styles["top-handle"];
848
+ this.element.appendChild(topHandle);
849
+ topHandle.addEventListener("pointerdown", this._onTopHandlePointerDown);
850
+ const topRightCornerHandle = root.ownerDocument.createElement("div");
851
+ topRightCornerHandle.className = ClassNames({ "right-handle": true, "top-right-corner-handle": true }, styles);
852
+ this.element.appendChild(topRightCornerHandle);
853
+ topRightCornerHandle.addEventListener("pointerdown", this._onTopRightHandlePointerDown);
854
+ const bottomRightCornerHandle = root.ownerDocument.createElement("div");
855
+ bottomRightCornerHandle.className = ClassNames({ "right-handle": true, "bottom-right-corner-handle": true }, styles);
856
+ this.element.appendChild(bottomRightCornerHandle);
857
+ bottomRightCornerHandle.addEventListener("pointerdown", this._onBottomRightHandlePointerDown);
858
+ const topLeftCornerHandle = root.ownerDocument.createElement("div");
859
+ topLeftCornerHandle.className = ClassNames({ "left-handle": true, "top-left-corner-handle": true }, styles);
860
+ this.element.appendChild(topLeftCornerHandle);
861
+ topLeftCornerHandle.addEventListener("pointerdown", this._onTopLeftHandlePointerDown);
862
+ const bottomLeftCornerHandle = root.ownerDocument.createElement("div");
863
+ bottomLeftCornerHandle.className = ClassNames({ "left-handle": true, "bottom-left-corner-handle": true }, styles);
864
+ this.element.appendChild(bottomLeftCornerHandle);
865
+ bottomLeftCornerHandle.addEventListener("pointerdown", this._onBottomLeftHandlePointerDown);
866
+ // add header elements
867
+ this._headerTextElement = root.ownerDocument.createElement("div");
868
+ this._headerTextElement.classList.add(styles["frame-box-header-title"]);
869
+ this._headerElement.appendChild(this._headerTextElement);
870
+ this._headerCollapseElement = root.ownerDocument.createElement("div");
871
+ this._headerCollapseElement.classList.add(styles["frame-box-header-collapse"]);
872
+ this._headerCollapseElement.classList.add(styles["frame-box-header-button"]);
873
+ this._headerCollapseElement.title = "Collapse";
874
+ this._headerCollapseElement.ondragstart = () => false;
875
+ this._headerCollapseElement.addEventListener("pointerdown", (evt) => {
876
+ this._headerCollapseElement.classList.add("down");
877
+ evt.stopPropagation();
815
878
  });
816
- this._frameInPorts = [];
817
- this._frameOutPorts = [];
818
- this._controlledPorts = [];
819
- this._createFramePorts();
820
- this._markFramePortPositions();
821
- this.ports.forEach((framePort) => framePort.node._refreshLinks());
822
- }
823
- set isCollapsed(value) {
824
- if (this._isCollapsed === value) {
825
- return;
826
- }
827
- this._isCollapsed = value;
828
- this._ownerCanvas._frameIsMoving = true;
829
- // Need to delegate the outside ports to the frame
830
- if (value) {
831
- this.element.classList.add(styles.collapsed);
832
- this.element.classList.remove(styles.expanded);
833
- this._headerElement.classList.add(styles.collapsedHeader);
834
- this._moveFrame((this.width - this._collapsedWidth) / 2, 0);
835
- this._createFramePorts();
836
- this._markFramePortPositions();
879
+ this._headerCollapseElement.addEventListener("pointerup", (evt) => {
880
+ evt.stopPropagation();
881
+ this._headerCollapseElement.classList.remove("down");
882
+ this.isCollapsed = !this.isCollapsed;
883
+ });
884
+ this._headerCollapseElement.innerHTML = this._collapseSVG;
885
+ this._headerElement.appendChild(this._headerCollapseElement);
886
+ this._headerCloseElement = root.ownerDocument.createElement("div");
887
+ this._headerCloseElement.classList.add(styles["frame-box-header-close"]);
888
+ this._headerCloseElement.classList.add(styles["frame-box-header-button"]);
889
+ this._headerCloseElement.title = "Close";
890
+ this._headerCloseElement.ondragstart = () => false;
891
+ this._headerCloseElement.addEventListener("pointerdown", (evt) => {
892
+ evt.stopPropagation();
893
+ });
894
+ this._headerCloseElement.addEventListener("pointerup", (evt) => {
895
+ evt.stopPropagation();
896
+ this.dispose();
897
+ });
898
+ this._headerCloseElement.innerHTML = this._closeSVG;
899
+ this._headerElement.appendChild(this._headerCloseElement);
900
+ this._portContainer = root.ownerDocument.createElement("div");
901
+ this._portContainer.classList.add(styles["port-container"]);
902
+ this.element.appendChild(this._portContainer);
903
+ this._outputPortContainer = root.ownerDocument.createElement("div");
904
+ this._outputPortContainer.classList.add(commonStyles["outputsContainer"]);
905
+ this._portContainer.appendChild(this._outputPortContainer);
906
+ this._inputPortContainer = root.ownerDocument.createElement("div");
907
+ this._inputPortContainer.classList.add(commonStyles["inputsContainer"]);
908
+ this._portContainer.appendChild(this._inputPortContainer);
909
+ this.name = "Frame";
910
+ this.color = Color3.FromInts(72, 72, 72);
911
+ if (candidate) {
912
+ this.x = parseFloat(candidate.style.left.replace("px", ""));
913
+ this.y = parseFloat(candidate.style.top.replace("px", ""));
914
+ this.width = parseFloat(candidate.style.width.replace("px", ""));
915
+ this.height = parseFloat(candidate.style.height.replace("px", ""));
916
+ this.cleanAccumulation();
837
917
  }
838
- else {
839
- this.element.classList.add(styles.expanded);
840
- this.element.classList.remove(styles.collapsed);
841
- this._headerElement.classList.remove(styles.collapsedHeader);
842
- this._outputPortContainer.innerHTML = "";
843
- this._inputPortContainer.innerHTML = "";
844
- this._frameInPorts.forEach((p) => {
845
- p.dispose();
846
- });
847
- this._frameOutPorts.forEach((p) => {
848
- p.dispose();
849
- });
850
- this._controlledPorts.forEach((port) => {
851
- port.delegatedPort = null;
852
- port.refresh();
853
- });
854
- this._frameInPorts = [];
855
- this._frameOutPorts = [];
856
- this._controlledPorts = [];
857
- this._onNodeLinkDisposedObservers = [];
858
- for (const node of this._nodes) {
859
- node.isVisible = true;
918
+ this._headerTextElement.addEventListener("pointerdown", (evt) => this._onDown(evt));
919
+ this._headerTextElement.addEventListener("pointerup", (evt) => this._onUp(evt));
920
+ this._headerTextElement.addEventListener("pointermove", (evt) => this._onMove(evt));
921
+ this._onSelectionChangedObserver = canvas.stateManager.onSelectionChangedObservable.add(() => {
922
+ if (this._ownerCanvas.selectedFrames.indexOf(this) !== -1) {
923
+ this._borderElement.classList.add(styles["selected"]);
860
924
  }
861
- this._moveFrame(-(this.width - this._collapsedWidth) / 2, 0);
862
- }
863
- this.cleanAccumulation();
864
- this._ownerCanvas._frameIsMoving = false;
865
- // UI
866
- if (this._isCollapsed) {
867
- this._headerCollapseElement.innerHTML = this._expandSVG;
868
- this._headerCollapseElement.title = "Expand";
869
- }
870
- else {
871
- this._headerCollapseElement.innerHTML = this._collapseSVG;
872
- this._headerCollapseElement.title = "Collapse";
873
- }
874
- this.onExpandStateChanged.notifyObservers(this);
875
- }
876
- get nodes() {
877
- return this._nodes;
878
- }
879
- get ports() {
880
- return this._frameInPorts.concat(this._frameOutPorts);
881
- }
882
- get name() {
883
- return this._name;
884
- }
885
- set name(value) {
886
- this._name = value;
887
- this._headerTextElement.innerHTML = value;
888
- }
889
- get color() {
890
- return this._color;
891
- }
892
- set color(value) {
893
- this._color = value;
894
- this._headerElement.style.background = `rgba(${value.r * 255}, ${value.g * 255}, ${value.b * 255}, 1)`;
895
- this._headerElement.style.borderColor = `rgba(${value.r * 255}, ${value.g * 255}, ${value.b * 255}, 1)`;
896
- this.element.style.background = `rgba(${value.r * 255}, ${value.g * 255}, ${value.b * 255}, 0.7)`;
897
- }
898
- get x() {
899
- return this._x;
900
- }
901
- set x(value) {
902
- if (this._x === value) {
903
- return;
904
- }
905
- this._x = value;
906
- this._gridAlignedX = this._ownerCanvas.getGridPosition(value);
907
- this.element.style.left = `${this._gridAlignedX}px`;
908
- }
909
- get y() {
910
- return this._y;
911
- }
912
- set y(value) {
913
- if (this._y === value) {
914
- return;
915
- }
916
- this._y = value;
917
- this._gridAlignedY = this._ownerCanvas.getGridPosition(value);
918
- this.element.style.top = `${this._gridAlignedY}px`;
919
- }
920
- get width() {
921
- return this._width;
922
- }
923
- set width(value) {
924
- if (this._width === value) {
925
- return;
926
- }
927
- const viableWidth = value > this._minFrameWidth ? value : this._minFrameWidth;
928
- this._width = viableWidth;
929
- const gridAlignedRight = this._ownerCanvas.getGridPositionCeil(viableWidth + this._gridAlignedX);
930
- this.element.style.width = `${gridAlignedRight - this._gridAlignedX}px`;
931
- }
932
- get height() {
933
- return this._height;
934
- }
935
- set height(value) {
936
- if (this._height === value) {
937
- return;
938
- }
939
- this._height = value;
940
- const gridAlignedBottom = this._ownerCanvas.getGridPositionCeil(value + this._gridAlignedY);
941
- this.element.style.height = `${gridAlignedBottom - this._gridAlignedY}px`;
942
- }
943
- get comments() {
944
- return this._comments;
945
- }
946
- set comments(comments) {
947
- if (comments && !this._comments && comments.length > 0) {
948
- this.element.style.gridTemplateRows = "40px min-content 1fr";
949
- this._borderElement.style.gridRow = "1 / span 3";
950
- this._portContainer.style.gridRow = "3";
951
- this._commentsElement.classList.add("has-comments");
952
- }
953
- else if (!comments) {
954
- this.element.style.gridTemplateRows = "40px calc(100% - 40px)";
955
- this._borderElement.style.gridRow = "1 / span 2";
956
- this._portContainer.style.gridRow = "2";
957
- this._commentsElement.classList.remove("has-comments");
958
- }
959
- if (comments === "" || (comments && comments.length >= 0)) {
960
- this._commentsElement.children[0].innerText = comments;
925
+ else {
926
+ this._borderElement.classList.remove(styles["selected"]);
927
+ }
928
+ });
929
+ canvas.stateManager.onSelectionBoxMoved.add((rect1) => {
930
+ const rect2 = this.element.getBoundingClientRect();
931
+ const overlap = !(rect1.right < rect2.left || rect1.left > rect2.right || rect1.bottom < rect2.top || rect1.top > rect2.bottom);
932
+ if (overlap) {
933
+ canvas.stateManager.onSelectionChangedObservable.notifyObservers({ selection: this, forceKeepSelection: true, marqueeSelection: true });
934
+ }
935
+ });
936
+ this._onGraphNodeRemovalObserver = canvas.stateManager.onGraphNodeRemovalObservable.add((node) => {
937
+ // remove node from this._nodes
938
+ const index = this._nodes.indexOf(node);
939
+ if (index === -1) {
940
+ return;
941
+ }
942
+ else {
943
+ node.enclosingFrameId = -1;
944
+ this._nodes.splice(index, 1);
945
+ }
946
+ });
947
+ this._onExposePortOnFrameObserver = canvas.stateManager.onExposePortOnFrameObservable.add((node) => {
948
+ if (this.nodes.indexOf(node) === -1) {
949
+ return;
950
+ }
951
+ this.redrawFramePorts();
952
+ });
953
+ this._commentsElement = document.createElement("div");
954
+ this._commentsElement.className = styles["frame-comments"];
955
+ this._commentsElement.style.color = "white";
956
+ this._commentsElement.style.fontSize = "16px";
957
+ const commentSpan = document.createElement("span");
958
+ commentSpan.className = styles["frame-comment-span"];
959
+ this._commentsElement.appendChild(commentSpan);
960
+ this.element.appendChild(this._commentsElement);
961
+ // Get nodes
962
+ if (!doNotCaptureNodes) {
963
+ this.refresh();
961
964
  }
962
- this.height = this._borderElement.offsetHeight;
963
- this._comments = comments;
964
- this._updateMinHeightWithComments();
965
965
  }
966
966
  refresh() {
967
967
  this._nodes = [];