@elyra/canvas 12.36.0 → 12.37.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.
Files changed (105) hide show
  1. package/dist/canvas-constants-766c12a9.js +2 -0
  2. package/dist/{canvas-constants-85883d4c.js.map → canvas-constants-766c12a9.js.map} +1 -1
  3. package/dist/canvas-constants-f4219d26.js +2 -0
  4. package/dist/{canvas-constants-d8652829.js.map → canvas-constants-f4219d26.js.map} +1 -1
  5. package/dist/canvas-controller-62b66fc8.js +2 -0
  6. package/dist/canvas-controller-62b66fc8.js.map +1 -0
  7. package/dist/canvas-controller-76f68572.js +2 -0
  8. package/dist/canvas-controller-76f68572.js.map +1 -0
  9. package/dist/common-canvas-339584b8.js +2 -0
  10. package/dist/common-canvas-339584b8.js.map +1 -0
  11. package/dist/common-canvas-c728f092.js +2 -0
  12. package/dist/common-canvas-c728f092.js.map +1 -0
  13. package/dist/common-canvas.es.js +1 -1
  14. package/dist/common-canvas.es.js.map +1 -1
  15. package/dist/common-canvas.js +1 -1
  16. package/dist/common-canvas.js.map +1 -1
  17. package/dist/common-properties-009d29d6.js +2 -0
  18. package/dist/{common-properties-a34905c3.js.map → common-properties-009d29d6.js.map} +1 -1
  19. package/dist/common-properties-99d34523.js +2 -0
  20. package/dist/{common-properties-d5775a12.js.map → common-properties-99d34523.js.map} +1 -1
  21. package/dist/context-menu-wrapper-624a1e7c.js +2 -0
  22. package/dist/context-menu-wrapper-624a1e7c.js.map +1 -0
  23. package/dist/context-menu-wrapper-ab018d6e.js +2 -0
  24. package/dist/context-menu-wrapper-ab018d6e.js.map +1 -0
  25. package/dist/{datarecord-metadata-v3-schema-531c7b07.js → datarecord-metadata-v3-schema-1f21696a.js} +2 -2
  26. package/dist/{datarecord-metadata-v3-schema-531c7b07.js.map → datarecord-metadata-v3-schema-1f21696a.js.map} +1 -1
  27. package/dist/{datarecord-metadata-v3-schema-28d4d7bb.js → datarecord-metadata-v3-schema-c2ad8862.js} +2 -2
  28. package/dist/{datarecord-metadata-v3-schema-28d4d7bb.js.map → datarecord-metadata-v3-schema-c2ad8862.js.map} +1 -1
  29. package/dist/flexible-table-4cf19e2e.js +2 -0
  30. package/dist/flexible-table-4cf19e2e.js.map +1 -0
  31. package/dist/flexible-table-8d10f5c9.js +2 -0
  32. package/dist/flexible-table-8d10f5c9.js.map +1 -0
  33. package/dist/{icon-909437d7.js → icon-5e06bfe1.js} +2 -2
  34. package/dist/{icon-909437d7.js.map → icon-5e06bfe1.js.map} +1 -1
  35. package/dist/{icon-de9c6b33.js → icon-8433d369.js} +2 -2
  36. package/dist/{icon-de9c6b33.js.map → icon-8433d369.js.map} +1 -1
  37. package/dist/{index-9960d3bf.js → index-2a61be58.js} +2 -2
  38. package/dist/{index-9960d3bf.js.map → index-2a61be58.js.map} +1 -1
  39. package/dist/{index-61e4a113.js → index-9a355ed6.js} +2 -2
  40. package/dist/{index-61e4a113.js.map → index-9a355ed6.js.map} +1 -1
  41. package/dist/lib/canvas-controller.es.js +1 -1
  42. package/dist/lib/canvas-controller.js +1 -1
  43. package/dist/lib/canvas.es.js +1 -1
  44. package/dist/lib/canvas.js +1 -1
  45. package/dist/lib/context-menu.es.js +1 -1
  46. package/dist/lib/context-menu.js +1 -1
  47. package/dist/lib/properties/field-picker.es.js +1 -1
  48. package/dist/lib/properties/field-picker.js +1 -1
  49. package/dist/lib/properties/flexible-table.es.js +1 -1
  50. package/dist/lib/properties/flexible-table.js +1 -1
  51. package/dist/lib/properties.es.js +1 -1
  52. package/dist/lib/properties.js +1 -1
  53. package/dist/styles/common-canvas.min.css +1 -1
  54. package/dist/styles/common-canvas.min.css.map +1 -1
  55. package/dist/{toolbar-cdb38f4a.js → toolbar-76733735.js} +2 -2
  56. package/dist/{toolbar-cdb38f4a.js.map → toolbar-76733735.js.map} +1 -1
  57. package/dist/{toolbar-3b5a592c.js → toolbar-85e1e463.js} +2 -2
  58. package/dist/{toolbar-3b5a592c.js.map → toolbar-85e1e463.js.map} +1 -1
  59. package/locales/common-canvas/locales/en.json +1 -1
  60. package/locales/common-canvas/locales/eo.json +1 -1
  61. package/package.json +2 -3
  62. package/src/common-canvas/canvas-controller.js +7 -0
  63. package/src/common-canvas/cc-contents.jsx +42 -4
  64. package/src/common-canvas/common-canvas-utils.js +9 -2
  65. package/src/common-canvas/common-canvas.scss +30 -3
  66. package/src/common-canvas/constants/canvas-constants.js +0 -6
  67. package/src/common-canvas/svg-canvas-d3.js +1 -3
  68. package/src/common-canvas/svg-canvas-d3.scss +0 -26
  69. package/src/common-canvas/svg-canvas-pipeline.js +6 -0
  70. package/src/common-canvas/svg-canvas-renderer.js +488 -2815
  71. package/src/common-canvas/svg-canvas-utils-drag-det-link.js +491 -0
  72. package/src/common-canvas/svg-canvas-utils-drag-new-link.js +595 -0
  73. package/src/common-canvas/svg-canvas-utils-drag-objects.js +832 -0
  74. package/src/common-canvas/svg-canvas-utils-external.js +82 -16
  75. package/src/common-canvas/svg-canvas-utils-zoom.js +780 -0
  76. package/src/context-menu/common-context-menu.jsx +57 -26
  77. package/src/context-menu/context-menu.scss +33 -53
  78. package/src/notification-panel/notification-panel.jsx +6 -1
  79. package/src/notification-panel/notification-panel.scss +4 -2
  80. package/src/palette/palette-content-list-item.jsx +23 -7
  81. package/stats.html +1 -1
  82. package/dist/canvas-constants-85883d4c.js +0 -2
  83. package/dist/canvas-constants-d8652829.js +0 -2
  84. package/dist/canvas-controller-7beb80ec.js +0 -2
  85. package/dist/canvas-controller-7beb80ec.js.map +0 -1
  86. package/dist/canvas-controller-b70d0f98.js +0 -2
  87. package/dist/canvas-controller-b70d0f98.js.map +0 -1
  88. package/dist/common-canvas-86fb7d21.js +0 -2
  89. package/dist/common-canvas-86fb7d21.js.map +0 -1
  90. package/dist/common-canvas-a6bfce5e.js +0 -2
  91. package/dist/common-canvas-a6bfce5e.js.map +0 -1
  92. package/dist/common-properties-a34905c3.js +0 -2
  93. package/dist/common-properties-d5775a12.js +0 -2
  94. package/dist/context-menu-wrapper-19a1cf72.js +0 -2
  95. package/dist/context-menu-wrapper-19a1cf72.js.map +0 -1
  96. package/dist/context-menu-wrapper-c3a98c63.js +0 -2
  97. package/dist/context-menu-wrapper-c3a98c63.js.map +0 -1
  98. package/dist/extends-093996c9.js +0 -2
  99. package/dist/extends-093996c9.js.map +0 -1
  100. package/dist/extends-1b35a664.js +0 -2
  101. package/dist/extends-1b35a664.js.map +0 -1
  102. package/dist/flexible-table-b9c08069.js +0 -2
  103. package/dist/flexible-table-b9c08069.js.map +0 -1
  104. package/dist/flexible-table-ddd6132b.js +0 -2
  105. package/dist/flexible-table-ddd6132b.js.map +0 -1
@@ -0,0 +1,832 @@
1
+ /*
2
+ * Copyright 2017-2023 Elyra Authors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ /* eslint no-lonely-if: "off" */
18
+
19
+ import * as d3Drag from "d3-drag";
20
+ import * as d3Selection from "d3-selection";
21
+ const d3 = Object.assign({}, d3Drag, d3Selection);
22
+
23
+ import Logger from "../logging/canvas-logger.js";
24
+ import CanvasUtils from "./common-canvas-utils.js";
25
+ import { SNAP_TO_GRID_AFTER, SNAP_TO_GRID_DURING, LINK_SELECTION_DETACHABLE }
26
+ from "./constants/canvas-constants.js";
27
+
28
+ // This utility files provides a drag handler which manages drag operations to move
29
+ // and resize nodes and comments.
30
+
31
+ export default class SVGCanvasUtilsDragObjects {
32
+ constructor(renderer) {
33
+ this.ren = renderer;
34
+
35
+ this.logger = new Logger("SVGCanvasUtilsDragObjects");
36
+
37
+ // Keeps track of the size and position, at the start of the sizing event,
38
+ // of the object (node or comment) being sized.
39
+ this.resizeObjInitialInfo = null;
40
+
41
+ // Allows us to track the sizing behavior of comments
42
+ this.commentSizing = false;
43
+ this.commentSizingDirection = null;
44
+ this.commentSizingCursor = "";
45
+
46
+ // Allows us to track the sizing behavior of nodes
47
+ this.nodeSizing = false;
48
+ this.nodeSizingDirection = null;
49
+ this.nodeSizingCursor = "";
50
+ this.nodeSizingObjectsInfo = {};
51
+ this.nodeSizingDetLinksInfo = {};
52
+
53
+ // Keeps track of the size and position, during a sizing event, of the
54
+ // object (node or comment) being sized, before it is snapped to grid.
55
+ this.notSnappedXPos = 0;
56
+ this.notSnappedYPos = 0;
57
+ this.notSnappedWidth = 0;
58
+ this.notSnappedHeight = 0;
59
+
60
+ // Object to store variables for drag behavior or nodes and comments.
61
+ this.draggingObjectData = null;
62
+
63
+ // Flag to indicate if the current drag operation is for a node that can
64
+ // be inserted into a link. Such a node would need input and output ports.
65
+ this.existingNodeInsertableIntoLink = false;
66
+
67
+ // Flag to indicate if the current drag operation is for a node that can
68
+ // be attached to a detached link.
69
+ this.existingNodeAttachableToDetachedLinks = false;
70
+
71
+ // Create a drag handler for resizing and moving nodes and comments.
72
+ this.dragObjectHandler = d3.drag()
73
+ .on("start", this.dragStartObject.bind(this))
74
+ .on("drag", this.dragObject.bind(this))
75
+ .on("end", this.dragEndObject.bind(this));
76
+ }
77
+
78
+ // Returns the dragObjectsHandler
79
+ getDragObjectHandler() {
80
+ return this.dragObjectHandler;
81
+ }
82
+
83
+ // Returns true if a sizing operation is currently underway.
84
+ isSizing() {
85
+ return this.nodeSizing || this.commentSizing;
86
+ }
87
+
88
+ // Returns truthy if a moving operation is currently underway.
89
+ isMoving() {
90
+ return this.draggingObjectData;
91
+ }
92
+
93
+ mouseEnterNodeSizingArea(d3Event, d) {
94
+ if (this.ren.config.enableEditingActions && // Only set cursor when we are able to resize nodes
95
+ this.isNodeResizable(d) &&
96
+ !this.ren.isRegionSelectOrSizingInProgress()) { // Don't switch sizing direction if we are already sizing
97
+ let cursorType = "default";
98
+ if (!this.isPointerCloseToBodyEdge(d3Event, d)) {
99
+ this.nodeSizingDirection = this.getSizingDirection(d3Event, d, d.layout.nodeCornerResizeArea);
100
+ this.nodeSizingCursor = this.getCursorBasedOnDirection(this.nodeSizingDirection);
101
+ cursorType = this.nodeSizingCursor;
102
+ }
103
+ d3.select(d3Event.currentTarget).style("cursor", cursorType);
104
+ }
105
+ }
106
+
107
+ mouseDownNodeSizingArea(d) {
108
+ if (this.isNodeResizable(d)) {
109
+ this.nodeSizing = true;
110
+ // Note - node resizing and finalization of size is handled by drag functions.
111
+ this.ren.addTempCursorOverlay(this.nodeSizingCursor);
112
+ }
113
+ }
114
+
115
+ mouseLeaveNodeSizingArea(d3Event) {
116
+ d3.select(d3Event.currentTarget).style("cursor", "default");
117
+ }
118
+
119
+ mouseEnterCommentSizingArea(d3Event, d) {
120
+ if (this.ren.config.enableEditingActions && // Only set cursor when we are able to edit comments
121
+ !this.ren.isRegionSelectOrSizingInProgress()) { // Don't switch sizing direction if we are already sizing
122
+ let cursorType = "default";
123
+ if (!this.isPointerCloseToBodyEdge(d3Event, d)) {
124
+ this.commentSizingDirection = this.getSizingDirection(d3Event, d, this.ren.canvasLayout.commentCornerResizeArea);
125
+ this.commentSizingCursor = this.getCursorBasedOnDirection(this.commentSizingDirection);
126
+ cursorType = this.commentSizingCursor;
127
+ }
128
+ d3.select(d3Event.currentTarget).style("cursor", cursorType);
129
+ }
130
+ }
131
+
132
+ mouseDownCommentSizingArea() {
133
+ // Note - comment resizing and finalization of size is handled by drag functions.
134
+ this.commentSizing = true;
135
+ this.ren.addTempCursorOverlay(this.commentSizingCursor);
136
+ }
137
+
138
+ mouseLeaveCommentSizingArea(d3Event) {
139
+ d3.select(d3Event.currentTarget).style("cursor", "default");
140
+ }
141
+
142
+ dragStartObject(d3Event, d) {
143
+ this.logger.logStartTimer("dragStartObject");
144
+
145
+ this.ren.closeContextMenuIfOpen();
146
+
147
+ if (this.commentSizing) {
148
+ this.initializeResizeVariables(d);
149
+
150
+ } else if (this.nodeSizing) {
151
+ this.initializeResizeVariables(d);
152
+
153
+ } else {
154
+ this.dragObjectsStart(d3Event, d);
155
+ }
156
+
157
+ this.logger.logEndTimer("dragStartObject", true);
158
+ }
159
+
160
+ dragObject(d3Event, d) {
161
+ this.logger.logStartTimer("dragObject");
162
+ if (this.commentSizing) {
163
+ this.resizeComment(d3Event, d);
164
+
165
+ } else if (this.nodeSizing) {
166
+ this.resizeNode(d3Event, d);
167
+
168
+ } else {
169
+ this.dragObjectsAction(d3Event);
170
+ }
171
+
172
+ this.logger.logEndTimer("dragObject", true);
173
+ }
174
+
175
+ dragEndObject(d3Event, d) {
176
+ this.logger.logStartTimer("dragEndObject");
177
+
178
+ this.ren.removeTempCursorOverlay();
179
+
180
+ if (this.commentSizing) {
181
+ this.endCommentSizing(d);
182
+ this.commentSizing = false;
183
+
184
+ } else if (this.nodeSizing) {
185
+ this.endNodeSizing(d);
186
+ this.nodeSizing = false;
187
+
188
+ } else {
189
+ this.dragObjectsEnd(d3Event, d);
190
+ }
191
+
192
+ this.logger.logEndTimer("dragEndObject", true);
193
+ }
194
+
195
+ // Records the initial starting position of the object being sized so
196
+ // that drag increments can be added to the original starting
197
+ // position to aid calculating the snap-to-grid position.
198
+ initializeResizeVariables(resizeObj) {
199
+ this.resizeObjInitialInfo = {
200
+ x_pos: resizeObj.x_pos, y_pos: resizeObj.y_pos, width: resizeObj.width, height: resizeObj.height };
201
+ this.notSnappedXPos = resizeObj.x_pos;
202
+ this.notSnappedYPos = resizeObj.y_pos;
203
+ this.notSnappedWidth = resizeObj.width;
204
+ this.notSnappedHeight = resizeObj.height;
205
+ }
206
+
207
+ // This method allows us to avoid a strange behavior which only appears in the
208
+ // Chrome browser. That is, when the mouse pointer is inside the
209
+ // node/comment selection highlight area but is close to either the
210
+ // right or bottom side of the node/comment body, any mousedown events will go
211
+ // to the body instead of the highlight area. We use this method to detect
212
+ // this situation and use the result to decide whether to display the sizing
213
+ // cursor or not.
214
+ isPointerCloseToBodyEdge(d3Event, d) {
215
+ const pos = this.ren.getTransformedMousePos(d3Event);
216
+ const rightEdge = d.x_pos + d.width;
217
+ const bottomEdge = d.y_pos + d.height;
218
+
219
+ // Is the pointer within 1 pixel of the right edge of the node or comment
220
+ const rightEdgeState =
221
+ pos.x >= rightEdge && pos.x <= rightEdge + 1 &&
222
+ pos.y >= 0 && pos.y <= bottomEdge;
223
+
224
+ // Is the pointer within 1 pixel of the bottom edge of the node or comment
225
+ const bottomEdgeState =
226
+ pos.y >= bottomEdge && pos.y <= bottomEdge + 1 &&
227
+ pos.x >= 0 && pos.x <= rightEdge;
228
+
229
+ return rightEdgeState || bottomEdgeState;
230
+ }
231
+
232
+ // Returns the comment or supernode sizing direction (i.e. one of n, s, e, w, nw, ne,
233
+ // sw or se) based on the current mouse position and the position and
234
+ // dimensions of the comment or node outline.
235
+ getSizingDirection(d3Event, d, cornerResizeArea) {
236
+ var xPart = "";
237
+ var yPart = "";
238
+
239
+ const transPos = this.ren.getTransformedMousePos(d3Event);
240
+ if (transPos.x < d.x_pos + cornerResizeArea) {
241
+ xPart = "w";
242
+ } else if (transPos.x > d.x_pos + d.width - cornerResizeArea) {
243
+ xPart = "e";
244
+ }
245
+ if (transPos.y < d.y_pos + cornerResizeArea) {
246
+ yPart = "n";
247
+ } else if (transPos.y > d.y_pos + d.height - cornerResizeArea) {
248
+ yPart = "s";
249
+ }
250
+
251
+ return yPart + xPart;
252
+ }
253
+
254
+ // Returns a cursor type based on the currect comment sizing direction.
255
+ // Possible values are: ns-resize, ew-resize, nwse-resize or nesw-resize.
256
+ getCursorBasedOnDirection(direction) {
257
+ var cursorType;
258
+ switch (direction) {
259
+ case "n":
260
+ case "s":
261
+ cursorType = "ns-resize";
262
+ break;
263
+ case "e":
264
+ case "w":
265
+ cursorType = "ew-resize";
266
+ break;
267
+ case "nw":
268
+ case "se":
269
+ cursorType = "nwse-resize";
270
+ break;
271
+ case "ne":
272
+ case "sw":
273
+ cursorType = "nesw-resize";
274
+ break;
275
+ default:
276
+ cursorType = "";
277
+ }
278
+
279
+ return cursorType;
280
+ }
281
+
282
+ // Returns true if the node should be resizeable. Expanded supernodes are
283
+ // always resizabele and all other nodes, except collapsed supernodes, are
284
+ // resizeable when enableResizableNodes is switched on.
285
+ isNodeResizable(node) {
286
+ if (!this.ren.config.enableEditingActions ||
287
+ CanvasUtils.isSuperBindingNode(node) ||
288
+ CanvasUtils.isCollapsedSupernode(node) ||
289
+ (!this.ren.config.enableResizableNodes && !CanvasUtils.isExpandedSupernode(node))) {
290
+ return false;
291
+ }
292
+ return true;
293
+ }
294
+
295
+ // Sets the size and position of the node in the canvasInfo.nodes
296
+ // array based on the position of the pointer during the resize action
297
+ // then redraws the nodes and links (the link positions may move based
298
+ // on the node size change).
299
+ resizeNode(d3Event, resizeObj) {
300
+ const oldSupernode = Object.assign({}, resizeObj);
301
+ const minHeight = this.getMinHeight(resizeObj);
302
+ const minWidth = this.getMinWidth(resizeObj);
303
+
304
+ const delta = this.resizeObject(d3Event, resizeObj,
305
+ this.nodeSizingDirection, minWidth, minHeight);
306
+
307
+ if (delta && (delta.x_pos !== 0 || delta.y_pos !== 0 || delta.width !== 0 || delta.height !== 0)) {
308
+ if (CanvasUtils.isSupernode(resizeObj) &&
309
+ this.ren.config.enableMoveNodesOnSupernodeResize) {
310
+ const objectsInfo = CanvasUtils.moveSurroundingObjects(
311
+ oldSupernode,
312
+ this.ren.activePipeline.getNodesAndComments(),
313
+ this.nodeSizingDirection,
314
+ resizeObj.width,
315
+ resizeObj.height,
316
+ true // Pass true to indicate that object positions should be updated.
317
+ );
318
+
319
+ const linksInfo = CanvasUtils.moveSurroundingDetachedLinks(
320
+ oldSupernode,
321
+ this.ren.activePipeline.links,
322
+ this.nodeSizingDirection,
323
+ resizeObj.width,
324
+ resizeObj.height,
325
+ true // Pass true to indicate that link positions should be updated.
326
+ );
327
+
328
+ // Overwrite the object and link info with any new info.
329
+ this.nodeSizingObjectsInfo = Object.assign(this.nodeSizingObjectsInfo, objectsInfo);
330
+ this.nodeSizingDetLinksInfo = Object.assign(this.nodeSizingDetLinksInfo, linksInfo);
331
+ }
332
+
333
+ this.logger.logStartTimer("displayObjects");
334
+
335
+ this.ren.displayMovedComments();
336
+ this.ren.displayMovedNodes();
337
+ this.ren.displaySingleNode(resizeObj);
338
+ this.ren.displayMovedLinks();
339
+ this.ren.displayCanvasAccoutrements();
340
+
341
+ if (CanvasUtils.isSupernode(resizeObj)) {
342
+ if (this.ren.dispUtils.isDisplayingSubFlow()) {
343
+ this.ren.displayBindingNodesToFitSVG();
344
+ }
345
+ this.ren.superRenderers.forEach((renderer) => renderer.displaySVGToFitSupernode());
346
+ }
347
+ this.logger.logEndTimer("displayObjects");
348
+ }
349
+ }
350
+
351
+ // Sets the size and position of the comment in the canvasInfo.comments
352
+ // array based on the position of the pointer during the resize action
353
+ // then redraws the comment and links (the link positions may move based
354
+ // on the comment size change).
355
+ resizeComment(d3Event, resizeObj) {
356
+ this.resizeObject(d3Event, resizeObj, this.commentSizingDirection, 20, 20);
357
+ this.ren.displaySingleComment(resizeObj);
358
+ this.ren.displayMovedLinks();
359
+ this.ren.displayCanvasAccoutrements();
360
+ }
361
+
362
+ // Sets the size and position of the object in the canvasInfo
363
+ // array based on the position of the pointer during the resize action.
364
+ resizeObject(d3Event, canvasObj, direction, minWidth, minHeight) {
365
+ let incrementX = 0;
366
+ let incrementY = 0;
367
+ let incrementWidth = 0;
368
+ let incrementHeight = 0;
369
+
370
+ if (direction.indexOf("e") > -1) {
371
+ incrementWidth += d3Event.dx;
372
+ }
373
+ if (direction.indexOf("s") > -1) {
374
+ incrementHeight += d3Event.dy;
375
+ }
376
+ if (direction.indexOf("n") > -1) {
377
+ incrementY += d3Event.dy;
378
+ incrementHeight -= d3Event.dy;
379
+ }
380
+ if (direction.indexOf("w") > -1) {
381
+ incrementX += d3Event.dx;
382
+ incrementWidth -= d3Event.dx;
383
+ }
384
+
385
+ let xPos = 0;
386
+ let yPos = 0;
387
+ let width = 0;
388
+ let height = 0;
389
+
390
+ if (this.ren.config.enableSnapToGridType === SNAP_TO_GRID_DURING) {
391
+ // Calculate where the object being resized would be and its size given
392
+ // current increments.
393
+ this.notSnappedXPos += incrementX;
394
+ this.notSnappedYPos += incrementY;
395
+ this.notSnappedWidth += incrementWidth;
396
+ this.notSnappedHeight += incrementHeight;
397
+
398
+ xPos = CanvasUtils.snapToGrid(this.notSnappedXPos, this.ren.canvasLayout.snapToGridXPx);
399
+ yPos = CanvasUtils.snapToGrid(this.notSnappedYPos, this.ren.canvasLayout.snapToGridYPx);
400
+ width = CanvasUtils.snapToGrid(this.notSnappedWidth, this.ren.canvasLayout.snapToGridXPx);
401
+ height = CanvasUtils.snapToGrid(this.notSnappedHeight, this.ren.canvasLayout.snapToGridYPx);
402
+
403
+ width = Math.max(width, minWidth);
404
+ height = Math.max(height, minHeight);
405
+
406
+ } else {
407
+ xPos = canvasObj.x_pos + incrementX;
408
+ yPos = canvasObj.y_pos + incrementY;
409
+ width = canvasObj.width + incrementWidth;
410
+ height = canvasObj.height + incrementHeight;
411
+ }
412
+
413
+ // Don't allow the object area to shrink below the min width and height.
414
+ // For comment sizing, errors may occur especially if the width becomes
415
+ // less that one character's width. For node sizing we want at least some
416
+ // area to display the sub-flow.
417
+ if (width < minWidth || height < minHeight) {
418
+ return null;
419
+ }
420
+
421
+ const delta = {
422
+ width: width - canvasObj.width,
423
+ height: height - canvasObj.height,
424
+ x_pos: xPos - canvasObj.x_pos,
425
+ y_pos: yPos - canvasObj.y_pos
426
+ };
427
+
428
+ canvasObj.x_pos = xPos;
429
+ canvasObj.y_pos = yPos;
430
+ canvasObj.width = width;
431
+ canvasObj.height = height;
432
+
433
+ return delta;
434
+ }
435
+
436
+ // Finalises the sizing of a node by calling editActionHandler
437
+ // with an editNode action.
438
+ endNodeSizing(node) {
439
+ let resizeObj = node;
440
+ if (this.ren.config.enableSnapToGridType === SNAP_TO_GRID_AFTER) {
441
+ resizeObj = this.snapToGridObject(resizeObj);
442
+ resizeObj = this.restrictNodeSizingToMinimums(resizeObj);
443
+ }
444
+
445
+ // If the dimensions or position has changed, issue the "resizeObjects" command.
446
+ // Note: x_pos or y_pos might change on resize if the node is sized
447
+ // upwards or to the left.
448
+ if (this.resizeObjInitialInfo.x_pos !== resizeObj.x_pos ||
449
+ this.resizeObjInitialInfo.y_pos !== resizeObj.y_pos ||
450
+ this.resizeObjInitialInfo.width !== resizeObj.width ||
451
+ this.resizeObjInitialInfo.height !== resizeObj.height) {
452
+ // Add the dimensions of the object being resized to the array of object infos.
453
+ this.nodeSizingObjectsInfo[resizeObj.id] = {
454
+ width: resizeObj.width,
455
+ height: resizeObj.height,
456
+ x_pos: resizeObj.x_pos,
457
+ y_pos: resizeObj.y_pos
458
+ };
459
+
460
+ // If the node has been resized set the resize properties appropriately.
461
+ // We use some padding because sometimes, when a node is sized back to its
462
+ // original dimensions, it isn't retunred to EXACTLY its default width/height.
463
+ if (resizeObj.height > resizeObj.layout.defaultNodeHeight + 2 ||
464
+ resizeObj.width > resizeObj.layout.defaultNodeWidth + 2) {
465
+ this.nodeSizingObjectsInfo[resizeObj.id].isResized = true;
466
+ this.nodeSizingObjectsInfo[resizeObj.id].resizeWidth = resizeObj.width;
467
+ this.nodeSizingObjectsInfo[resizeObj.id].resizeHeight = resizeObj.height;
468
+ }
469
+
470
+ this.ren.canvasController.editActionHandler({
471
+ editType: "resizeObjects",
472
+ editSource: "canvas",
473
+ objectsInfo: this.nodeSizingObjectsInfo,
474
+ detachedLinksInfo: this.nodeSizingDetLinksInfo,
475
+ pipelineId: this.ren.activePipeline.id
476
+ });
477
+ }
478
+ }
479
+
480
+ // Finalises the sizing of a comment by calling editActionHandler
481
+ // with an editComment action.
482
+ endCommentSizing(comment) {
483
+ let resizeObj = comment;
484
+ if (this.ren.config.enableSnapToGridType === SNAP_TO_GRID_AFTER) {
485
+ resizeObj = this.snapToGridObject(resizeObj);
486
+ }
487
+
488
+ // If the dimensions or position has changed, issue the command.
489
+ // Note: x_pos or y_pos might change on resize if the node is sized
490
+ // upwards or to the left.
491
+ if (this.resizeObjInitialInfo.x_pos !== resizeObj.x_pos ||
492
+ this.resizeObjInitialInfo.y_pos !== resizeObj.y_pos ||
493
+ this.resizeObjInitialInfo.width !== resizeObj.width ||
494
+ this.resizeObjInitialInfo.height !== resizeObj.height) {
495
+ const commentSizingObjectsInfo = [];
496
+ commentSizingObjectsInfo[resizeObj.id] = {
497
+ width: resizeObj.width,
498
+ height: resizeObj.height,
499
+ x_pos: resizeObj.x_pos,
500
+ y_pos: resizeObj.y_pos
501
+ };
502
+
503
+ const data = {
504
+ editType: "resizeObjects",
505
+ editSource: "canvas",
506
+ objectsInfo: commentSizingObjectsInfo,
507
+ detachedLinksInfo: {}, // Comments cannot have detached links
508
+ pipelineId: this.ren.activePipeline.id
509
+ };
510
+ this.ren.canvasController.editActionHandler(data);
511
+ }
512
+ }
513
+
514
+ // Ensure the snap-to-grid does not make the width or height smaller than
515
+ // the minimums allowed.
516
+ restrictNodeSizingToMinimums(resizeObj) {
517
+ const minHeight = this.getMinHeight(resizeObj);
518
+ const minWidth = this.getMinWidth(resizeObj);
519
+ resizeObj.width = Math.max(resizeObj.width, minWidth);
520
+ resizeObj.height = Math.max(resizeObj.height, minHeight);
521
+ return resizeObj;
522
+ }
523
+
524
+ // Returns the minimum allowed height for the node passed in. For supernodes
525
+ // this means combining the bigger of the space for the inputs and output ports
526
+ // with some space for the top of the display frame and the padding at the
527
+ // bottom of the frame. Then the bigger of that height versus the default
528
+ // supernode minimum height is retunred.
529
+ getMinHeight(node) {
530
+ if (CanvasUtils.isSupernode(node)) {
531
+ const minHt = Math.max(node.inputPortsHeight, node.outputPortsHeight) +
532
+ this.ren.canvasLayout.supernodeTopAreaHeight + this.ren.canvasLayout.supernodeSVGAreaPadding;
533
+ return Math.max(this.ren.canvasLayout.supernodeMinHeight, minHt);
534
+ }
535
+ return node.layout.defaultNodeHeight;
536
+ }
537
+
538
+ // Returns the minimum allowed width for the node passed in.
539
+ getMinWidth(node) {
540
+ if (CanvasUtils.isSupernode(node)) {
541
+ return this.ren.canvasLayout.supernodeMinWidth;
542
+ }
543
+ return node.layout.defaultNodeWidth;
544
+ }
545
+
546
+ // Starts the dragging action for canvas objects (nodes and comments).
547
+ dragObjectsStart(d3Event, d) {
548
+ // Ensure flags are false before staring a new drag.
549
+ this.existingNodeInsertableIntoLink = false;
550
+ this.existingNodeAttachableToDetachedLinks = false;
551
+
552
+ this.draggingObjectData = {
553
+ dragOffsetX: 0,
554
+ dragOffsetY: 0,
555
+ dragRunningX: 0,
556
+ dragRunningY: 0,
557
+ dragObjects: this.getDragObjects(d)
558
+ };
559
+
560
+ if (this.draggingObjectData.dragObjects?.length > 0) {
561
+ this.draggingObjectData.dragStartX = this.draggingObjectData.dragObjects[0].x_pos;
562
+ this.draggingObjectData.dragStartY = this.draggingObjectData.dragObjects[0].y_pos;
563
+ }
564
+
565
+ // If we are dragging an 'insertable' node, set it to be translucent so
566
+ // that, when it is dragged over a link line, the highlightd line can be seen OK.
567
+ if (this.isExistingNodeInsertableIntoLink()) {
568
+ // Only style the node to be translucent if this action isn't cancelled
569
+ // by the user releasing the mouse button within 200 ms of pressing it.
570
+ // This stops the node flashing when the user is only selecting it.
571
+ this.startNodeInsertingInLink = setTimeout(() => {
572
+ this.existingNodeInsertableIntoLink = true;
573
+ this.setNodeTranslucentState(this.draggingObjectData.dragObjects[0].id, true);
574
+ this.ren.setDataLinkSelectionAreaWider(true);
575
+ }, 200);
576
+ }
577
+
578
+ // If we are dragging an 'attachable' node, set it to be translucent so
579
+ // that, when it is dragged over link lines, the highlightd lines can be seen OK.
580
+ if (this.isExistingNodeAttachableToDetachedLinks()) {
581
+ // Only style the node to be translucent if this action isn't cancelled
582
+ // by the user releasing the mouse button within 200 ms of pressing it.
583
+ // This stops the node from being made translucent when the user is only selecting it.
584
+ this.startNodeAttachingToDetachedLinks = setTimeout(() => {
585
+ this.existingNodeAttachableToDetachedLinks = true;
586
+ this.setNodeTranslucentState(this.draggingObjectData.dragObjects[0].id, true);
587
+ }, 200);
588
+ }
589
+ }
590
+
591
+ // Performs the dragging action for canvas objects (nodes and comments).
592
+ dragObjectsAction(d3Event) {
593
+ this.draggingObjectData.dragOffsetX += d3Event.dx;
594
+ this.draggingObjectData.dragOffsetY += d3Event.dy;
595
+
596
+ // Limit the size a drag can be so, when the user is dragging objects in
597
+ // an in-place subflow they do not drag them too far.
598
+ // this.logger.log("Drag offset X = " + this.dragOffsetX + " y = " + this.draggingObjectData.dragOffsetY);
599
+ if (this.ren.dispUtils.isDisplayingSubFlowInPlace() &&
600
+ (this.draggingObjectData.dragOffsetX > 1000 || this.draggingObjectData.dragOffsetX < -1000 ||
601
+ this.draggingObjectData.dragOffsetY > 1000 || this.draggingObjectData.dragOffsetY < -1000)) {
602
+ this.draggingObjectData.dragOffsetX -= d3Event.dx;
603
+ this.draggingObjectData.dragOffsetY -= d3Event.dy;
604
+
605
+ } else {
606
+ let increment = { x: 0, y: 0 };
607
+
608
+ if (this.ren.config.enableSnapToGridType === SNAP_TO_GRID_DURING) {
609
+ const stgPos = this.snapToGridDraggedNode(this.draggingObjectData);
610
+
611
+ increment = {
612
+ x: stgPos.x - this.draggingObjectData.dragObjects[0].x_pos,
613
+ y: stgPos.y - this.draggingObjectData.dragObjects[0].y_pos
614
+ };
615
+
616
+ } else {
617
+ increment = {
618
+ x: d3Event.dx,
619
+ y: d3Event.dy
620
+ };
621
+ }
622
+
623
+ this.draggingObjectData.dragRunningX += increment.x;
624
+ this.draggingObjectData.dragRunningY += increment.y;
625
+
626
+ this.draggingObjectData.dragObjects.forEach((d) => {
627
+ d.x_pos += increment.x;
628
+ d.y_pos += increment.y;
629
+ });
630
+
631
+ if (this.ren.config.enableLinkSelection === LINK_SELECTION_DETACHABLE) {
632
+ this.ren.activePipeline.getSelectedLinks().forEach((link) => {
633
+ if (link.srcPos) {
634
+ link.srcPos.x_pos += increment.x;
635
+ link.srcPos.y_pos += increment.y;
636
+ }
637
+ if (link.trgPos) {
638
+ link.trgPos.x_pos += increment.x;
639
+ link.trgPos.y_pos += increment.y;
640
+ }
641
+ });
642
+ }
643
+ }
644
+
645
+ this.ren.displayMovedComments();
646
+ this.ren.displayMovedNodes();
647
+ this.ren.displayMovedLinks();
648
+ this.ren.displayCanvasAccoutrements();
649
+
650
+ if (this.ren.dispUtils.isDisplayingSubFlowInPlace()) {
651
+ this.ren.displaySVGToFitSupernode();
652
+ }
653
+
654
+
655
+ if (this.existingNodeInsertableIntoLink) {
656
+ const link = this.ren.getLinkAtMousePos(d3Event.sourceEvent.clientX, d3Event.sourceEvent.clientY);
657
+ // Set highlighting when there is no link because this will turn
658
+ // current highlighting off. And only switch on highlighting when we are
659
+ // over a fully attached link (not a detached link) and provided the
660
+ // link is not to/from the node being dragged (which is possible in
661
+ // some odd situations).
662
+ if (!link ||
663
+ (this.ren.isLinkFullyAttached(link) &&
664
+ this.draggingObjectData.dragObjects[0].id !== link.srcNodeId &&
665
+ this.draggingObjectData.dragObjects[0].id !== link.trgNodeId)) {
666
+ this.ren.setInsertNodeIntoLinkHighlighting(link);
667
+ }
668
+ }
669
+
670
+ if (this.existingNodeAttachableToDetachedLinks) {
671
+ // const mousePos = this.ren.getTransformedMousePos(d3Event);
672
+ const node = this.draggingObjectData.dragObjects[0];
673
+ const ghostArea = {
674
+ x1: node.x_pos,
675
+ y1: node.y_pos,
676
+ x2: node.x_pos + node.width,
677
+ y2: node.y_pos + node.height
678
+ };
679
+ const links = this.ren.getAttachableLinksForNodeAtPos(node, ghostArea);
680
+ this.ren.setDetachedLinkHighlighting(links);
681
+ }
682
+ }
683
+
684
+ // Ends the dragging action for canvas objects (nodes and comments).
685
+ dragObjectsEnd(d3Event, d) {
686
+ // Save a local reference to this.draggingObjectData so we can set it to null before
687
+ // calling the canvas-controller. This means the this.draggingObjectData object will
688
+ // be null when the canvas is refreshed.
689
+ const draggingObjectData = this.draggingObjectData;
690
+ this.draggingObjectData = null;
691
+
692
+ // Cancels the styling of insertable/attachable nodes if the user releases
693
+ // the mouse button with 200 milliseconds of pressing it on the node. This
694
+ // stops the node flashing when the user just selects the node.
695
+ clearTimeout(this.startNodeInsertingInLink);
696
+ clearTimeout(this.startNodeAttachingToDetachedLinks);
697
+
698
+ // If the pointer hasn't moved and enableDragWithoutSelect is enabled we interpret
699
+ // that as a select on the object.
700
+ if (draggingObjectData.dragOffsetX === 0 &&
701
+ draggingObjectData.dragOffsetY === 0 &&
702
+ this.ren.config.enableDragWithoutSelect) {
703
+ this.ren.selectObjectSourceEvent(d3Event, d);
704
+
705
+ } else {
706
+ if (draggingObjectData.dragRunningX !== 0 ||
707
+ draggingObjectData.dragRunningY !== 0) {
708
+ let dragFinalOffset = null;
709
+ if (this.ren.config.enableSnapToGridType === SNAP_TO_GRID_AFTER) {
710
+ const stgPos = this.snapToGridDraggedNode(draggingObjectData);
711
+ dragFinalOffset = {
712
+ x: stgPos.x - draggingObjectData.dragStartX,
713
+ y: stgPos.y - draggingObjectData.dragStartY
714
+ };
715
+ } else {
716
+ dragFinalOffset = { x: draggingObjectData.dragRunningX, y: draggingObjectData.dragRunningY };
717
+ }
718
+
719
+ if (this.existingNodeInsertableIntoLink &&
720
+ this.ren.dragOverLink) {
721
+ this.ren.canvasController.editActionHandler({
722
+ editType: "insertNodeIntoLink",
723
+ editSource: "canvas",
724
+ node: draggingObjectData.dragObjects[0],
725
+ link: this.ren.dragOverLink,
726
+ offsetX: dragFinalOffset.x,
727
+ offsetY: dragFinalOffset.y,
728
+ pipelineId: this.ren.activePipeline.id });
729
+
730
+ } else if (this.existingNodeAttachableToDetachedLinks &&
731
+ this.ren.dragOverDetachedLinks.length > 0) {
732
+ this.ren.canvasController.editActionHandler({
733
+ editType: "attachNodeToLinks",
734
+ editSource: "canvas",
735
+ node: draggingObjectData.dragObjects[0],
736
+ detachedLinks: this.ren.dragOverDetachedLinks,
737
+ offsetX: dragFinalOffset.x,
738
+ offsetY: dragFinalOffset.y,
739
+ pipelineId: this.ren.activePipeline.id });
740
+
741
+ } else {
742
+ this.ren.canvasController.editActionHandler({
743
+ editType: "moveObjects",
744
+ editSource: "canvas",
745
+ nodes: draggingObjectData.dragObjects.map((o) => o.id),
746
+ links: this.ren.activePipeline.getSelectedDetachedLinks(),
747
+ offsetX: dragFinalOffset.x,
748
+ offsetY: dragFinalOffset.y,
749
+ pipelineId: this.ren.activePipeline.id });
750
+ }
751
+ }
752
+ }
753
+
754
+ // Switch off any drag highlighting
755
+ this.ren.setDataLinkSelectionAreaWider(false);
756
+ this.unsetNodeTranslucentState(draggingObjectData.dragObjects);
757
+ this.ren.unsetInsertNodeIntoLinkHighlighting();
758
+ this.ren.unsetDetachedLinkHighlighting();
759
+ }
760
+
761
+ // Returns an array of objects to drag. If enableDragWithoutSelect is true,
762
+ // and the object on which this drag start has initiated is not in the
763
+ // set of selected objects, then just that object is to be dragged. Otherwise,
764
+ // the selected objects are the objects to be dragged.
765
+ getDragObjects(d) {
766
+ const selectedObjects = this.ren.activePipeline.getSelectedNodesAndComments();
767
+
768
+ if (this.ren.config.enableDragWithoutSelect &&
769
+ selectedObjects.findIndex((o) => o.id === d.id) === -1) {
770
+ return [d];
771
+ }
772
+
773
+ return selectedObjects;
774
+ }
775
+
776
+ // Returns true if the current drag objects array has a single node which
777
+ // is 'insertable' into a data link between nodes on the canvas. Returns
778
+ // false otherwise, including if a single comment is being dragged.
779
+ isExistingNodeInsertableIntoLink() {
780
+ return (this.ren.config.enableInsertNodeDroppedOnLink &&
781
+ this.draggingObjectData.dragObjects.length === 1 &&
782
+ CanvasUtils.isNode(this.draggingObjectData.dragObjects[0]) &&
783
+ CanvasUtils.hasInputAndOutputPorts(this.draggingObjectData.dragObjects[0]) &&
784
+ !CanvasUtils.isNodeDefaultPortsCardinalityAtMax(this.draggingObjectData.dragObjects[0], this.ren.activePipeline.links));
785
+ }
786
+
787
+ // Returns true if the current drag objects array has a single node which
788
+ // is 'attachable' to any detached link on the canvas. Returns false otherwise,
789
+ // including if a single comment is being dragged.
790
+ isExistingNodeAttachableToDetachedLinks() {
791
+ return (this.ren.config.enableLinkSelection === LINK_SELECTION_DETACHABLE &&
792
+ this.draggingObjectData.dragObjects.length === 1 &&
793
+ CanvasUtils.isNode(this.draggingObjectData.dragObjects[0]));
794
+ }
795
+
796
+ // Switches on or off the translucent state of the node identified by the
797
+ // node ID passed in. This is used when an 'insertable' node is dragged on
798
+ // the canvas. It makes is easier for the user to see the highlighted link
799
+ // when the node is dragged over it.
800
+ setNodeTranslucentState(nodeId, state) {
801
+ this.ren.getNodeGroupSelectionById(nodeId).classed("d3-node-group-translucent", state);
802
+ }
803
+
804
+ // Switched off the translucent state of the objects being dragged (if
805
+ // there are any).
806
+ unsetNodeTranslucentState(dragObjects) {
807
+ if (dragObjects?.length > 0) {
808
+ this.setNodeTranslucentState(dragObjects[0].id, false);
809
+ }
810
+ }
811
+
812
+ // Returns the snap-to-grid position of the object positioned at
813
+ // this.draggingObjectData.dragStartX and this.draggingObjectData.dragStartY after applying the current offset of
814
+ // this.draggingObjectData.dragOffsetX and this.draggingObjectData.dragOffsetY.
815
+ snapToGridDraggedNode(draggingObjectData) {
816
+ const objPosX = draggingObjectData.dragStartX + draggingObjectData.dragOffsetX;
817
+ const objPosY = draggingObjectData.dragStartY + draggingObjectData.dragOffsetY;
818
+
819
+ return this.ren.snapToGridPosition({ x: objPosX, y: objPosY });
820
+ }
821
+
822
+ // Returns the object passed in with its position and size snapped to
823
+ // the current grid dimensions. Used when the object is being resized.
824
+ snapToGridObject(inResizeObj) {
825
+ const resizeObj = inResizeObj;
826
+ resizeObj.x_pos = CanvasUtils.snapToGrid(resizeObj.x_pos, this.ren.canvasLayout.snapToGridXPx);
827
+ resizeObj.y_pos = CanvasUtils.snapToGrid(resizeObj.y_pos, this.ren.canvasLayout.snapToGridYPx);
828
+ resizeObj.width = CanvasUtils.snapToGrid(resizeObj.width, this.ren.canvasLayout.snapToGridXPx);
829
+ resizeObj.height = CanvasUtils.snapToGrid(resizeObj.height, this.ren.canvasLayout.snapToGridYPx);
830
+ return resizeObj;
831
+ }
832
+ }