@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.
- package/dist/canvas-constants-766c12a9.js +2 -0
- package/dist/{canvas-constants-85883d4c.js.map → canvas-constants-766c12a9.js.map} +1 -1
- package/dist/canvas-constants-f4219d26.js +2 -0
- package/dist/{canvas-constants-d8652829.js.map → canvas-constants-f4219d26.js.map} +1 -1
- package/dist/canvas-controller-62b66fc8.js +2 -0
- package/dist/canvas-controller-62b66fc8.js.map +1 -0
- package/dist/canvas-controller-76f68572.js +2 -0
- package/dist/canvas-controller-76f68572.js.map +1 -0
- package/dist/common-canvas-339584b8.js +2 -0
- package/dist/common-canvas-339584b8.js.map +1 -0
- package/dist/common-canvas-c728f092.js +2 -0
- package/dist/common-canvas-c728f092.js.map +1 -0
- package/dist/common-canvas.es.js +1 -1
- package/dist/common-canvas.es.js.map +1 -1
- package/dist/common-canvas.js +1 -1
- package/dist/common-canvas.js.map +1 -1
- package/dist/common-properties-009d29d6.js +2 -0
- package/dist/{common-properties-a34905c3.js.map → common-properties-009d29d6.js.map} +1 -1
- package/dist/common-properties-99d34523.js +2 -0
- package/dist/{common-properties-d5775a12.js.map → common-properties-99d34523.js.map} +1 -1
- package/dist/context-menu-wrapper-624a1e7c.js +2 -0
- package/dist/context-menu-wrapper-624a1e7c.js.map +1 -0
- package/dist/context-menu-wrapper-ab018d6e.js +2 -0
- package/dist/context-menu-wrapper-ab018d6e.js.map +1 -0
- package/dist/{datarecord-metadata-v3-schema-531c7b07.js → datarecord-metadata-v3-schema-1f21696a.js} +2 -2
- package/dist/{datarecord-metadata-v3-schema-531c7b07.js.map → datarecord-metadata-v3-schema-1f21696a.js.map} +1 -1
- package/dist/{datarecord-metadata-v3-schema-28d4d7bb.js → datarecord-metadata-v3-schema-c2ad8862.js} +2 -2
- package/dist/{datarecord-metadata-v3-schema-28d4d7bb.js.map → datarecord-metadata-v3-schema-c2ad8862.js.map} +1 -1
- package/dist/flexible-table-4cf19e2e.js +2 -0
- package/dist/flexible-table-4cf19e2e.js.map +1 -0
- package/dist/flexible-table-8d10f5c9.js +2 -0
- package/dist/flexible-table-8d10f5c9.js.map +1 -0
- package/dist/{icon-909437d7.js → icon-5e06bfe1.js} +2 -2
- package/dist/{icon-909437d7.js.map → icon-5e06bfe1.js.map} +1 -1
- package/dist/{icon-de9c6b33.js → icon-8433d369.js} +2 -2
- package/dist/{icon-de9c6b33.js.map → icon-8433d369.js.map} +1 -1
- package/dist/{index-9960d3bf.js → index-2a61be58.js} +2 -2
- package/dist/{index-9960d3bf.js.map → index-2a61be58.js.map} +1 -1
- package/dist/{index-61e4a113.js → index-9a355ed6.js} +2 -2
- package/dist/{index-61e4a113.js.map → index-9a355ed6.js.map} +1 -1
- package/dist/lib/canvas-controller.es.js +1 -1
- package/dist/lib/canvas-controller.js +1 -1
- package/dist/lib/canvas.es.js +1 -1
- package/dist/lib/canvas.js +1 -1
- package/dist/lib/context-menu.es.js +1 -1
- package/dist/lib/context-menu.js +1 -1
- package/dist/lib/properties/field-picker.es.js +1 -1
- package/dist/lib/properties/field-picker.js +1 -1
- package/dist/lib/properties/flexible-table.es.js +1 -1
- package/dist/lib/properties/flexible-table.js +1 -1
- package/dist/lib/properties.es.js +1 -1
- package/dist/lib/properties.js +1 -1
- package/dist/styles/common-canvas.min.css +1 -1
- package/dist/styles/common-canvas.min.css.map +1 -1
- package/dist/{toolbar-cdb38f4a.js → toolbar-76733735.js} +2 -2
- package/dist/{toolbar-cdb38f4a.js.map → toolbar-76733735.js.map} +1 -1
- package/dist/{toolbar-3b5a592c.js → toolbar-85e1e463.js} +2 -2
- package/dist/{toolbar-3b5a592c.js.map → toolbar-85e1e463.js.map} +1 -1
- package/locales/common-canvas/locales/en.json +1 -1
- package/locales/common-canvas/locales/eo.json +1 -1
- package/package.json +2 -3
- package/src/common-canvas/canvas-controller.js +7 -0
- package/src/common-canvas/cc-contents.jsx +42 -4
- package/src/common-canvas/common-canvas-utils.js +9 -2
- package/src/common-canvas/common-canvas.scss +30 -3
- package/src/common-canvas/constants/canvas-constants.js +0 -6
- package/src/common-canvas/svg-canvas-d3.js +1 -3
- package/src/common-canvas/svg-canvas-d3.scss +0 -26
- package/src/common-canvas/svg-canvas-pipeline.js +6 -0
- package/src/common-canvas/svg-canvas-renderer.js +488 -2815
- package/src/common-canvas/svg-canvas-utils-drag-det-link.js +491 -0
- package/src/common-canvas/svg-canvas-utils-drag-new-link.js +595 -0
- package/src/common-canvas/svg-canvas-utils-drag-objects.js +832 -0
- package/src/common-canvas/svg-canvas-utils-external.js +82 -16
- package/src/common-canvas/svg-canvas-utils-zoom.js +780 -0
- package/src/context-menu/common-context-menu.jsx +57 -26
- package/src/context-menu/context-menu.scss +33 -53
- package/src/notification-panel/notification-panel.jsx +6 -1
- package/src/notification-panel/notification-panel.scss +4 -2
- package/src/palette/palette-content-list-item.jsx +23 -7
- package/stats.html +1 -1
- package/dist/canvas-constants-85883d4c.js +0 -2
- package/dist/canvas-constants-d8652829.js +0 -2
- package/dist/canvas-controller-7beb80ec.js +0 -2
- package/dist/canvas-controller-7beb80ec.js.map +0 -1
- package/dist/canvas-controller-b70d0f98.js +0 -2
- package/dist/canvas-controller-b70d0f98.js.map +0 -1
- package/dist/common-canvas-86fb7d21.js +0 -2
- package/dist/common-canvas-86fb7d21.js.map +0 -1
- package/dist/common-canvas-a6bfce5e.js +0 -2
- package/dist/common-canvas-a6bfce5e.js.map +0 -1
- package/dist/common-properties-a34905c3.js +0 -2
- package/dist/common-properties-d5775a12.js +0 -2
- package/dist/context-menu-wrapper-19a1cf72.js +0 -2
- package/dist/context-menu-wrapper-19a1cf72.js.map +0 -1
- package/dist/context-menu-wrapper-c3a98c63.js +0 -2
- package/dist/context-menu-wrapper-c3a98c63.js.map +0 -1
- package/dist/extends-093996c9.js +0 -2
- package/dist/extends-093996c9.js.map +0 -1
- package/dist/extends-1b35a664.js +0 -2
- package/dist/extends-1b35a664.js.map +0 -1
- package/dist/flexible-table-b9c08069.js +0 -2
- package/dist/flexible-table-b9c08069.js.map +0 -1
- package/dist/flexible-table-ddd6132b.js +0 -2
- package/dist/flexible-table-ddd6132b.js.map +0 -1
|
@@ -0,0 +1,780 @@
|
|
|
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 d3Selection from "d3-selection";
|
|
20
|
+
import * as d3Zoom from "./d3-zoom-extension/src";
|
|
21
|
+
const d3 = Object.assign({}, d3Selection, d3Zoom);
|
|
22
|
+
|
|
23
|
+
import Logger from "../logging/canvas-logger.js";
|
|
24
|
+
import CanvasUtils from "./common-canvas-utils.js";
|
|
25
|
+
import { INTERACTION_CARBON, INTERACTION_MOUSE, INTERACTION_TRACKPAD }
|
|
26
|
+
from "./constants/canvas-constants.js";
|
|
27
|
+
|
|
28
|
+
// This utility file provides a d3-zoom handler which manages zoom operations
|
|
29
|
+
// on the canvas as well as various utility functions to handle zoom behavior.
|
|
30
|
+
|
|
31
|
+
export default class SVGCanvasUtilsZoom {
|
|
32
|
+
|
|
33
|
+
constructor(renderer) {
|
|
34
|
+
this.ren = renderer;
|
|
35
|
+
|
|
36
|
+
this.logger = new Logger("SVGCanvasUtilsZoom");
|
|
37
|
+
|
|
38
|
+
// Dimensions for extent of canvas scaling
|
|
39
|
+
this.minScaleExtent = 0.2;
|
|
40
|
+
this.maxScaleExtent = 1.8;
|
|
41
|
+
|
|
42
|
+
// Keep track of when the context menu has been closed, so we don't remove
|
|
43
|
+
// selections when a context menu is closed during a zoom gesture.
|
|
44
|
+
this.contextMenuClosedOnZoom = false;
|
|
45
|
+
|
|
46
|
+
// Keep track of when text editing has been closed, so we don't remove
|
|
47
|
+
// selections when that happens during a zoom gesture.
|
|
48
|
+
this.textEditingClosedOnZoom = false;
|
|
49
|
+
|
|
50
|
+
// Used to monitor the region selection rectangle.
|
|
51
|
+
this.regionSelect = false;
|
|
52
|
+
|
|
53
|
+
// Used to track the start of the zoom.
|
|
54
|
+
this.zoomStartPoint = { x: 0, y: 0, k: 0, startX: 0, startY: 0 };
|
|
55
|
+
|
|
56
|
+
// Stores the previous events from D3 so we can calculate zoom increment amounts.
|
|
57
|
+
this.previousD3Event = {};
|
|
58
|
+
|
|
59
|
+
// Stores the dimensions of the canvas to save recalculating the size on
|
|
60
|
+
// each zoom increment.
|
|
61
|
+
this.zoomCanvasDimensions = {};
|
|
62
|
+
|
|
63
|
+
// I was not able to figure out how to use the zoom filter method to
|
|
64
|
+
// allow mousedown and mousemove messages to go through to the canvas to
|
|
65
|
+
// do region selection. Therefore I had to implement region selection in
|
|
66
|
+
// the zoom methods. This has the side effect that, when a region is
|
|
67
|
+
// selected, d3Event.transform.x and d3Event.transform.y are incremented
|
|
68
|
+
// even though the objects in the canvas have not moved. The values below
|
|
69
|
+
// are used to store the current transform x and y amounts at the beginning
|
|
70
|
+
// of the region selection and then restore those amounts at the end of
|
|
71
|
+
// the region selection.
|
|
72
|
+
this.regionStartTransformX = 0;
|
|
73
|
+
this.regionStartTransformY = 0;
|
|
74
|
+
|
|
75
|
+
// Stores the current zoom transform amounts.
|
|
76
|
+
this.zoomTransform = d3.zoomIdentity.translate(0, 0).scale(1);
|
|
77
|
+
|
|
78
|
+
// Flag to indicate when a zoom handled by zoomHandler is hapening.
|
|
79
|
+
this.zooming = false;
|
|
80
|
+
|
|
81
|
+
// Flag to indicate when a zoom is invoked programmatically.
|
|
82
|
+
this.zoomingAction = false;
|
|
83
|
+
|
|
84
|
+
// Flag to indicate when the space key is down (used when dragging).
|
|
85
|
+
this.spaceKeyPressed = false;
|
|
86
|
+
|
|
87
|
+
// Create a zoom handler for use with the canvas.
|
|
88
|
+
this.zoomHandler =
|
|
89
|
+
d3.zoom()
|
|
90
|
+
.trackpad(this.ren.config.enableInteractionType === INTERACTION_TRACKPAD)
|
|
91
|
+
.preventBackGesture(true)
|
|
92
|
+
.wheelDelta((d3Event) => -d3Event.deltaY * (this.ren.config.enableInteractionType === INTERACTION_TRACKPAD ? 0.02 : 0.002))
|
|
93
|
+
.scaleExtent([this.minScaleExtent, this.maxScaleExtent])
|
|
94
|
+
.on("start", this.zoomStart.bind(this))
|
|
95
|
+
.on("zoom", this.zoomAction.bind(this))
|
|
96
|
+
.on("end", this.zoomEnd.bind(this));
|
|
97
|
+
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Saves the state when the user presses and holds the space bar. This
|
|
101
|
+
// can be used for gestures that require the space bar to be held down.
|
|
102
|
+
setSpaceKeyPressed(state) {
|
|
103
|
+
this.spaceKeyPressed = state;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Returns true if the space bar is pressed and held down.
|
|
107
|
+
isSpaceKeyPressed() {
|
|
108
|
+
return this.spaceKeyPressed;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Returns the dragObjectsHandler
|
|
112
|
+
getZoomHandler() {
|
|
113
|
+
return this.zoomHandler;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Returns the zoom transform object.
|
|
117
|
+
getZoomTransform() {
|
|
118
|
+
return this.zoomTransform;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Returns a copy of the zoom transform object.
|
|
122
|
+
getZoom() {
|
|
123
|
+
return { ...this.zoomTransform };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
getZoomScale() {
|
|
127
|
+
return this.zoomTransform.k;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Resets the local zoom transform object to the default (identity) zoom.
|
|
131
|
+
resetZoomTransform() {
|
|
132
|
+
this.zoomTransform = d3.zoomIdentity.translate(0, 0).scale(1);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Zooms the canvas to the extent specified in the zoom object.
|
|
136
|
+
zoomTo(zoomObject) {
|
|
137
|
+
const animateTime = 500;
|
|
138
|
+
this.zoomCanvasInvokeZoomBehavior(zoomObject, animateTime);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Pans the canvas by the x and y amount specified in the time specified.
|
|
142
|
+
translateBy(x, y, animateTime) {
|
|
143
|
+
const z = this.getZoomTransform();
|
|
144
|
+
const zoomObject = d3.zoomIdentity.translate(z.x + x, z.y + y).scale(z.k);
|
|
145
|
+
this.zoomCanvasInvokeZoomBehavior(zoomObject, animateTime);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Zooms in the canvas by an increment amount.
|
|
149
|
+
zoomIn() {
|
|
150
|
+
if (this.zoomTransform.k < this.maxScaleExtent) {
|
|
151
|
+
const newScale = Math.min(this.zoomTransform.k * 1.1, this.maxScaleExtent);
|
|
152
|
+
this.ren.canvasSVG.call(this.zoomHandler.scaleTo, newScale);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Zooms out the canvas by an increment amount.
|
|
157
|
+
zoomOut() {
|
|
158
|
+
if (this.zoomTransform.k > this.minScaleExtent) {
|
|
159
|
+
const newScale = Math.max(this.zoomTransform.k / 1.1, this.minScaleExtent);
|
|
160
|
+
this.ren.canvasSVG.call(this.zoomHandler.scaleTo, newScale);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Returns true if the canvas is currently zoomed to the maximum amount.
|
|
165
|
+
isZoomedToMax() {
|
|
166
|
+
return this.zoomTransform ? this.zoomTransform.k === this.maxScaleExtent : false;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Returns true if the canvas is currently zoomed to the minimum amount.
|
|
170
|
+
isZoomedToMin() {
|
|
171
|
+
return this.zoomTransform ? this.zoomTransform.k === this.minScaleExtent : false;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Sets the maximum zoom extent by multiplying the current extent by
|
|
175
|
+
// the factor passed in.
|
|
176
|
+
setMaxZoomExtent(factor) {
|
|
177
|
+
// Don't allow the scale extent to be changed while in the middle of a
|
|
178
|
+
// zoom operation.
|
|
179
|
+
if (this.zooming) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const newMaxExtent = this.maxScaleExtent * factor;
|
|
183
|
+
this.zoomHandler = this.zoomHandler.scaleExtent([this.minScaleExtent, newMaxExtent]);
|
|
184
|
+
this.ren.resetCanvasSVGBehaviors();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Transforms the x and y fields passed in by the current zoom
|
|
188
|
+
// transformation amounts to convert a coordinate position in screen pixels
|
|
189
|
+
// to a canvas coordinate position.
|
|
190
|
+
transformPos(pos) {
|
|
191
|
+
return {
|
|
192
|
+
x: (pos.x - this.zoomTransform.x) / this.zoomTransform.k,
|
|
193
|
+
y: (pos.y - this.zoomTransform.y) / this.zoomTransform.k
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Transforms the x and y fields passed in by the current zoom
|
|
198
|
+
// transformation amounts to convert a canvas coordinate position
|
|
199
|
+
// to a coordinate position in screen pixels.
|
|
200
|
+
unTransformPos(pos) {
|
|
201
|
+
return {
|
|
202
|
+
x: (pos.x * this.zoomTransform.k) + this.zoomTransform.x,
|
|
203
|
+
y: (pos.y * this.zoomTransform.k) + this.zoomTransform.y
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Transforms the x, y, height and width fields of the object passed in by the
|
|
208
|
+
// current zoom transformation amounts to convert coordinate positions and
|
|
209
|
+
// dimensions in screen pixels to coordinate positions and dimensions in
|
|
210
|
+
// zoomed pixels.
|
|
211
|
+
getTransformedRect(svgRect, pad) {
|
|
212
|
+
const transPad = (pad / this.zoomTransform.k);
|
|
213
|
+
return {
|
|
214
|
+
x: (-this.zoomTransform.x / this.zoomTransform.k) + transPad,
|
|
215
|
+
y: (-this.zoomTransform.y / this.zoomTransform.k) + transPad,
|
|
216
|
+
height: (svgRect.height / this.zoomTransform.k) - (2 * transPad),
|
|
217
|
+
width: (svgRect.width / this.zoomTransform.k) - (2 * transPad)
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Handles the beginning of a zoom action
|
|
222
|
+
zoomStart(d3Event) {
|
|
223
|
+
this.logger.log("zoomStart - " + JSON.stringify(d3Event.transform));
|
|
224
|
+
|
|
225
|
+
// Ensure any open tip is closed before starting a zoom operation.
|
|
226
|
+
this.ren.canvasController.closeTip();
|
|
227
|
+
|
|
228
|
+
this.zooming = true;
|
|
229
|
+
|
|
230
|
+
// Close the context menu, if it's open, before panning or zooming.
|
|
231
|
+
// If the context menu is opened inside the expanded supernode (in-place
|
|
232
|
+
// subflow), when the user zooms the canvas, the full page flow is handling
|
|
233
|
+
// that zoom, which causes a refresh in the subflow, so the full page flow
|
|
234
|
+
// will take care of closing the context menu. This means the in-place
|
|
235
|
+
// subflow doesn’t need to do anything on zoom,
|
|
236
|
+
// hence: !this.ren.dispUtils.isDisplayingSubFlowInPlace()
|
|
237
|
+
if (this.ren.canvasController.isContextMenuDisplayed() &&
|
|
238
|
+
!this.ren.dispUtils.isDisplayingSubFlowInPlace()) {
|
|
239
|
+
this.ren.canvasController.closeContextMenu();
|
|
240
|
+
this.contextMenuClosedOnZoom = true;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Any text editing in progress will be closed by the textarea's blur event
|
|
244
|
+
// if the user clicks on the canvas background. So we set this flag to
|
|
245
|
+
// prevent the selection being lost in the zoomEnd (mouseup) event.
|
|
246
|
+
if (this.ren.svgCanvasTextArea.isEditingText()) {
|
|
247
|
+
this.textEditingClosedOnZoom = true;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
this.regionSelect = this.isRegionSelectActivated(d3Event);
|
|
251
|
+
|
|
252
|
+
if (this.regionSelect) {
|
|
253
|
+
// Add a delay so, if the user just clicks, they don't see the crosshair.
|
|
254
|
+
// This will be cleared in zoomEnd if the user's click takes less than 200 ms.
|
|
255
|
+
this.addingCursorOverlay = setTimeout(() => this.ren.addTempCursorOverlay("crosshair"), 200);
|
|
256
|
+
this.regionStartTransformX = d3Event.transform.x;
|
|
257
|
+
this.regionStartTransformY = d3Event.transform.y;
|
|
258
|
+
|
|
259
|
+
} else {
|
|
260
|
+
if (this.isDragActivated(d3Event)) {
|
|
261
|
+
this.addingCursorOverlay = setTimeout(() => this.ren.addTempCursorOverlay("grabbing"), 200);
|
|
262
|
+
} else {
|
|
263
|
+
this.addingCursorOverlay = setTimeout(() => this.ren.addTempCursorOverlay("default"), 200);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const transPos = this.ren.getTransformedMousePos(d3Event);
|
|
268
|
+
this.zoomStartPoint = { x: d3Event.transform.x, y: d3Event.transform.y, k: d3Event.transform.k, startX: transPos.x, startY: transPos.y };
|
|
269
|
+
this.previousD3Event = { ...d3Event.transform };
|
|
270
|
+
|
|
271
|
+
// Store the canvas dimensions so we don't have to recalculate
|
|
272
|
+
// them for every zoom action event.
|
|
273
|
+
this.zoomCanvasDimensions = this.getCanvasDimensions();
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Handles each increment of a zoom action
|
|
277
|
+
zoomAction(d3Event) {
|
|
278
|
+
this.logger.log("zoomAction - " + JSON.stringify(d3Event.transform));
|
|
279
|
+
|
|
280
|
+
// If the scale amount is the same we are not zooming, so we must be panning.
|
|
281
|
+
if (d3Event.transform.k === this.zoomStartPoint.k) {
|
|
282
|
+
if (this.regionSelect) {
|
|
283
|
+
this.drawRegionSelector(d3Event);
|
|
284
|
+
|
|
285
|
+
} else {
|
|
286
|
+
this.zoomCanvasBackground(d3Event);
|
|
287
|
+
}
|
|
288
|
+
} else {
|
|
289
|
+
this.ren.addTempCursorOverlay("default");
|
|
290
|
+
this.zoomCanvasBackground(d3Event);
|
|
291
|
+
this.ren.repositionCommentToolbar();
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Handles the end of a zoom action
|
|
296
|
+
zoomEnd(d3Event) {
|
|
297
|
+
this.logger.log("zoomEnd - " + JSON.stringify(d3Event.transform));
|
|
298
|
+
|
|
299
|
+
// Clears the display of the cursor overlay if the user clicks within 200 ms
|
|
300
|
+
clearTimeout(this.addingCursorOverlay);
|
|
301
|
+
|
|
302
|
+
const transPos = this.ren.getTransformedMousePos(d3Event);
|
|
303
|
+
|
|
304
|
+
// The user just clicked -- with no drag.
|
|
305
|
+
if (transPos.x === this.zoomStartPoint.startX &&
|
|
306
|
+
transPos.y === this.zoomStartPoint.startY &&
|
|
307
|
+
!this.zoomChanged()) {
|
|
308
|
+
this.zoomClick(d3Event);
|
|
309
|
+
|
|
310
|
+
} else if (this.regionSelect) {
|
|
311
|
+
this.zoomEndRegionSelect(d3Event);
|
|
312
|
+
|
|
313
|
+
} else if (this.ren.dispUtils.isDisplayingFullPage() && this.zoomChanged()) {
|
|
314
|
+
this.zoomSave();
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Remove the cursor overlay and reset the SVG background rectangle
|
|
318
|
+
// cursor style, which was set in the zoom start method.
|
|
319
|
+
this.ren.resetCanvasCursor(d3Event);
|
|
320
|
+
this.ren.removeTempCursorOverlay();
|
|
321
|
+
this.contextMenuClosedOnZoom = false;
|
|
322
|
+
this.textEditingClosedOnZoom = false;
|
|
323
|
+
this.regionSelect = false;
|
|
324
|
+
this.zooming = false;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Returns true if the current zoom transform is different from the
|
|
328
|
+
// zoom values at the beginning of the zoom action.
|
|
329
|
+
zoomChanged() {
|
|
330
|
+
return (this.zoomTransform.k !== this.zoomStartPoint.k ||
|
|
331
|
+
this.zoomTransform.x !== this.zoomStartPoint.x ||
|
|
332
|
+
this.zoomTransform.y !== this.zoomStartPoint.y);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Returns true if the event indicates that a drag (rather than a region
|
|
336
|
+
// select) is in action. This means that, with the Carbon interation
|
|
337
|
+
// option the space bar is pressed or with legacy interation the
|
|
338
|
+
// shift key is NOT pressed.
|
|
339
|
+
isDragActivated(d3Event) {
|
|
340
|
+
if (this.ren.config.enableInteractionType === INTERACTION_CARBON) {
|
|
341
|
+
return this.isSpaceKeyPressed();
|
|
342
|
+
}
|
|
343
|
+
return (d3Event && d3Event.sourceEvent && !d3Event.sourceEvent.shiftKey);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Returns true if the region select gesture is requested by the user.
|
|
347
|
+
isRegionSelectActivated(d3Event) {
|
|
348
|
+
// The this.zoomingAction flag indicates zooming is being invoked
|
|
349
|
+
// programmatically.
|
|
350
|
+
if (this.zoomingAction) {
|
|
351
|
+
return false;
|
|
352
|
+
|
|
353
|
+
} else if (this.ren.config.enableInteractionType === INTERACTION_MOUSE &&
|
|
354
|
+
(d3Event && d3Event.sourceEvent && d3Event.sourceEvent.shiftKey)) {
|
|
355
|
+
return true;
|
|
356
|
+
|
|
357
|
+
} else if (this.ren.config.enableInteractionType === INTERACTION_CARBON &&
|
|
358
|
+
!this.isSpaceKeyPressed()) {
|
|
359
|
+
return true;
|
|
360
|
+
|
|
361
|
+
} else if (this.ren.config.enableInteractionType === INTERACTION_TRACKPAD &&
|
|
362
|
+
(d3Event.sourceEvent && d3Event.sourceEvent.buttons === 1) && // Main button is pressed
|
|
363
|
+
!this.isSpaceKeyPressed()) {
|
|
364
|
+
return true;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
drawRegionSelector(d3Event) {
|
|
371
|
+
this.removeRegionSelector();
|
|
372
|
+
const { x, y, width, height } = this.getRegionDimensions(d3Event);
|
|
373
|
+
|
|
374
|
+
this.ren.canvasGrp
|
|
375
|
+
.append("rect")
|
|
376
|
+
.attr("width", width)
|
|
377
|
+
.attr("height", height)
|
|
378
|
+
.attr("x", x)
|
|
379
|
+
.attr("y", y)
|
|
380
|
+
.attr("class", "d3-region-selector");
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Handles the behavior when the user stops doing a region select.
|
|
384
|
+
zoomEndRegionSelect(d3Event) {
|
|
385
|
+
this.removeRegionSelector();
|
|
386
|
+
|
|
387
|
+
// Reset the transform x and y to what they were before the region
|
|
388
|
+
// selection action was started. This directly sets the x and y values
|
|
389
|
+
// in the __zoom property of the svgCanvas DOM object.
|
|
390
|
+
d3Event.transform.x = this.regionStartTransformX;
|
|
391
|
+
d3Event.transform.y = this.regionStartTransformY;
|
|
392
|
+
|
|
393
|
+
this.ren.selectObjsInRegion(
|
|
394
|
+
this.getRegionDimensions(d3Event));
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Removes the region selection graphic rectangle.
|
|
398
|
+
removeRegionSelector() {
|
|
399
|
+
this.ren.canvasGrp.selectAll(".d3-region-selector").remove();
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Returns the x, y, width and height of the selection region
|
|
403
|
+
// where x and y are always the top left corner of the region
|
|
404
|
+
// and width and height are therefore always positive.
|
|
405
|
+
getRegionDimensions(d3Event) {
|
|
406
|
+
const transPos = this.ren.getTransformedMousePos(d3Event);
|
|
407
|
+
let x = this.zoomStartPoint.startX;
|
|
408
|
+
let y = this.zoomStartPoint.startY;
|
|
409
|
+
let width = transPos.x - x;
|
|
410
|
+
let height = transPos.y - y;
|
|
411
|
+
|
|
412
|
+
if (width < 0) {
|
|
413
|
+
width = Math.abs(width);
|
|
414
|
+
x -= width;
|
|
415
|
+
}
|
|
416
|
+
if (height < 0) {
|
|
417
|
+
height = Math.abs(height);
|
|
418
|
+
y -= height;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return { x, y, width, height };
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Performs zoom behaviors for each incremental zoom action.
|
|
425
|
+
zoomCanvasBackground(d3Event) {
|
|
426
|
+
this.regionSelect = false;
|
|
427
|
+
|
|
428
|
+
if (this.ren.dispUtils.isDisplayingPrimaryFlowFullPage()) {
|
|
429
|
+
const incTransform = this.getTransformIncrement(d3Event);
|
|
430
|
+
this.zoomTransform = this.zoomConstrainRegular(incTransform, this.getViewportDimensions(), this.zoomCanvasDimensions);
|
|
431
|
+
} else {
|
|
432
|
+
this.zoomTransform = d3.zoomIdentity.translate(d3Event.transform.x, d3Event.transform.y).scale(d3Event.transform.k);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
this.ren.canvasGrp.attr("transform", this.zoomTransform);
|
|
436
|
+
|
|
437
|
+
this.ren.displayCanvasAccoutrements();
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Handles a zoom operation that is just a click on the canvas background.
|
|
441
|
+
zoomClick(d3Event) {
|
|
442
|
+
// Only clear selections under these conditions:
|
|
443
|
+
// * if the click was on the canvas of the current active pipeline. (This
|
|
444
|
+
// is because clicking on the canvas background of an expanded supernode
|
|
445
|
+
// should select that node.)
|
|
446
|
+
// * if we have not just closed a context menu
|
|
447
|
+
// * if we have not just closed text editing
|
|
448
|
+
// * if editing actions are enabled OR the target is the canvas background.
|
|
449
|
+
// (This condition is necessary because when editing actions are disabled,
|
|
450
|
+
// for a read-only canvas, the mouse-up over a node can cause this method
|
|
451
|
+
// to be called.)
|
|
452
|
+
if (this.ren.dispUtils.isDisplayingCurrentPipeline() &&
|
|
453
|
+
!this.contextMenuClosedOnZoom &&
|
|
454
|
+
!this.textEditingClosedOnZoom &&
|
|
455
|
+
(this.ren.config.enableEditingActions ||
|
|
456
|
+
(d3Event.sourceEvent?.target?.classList?.contains("d3-svg-background")))) {
|
|
457
|
+
this.ren.canvasController.clearSelections();
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Save the zoom amount. The canvas controller/object model will decide
|
|
462
|
+
// how this info is saved.
|
|
463
|
+
zoomSave() {
|
|
464
|
+
// Set the internal zoom value for canvasSVG used by D3. This will be
|
|
465
|
+
// used by d3Event next time a zoom action is initiated.
|
|
466
|
+
this.ren.canvasSVG.property("__zoom", this.zoomTransform);
|
|
467
|
+
|
|
468
|
+
const data = {
|
|
469
|
+
editType: "setZoom",
|
|
470
|
+
editSource: "canvas",
|
|
471
|
+
zoom: this.zoomTransform,
|
|
472
|
+
pipelineId: this.ren.activePipeline.id
|
|
473
|
+
};
|
|
474
|
+
this.ren.canvasController.editActionHandler(data);
|
|
475
|
+
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Returns a new zoom which is the result of incrementing the current zoom
|
|
479
|
+
// by the amount since the previous d3Event event.
|
|
480
|
+
// We calculate increments because d3Event.transform is not based on
|
|
481
|
+
// the constrained zoom position (which is very annoying) so we keep track
|
|
482
|
+
// of the current constraind zoom amount in this.zoomTransform.
|
|
483
|
+
getTransformIncrement(d3Event) {
|
|
484
|
+
const xInc = d3Event.transform.x - this.previousD3Event.x;
|
|
485
|
+
const yInc = d3Event.transform.y - this.previousD3Event.y;
|
|
486
|
+
|
|
487
|
+
const newTransform = { x: this.zoomTransform.x + xInc, y: this.zoomTransform.y + yInc, k: d3Event.transform.k };
|
|
488
|
+
this.previousD3Event = { ...d3Event.transform };
|
|
489
|
+
return newTransform;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Returns a modifed transform object so that the canvas area (the area
|
|
493
|
+
// containing nodes and comments) is constrained such that it never totally
|
|
494
|
+
// disappears from the view port.
|
|
495
|
+
zoomConstrainRegular(transform, viewPort, canvasDimensions) {
|
|
496
|
+
if (!canvasDimensions) {
|
|
497
|
+
return this.zoomTransform;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const k = transform.k;
|
|
501
|
+
let x = transform.x;
|
|
502
|
+
let y = transform.y;
|
|
503
|
+
|
|
504
|
+
const canv =
|
|
505
|
+
this.convertRectAdjustedForScaleWithPadding(canvasDimensions, k, this.getZoomToFitPadding());
|
|
506
|
+
|
|
507
|
+
const rightOffsetLimit = viewPort.width - Math.min((viewPort.width * 0.25), (canv.width * 0.25));
|
|
508
|
+
const leftOffsetLimit = -(Math.max((canv.width - (viewPort.width * 0.25)), (canv.width * 0.75)));
|
|
509
|
+
|
|
510
|
+
const bottomOffsetLimit = viewPort.height - Math.min((viewPort.height * 0.25), (canv.height * 0.25));
|
|
511
|
+
const topOffsetLimit = -(Math.max((canv.height - (viewPort.height * 0.25)), (canv.height * 0.75)));
|
|
512
|
+
|
|
513
|
+
if (x > -canv.left + rightOffsetLimit) {
|
|
514
|
+
x = -canv.left + rightOffsetLimit;
|
|
515
|
+
|
|
516
|
+
} else if (x < -canv.left + leftOffsetLimit) {
|
|
517
|
+
x = -canv.left + leftOffsetLimit;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (y > -canv.top + bottomOffsetLimit) {
|
|
521
|
+
y = -canv.top + bottomOffsetLimit;
|
|
522
|
+
|
|
523
|
+
} else if (y < -canv.top + topOffsetLimit) {
|
|
524
|
+
y = -canv.top + topOffsetLimit;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
return d3.zoomIdentity.translate(x, y).scale(k);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Restores the zoom of the canvas, if it has changed, based on the type
|
|
531
|
+
// of 'save zoom' specified in the configuration and, if no saved zoom, was
|
|
532
|
+
// provided pans the canvas area so it is always visible.
|
|
533
|
+
restoreZoom() {
|
|
534
|
+
let newZoom = this.ren.canvasController.getSavedZoom(this.ren.activePipeline.id);
|
|
535
|
+
|
|
536
|
+
// If there's no saved zoom, and enablePanIntoViewOnOpen is set, pan so
|
|
537
|
+
// the canvas area (containing nodes and comments) is visible in the viewport.
|
|
538
|
+
if (!newZoom && this.ren.config.enablePanIntoViewOnOpen) {
|
|
539
|
+
const canvWithPadding = this.getCanvasDimensionsWithPadding();
|
|
540
|
+
if (canvWithPadding) {
|
|
541
|
+
newZoom = { x: -canvWithPadding.left, y: -canvWithPadding.top, k: 1 };
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// If there's no saved zoom and we have some initial pan amounts provided use them.
|
|
546
|
+
if (!newZoom && this.ren.canvasLayout.initialPanX && this.ren.canvasLayout.initialPanY) {
|
|
547
|
+
newZoom = { x: this.ren.canvasLayout.initialPanX, y: this.ren.canvasLayout.initialPanY, k: 1 };
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// If new zoom is different to the current zoom amount, apply it.
|
|
551
|
+
if (newZoom &&
|
|
552
|
+
(newZoom.k !== this.zoomTransform.k ||
|
|
553
|
+
newZoom.x !== this.zoomTransform.x ||
|
|
554
|
+
newZoom.y !== this.zoomTransform.y)) {
|
|
555
|
+
this.zoomCanvasInvokeZoomBehavior(newZoom);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// Zooms the canvas to the amount specified in newZoomTransform. Zooming the
|
|
560
|
+
// canvas in this way will invoke the zoom behavior methods: zoomStart,
|
|
561
|
+
// zoomAction and zoomEnd. It does not perform a zoom if newZoomTransform
|
|
562
|
+
// is the same as the current zoom transform.
|
|
563
|
+
zoomCanvasInvokeZoomBehavior(newZoomTransform, animateTime) {
|
|
564
|
+
if (isFinite(newZoomTransform.x) &&
|
|
565
|
+
isFinite(newZoomTransform.y) &&
|
|
566
|
+
isFinite(newZoomTransform.k) &&
|
|
567
|
+
this.zoomHasChanged(newZoomTransform)) {
|
|
568
|
+
this.zoomingAction = true;
|
|
569
|
+
const zoomTransform = d3.zoomIdentity.translate(newZoomTransform.x, newZoomTransform.y).scale(newZoomTransform.k);
|
|
570
|
+
if (animateTime) {
|
|
571
|
+
this.ren.canvasSVG.call(this.zoomHandler).transition()
|
|
572
|
+
.duration(animateTime)
|
|
573
|
+
.call(this.zoomHandler.transform, zoomTransform);
|
|
574
|
+
} else {
|
|
575
|
+
this.ren.canvasSVG.call(this.zoomHandler.transform, zoomTransform);
|
|
576
|
+
}
|
|
577
|
+
this.zoomingAction = false;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// Return true if the new zoom transform passed in is different from the
|
|
582
|
+
// current zoom transform.
|
|
583
|
+
zoomHasChanged(newZoomTransform) {
|
|
584
|
+
return newZoomTransform.k !== this.zoomTransform.k ||
|
|
585
|
+
newZoomTransform.x !== this.zoomTransform.x ||
|
|
586
|
+
newZoomTransform.y !== this.zoomTransform.y;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// Zooms the canvas to fit in the current viewport.
|
|
590
|
+
zoomToFit() {
|
|
591
|
+
const canvasDimensions = this.getCanvasDimensionsWithPadding();
|
|
592
|
+
const viewPortDimensions = this.getViewportDimensions();
|
|
593
|
+
|
|
594
|
+
if (canvasDimensions) {
|
|
595
|
+
const xRatio = viewPortDimensions.width / canvasDimensions.width;
|
|
596
|
+
const yRatio = viewPortDimensions.height / canvasDimensions.height;
|
|
597
|
+
const newScale = Math.min(xRatio, yRatio, 1); // Don't let the canvas be scaled more than 1 in either direction
|
|
598
|
+
|
|
599
|
+
let x = (viewPortDimensions.width - (canvasDimensions.width * newScale)) / 2;
|
|
600
|
+
let y = (viewPortDimensions.height - (canvasDimensions.height * newScale)) / 2;
|
|
601
|
+
|
|
602
|
+
x -= newScale * canvasDimensions.left;
|
|
603
|
+
y -= newScale * canvasDimensions.top;
|
|
604
|
+
|
|
605
|
+
this.zoomCanvasInvokeZoomBehavior({ x: x, y: y, k: newScale });
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// Returns a zoom object that will, if applied to the canvas, zoom the objects
|
|
610
|
+
// dentified in the objectIDs array so their center is at the xPos, yPos
|
|
611
|
+
// position in the viewport.
|
|
612
|
+
getZoomToReveal(objectIDs, xPos, yPos) {
|
|
613
|
+
const transformedSVGRect = this.getTransformedViewportDimensions();
|
|
614
|
+
const nodes = this.ren.activePipeline.getNodes(objectIDs);
|
|
615
|
+
const comments = this.ren.activePipeline.getComments(objectIDs);
|
|
616
|
+
const links = this.ren.activePipeline.getLinks(objectIDs);
|
|
617
|
+
|
|
618
|
+
if (nodes.length > 0 || comments.length > 0 || links.length > 0) {
|
|
619
|
+
const canvasDimensions = CanvasUtils.getCanvasDimensions(nodes, comments, links, 0, 0, true);
|
|
620
|
+
const canv = this.convertRectAdjustedForScaleWithPadding(canvasDimensions, 1, 10);
|
|
621
|
+
const xPosInt = parseInt(xPos, 10);
|
|
622
|
+
const yPosInt = typeof yPos === "undefined" ? xPosInt : parseInt(yPos, 10);
|
|
623
|
+
|
|
624
|
+
if (canv) {
|
|
625
|
+
let xOffset;
|
|
626
|
+
let yOffset;
|
|
627
|
+
|
|
628
|
+
if (!Number.isNaN(xPosInt) && !Number.isNaN(yPosInt)) {
|
|
629
|
+
xOffset = transformedSVGRect.x + (transformedSVGRect.width * (xPosInt / 100)) - (canv.left + (canv.width / 2));
|
|
630
|
+
yOffset = transformedSVGRect.y + (transformedSVGRect.height * (yPosInt / 100)) - (canv.top + (canv.height / 2));
|
|
631
|
+
|
|
632
|
+
} else {
|
|
633
|
+
if (canv.right > transformedSVGRect.x + transformedSVGRect.width) {
|
|
634
|
+
xOffset = transformedSVGRect.x + transformedSVGRect.width - canv.right;
|
|
635
|
+
}
|
|
636
|
+
if (canv.left < transformedSVGRect.x) {
|
|
637
|
+
xOffset = transformedSVGRect.x - canv.left;
|
|
638
|
+
}
|
|
639
|
+
if (canv.bottom > transformedSVGRect.y + transformedSVGRect.height) {
|
|
640
|
+
yOffset = transformedSVGRect.y + transformedSVGRect.height - canv.bottom;
|
|
641
|
+
}
|
|
642
|
+
if (canv.top < transformedSVGRect.y) {
|
|
643
|
+
yOffset = transformedSVGRect.y - canv.top;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
if (typeof xOffset !== "undefined" || typeof yOffset !== "undefined") {
|
|
648
|
+
const x = this.zoomTransform.x + ((xOffset || 0)) * this.zoomTransform.k;
|
|
649
|
+
const y = this.zoomTransform.y + ((yOffset || 0)) * this.zoomTransform.k;
|
|
650
|
+
return { x: x || 0, y: y || 0, k: this.zoomTransform.k };
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
return null;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// Returns the maximum amount for padding, when zooming to fit the canvas
|
|
659
|
+
// objects within a subflow, to allow the connection lines to be displayed
|
|
660
|
+
// without them doubling back on themselves.
|
|
661
|
+
getMaxZoomToFitPaddingForConnections() {
|
|
662
|
+
const paddingForInputBinding = this.getMaxPaddingForConnectionsFromInputBindingNodes();
|
|
663
|
+
const paddingForOutputBinding = this.getMaxPaddingForConnectionsToOutputBindingNodes();
|
|
664
|
+
const padding = Math.max(paddingForInputBinding, paddingForOutputBinding);
|
|
665
|
+
return padding;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// Returns the maximum amount for padding, when zooming to fit the canvas
|
|
669
|
+
// objects within a subflow, to allow the connection lines (from input binding
|
|
670
|
+
// nodes to other sub-flow nodes) to be displayed without them doubling back
|
|
671
|
+
// on themselves.
|
|
672
|
+
getMaxPaddingForConnectionsFromInputBindingNodes() {
|
|
673
|
+
let maxPadding = 0;
|
|
674
|
+
const inputBindingNodes = this.ren.activePipeline.nodes.filter((n) => n.isSupernodeInputBinding);
|
|
675
|
+
|
|
676
|
+
inputBindingNodes.forEach((n) => {
|
|
677
|
+
const nodePadding = CanvasUtils.getNodePaddingToTargetNodes(n, this.ren.activePipeline.nodes,
|
|
678
|
+
this.ren.activePipeline.links, this.ren.canvasLayout.linkType);
|
|
679
|
+
maxPadding = Math.max(maxPadding, nodePadding);
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
return maxPadding;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// Returns the maximum amount for padding, when zooming to fit the canvas
|
|
686
|
+
// objects within a subflow, to allow the connection lines (from sub-flow nodes
|
|
687
|
+
// to output binding nodes) to be displayed without them doubling back
|
|
688
|
+
// on themselves.
|
|
689
|
+
getMaxPaddingForConnectionsToOutputBindingNodes() {
|
|
690
|
+
let maxPadding = 0;
|
|
691
|
+
const outputBindingNodes = this.ren.activePipeline.nodes.filter((n) => n.isSupernodeOutputBinding);
|
|
692
|
+
|
|
693
|
+
this.ren.activePipeline.nodes.forEach((n) => {
|
|
694
|
+
const nodePadding = CanvasUtils.getNodePaddingToTargetNodes(n, outputBindingNodes,
|
|
695
|
+
this.ren.activePipeline.links, this.ren.canvasLayout.linkType);
|
|
696
|
+
maxPadding = Math.max(maxPadding, nodePadding);
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
return maxPadding;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// Returns an object representing the viewport dimensions which have been
|
|
703
|
+
// transformed for the current zoom amount.
|
|
704
|
+
getTransformedViewportDimensions() {
|
|
705
|
+
const svgRect = this.getViewportDimensions();
|
|
706
|
+
return this.getTransformedRect(svgRect, 0);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// Returns the dimensions of the SVG area. When we are displaying a sub-flow
|
|
710
|
+
// we can use the supernode's dimensions. If not we are displaying
|
|
711
|
+
// full-page so we can use getBoundingClientRect() to get the dimensions
|
|
712
|
+
// (for some reason that method doesn't return correct values with embedded SVG areas).
|
|
713
|
+
getViewportDimensions() {
|
|
714
|
+
let viewportDimensions = {};
|
|
715
|
+
|
|
716
|
+
if (this.ren.dispUtils.isDisplayingSubFlowInPlace()) {
|
|
717
|
+
const dims = this.ren.getParentSupernodeSVGDimensions();
|
|
718
|
+
viewportDimensions.width = dims.width;
|
|
719
|
+
viewportDimensions.height = dims.height;
|
|
720
|
+
|
|
721
|
+
} else {
|
|
722
|
+
if (this.ren.canvasSVG && this.ren.canvasSVG.node()) {
|
|
723
|
+
viewportDimensions = this.ren.canvasSVG.node().getBoundingClientRect();
|
|
724
|
+
} else {
|
|
725
|
+
viewportDimensions = { x: 0, y: 0, width: 1100, height: 640 }; // Return a sensible default (for Jest tests)
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
return viewportDimensions;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// Returns the dimensions in SVG coordinates of the canvas area. This is
|
|
732
|
+
// based on the position and width and height of the nodes and comments. It
|
|
733
|
+
// does not include the 'super binding nodes' which are the binding nodes in
|
|
734
|
+
// a sub-flow that map to a port in the containing supernode. The dimensions
|
|
735
|
+
// include an appropriate padding amount.
|
|
736
|
+
getCanvasDimensionsWithPadding() {
|
|
737
|
+
return this.getCanvasDimensions(this.getZoomToFitPadding());
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// Returns the dimensions in SVG coordinates of the canvas area. This is
|
|
741
|
+
// based on the position and width and height of the nodes and comments. It
|
|
742
|
+
// does not include the 'super binding nodes' which are the binding nodes in
|
|
743
|
+
// a sub-flow that map to a port in the containing supernode. If a pad is
|
|
744
|
+
// provided, it is also added in to the dimensions.
|
|
745
|
+
getCanvasDimensions(pad) {
|
|
746
|
+
const gap = this.ren.canvasLayout.commentHighlightGap;
|
|
747
|
+
const canvasDimensions = this.ren.activePipeline.getCanvasDimensions(gap);
|
|
748
|
+
return this.convertRectAdjustedForScaleWithPadding(canvasDimensions, 1, pad);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// Returns a rect object describing the rect passed in but
|
|
752
|
+
// scaled by k and with padding added.
|
|
753
|
+
convertRectAdjustedForScaleWithPadding(rect, k, pad = 0) {
|
|
754
|
+
if (rect) {
|
|
755
|
+
return {
|
|
756
|
+
left: (rect.left * k) - pad,
|
|
757
|
+
top: (rect.top * k) - pad,
|
|
758
|
+
right: (rect.right * k) + pad,
|
|
759
|
+
bottom: (rect.bottom * k) + pad,
|
|
760
|
+
width: (rect.width * k) + (2 * pad),
|
|
761
|
+
height: (rect.height * k) + (2 * pad)
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
return null;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
// Returns the padding space for the canvas objects to be zoomed which takes
|
|
768
|
+
// into account any connections that need to be made to/from any sub-flow
|
|
769
|
+
// binding nodes plus any space needed for the binding nodes ports.
|
|
770
|
+
getZoomToFitPadding() {
|
|
771
|
+
let padding = this.ren.canvasLayout.zoomToFitPadding;
|
|
772
|
+
|
|
773
|
+
if (this.ren.dispUtils.isDisplayingSubFlow()) {
|
|
774
|
+
// Allocate some space for connecting lines and the binding node ports
|
|
775
|
+
const newPadding = this.getMaxZoomToFitPaddingForConnections() + (2 * this.ren.canvasLayout.supernodeBindingPortRadius);
|
|
776
|
+
padding = Math.max(padding, newPadding);
|
|
777
|
+
}
|
|
778
|
+
return padding;
|
|
779
|
+
}
|
|
780
|
+
}
|