@joint/core 4.1.3 → 4.2.0-alpha.1
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/README.md +4 -2
- package/dist/geometry.js +129 -124
- package/dist/geometry.min.js +4 -3
- package/dist/joint.d.ts +352 -160
- package/dist/joint.js +3654 -2191
- package/dist/joint.min.js +4 -3
- package/dist/joint.nowrap.js +3653 -2188
- package/dist/joint.nowrap.min.js +4 -3
- package/dist/vectorizer.js +489 -279
- package/dist/vectorizer.min.js +4 -3
- package/dist/version.mjs +1 -1
- package/package.json +33 -27
- package/src/V/create.mjs +51 -0
- package/src/V/index.mjs +89 -159
- package/src/V/namespace.mjs +9 -0
- package/src/V/transform.mjs +183 -0
- package/src/V/traverse.mjs +16 -0
- package/src/alg/Deque.mjs +126 -0
- package/src/anchors/index.mjs +140 -33
- package/src/cellTools/Boundary.mjs +15 -13
- package/src/cellTools/Button.mjs +7 -5
- package/src/cellTools/Control.mjs +38 -15
- package/src/cellTools/HoverConnect.mjs +5 -1
- package/src/cellTools/helpers.mjs +44 -3
- package/src/config/index.mjs +8 -0
- package/src/connectionPoints/index.mjs +24 -9
- package/src/connectionStrategies/index.mjs +1 -1
- package/src/connectors/jumpover.mjs +1 -1
- package/src/dia/Cell.mjs +32 -12
- package/src/dia/CellView.mjs +53 -38
- package/src/dia/Element.mjs +81 -35
- package/src/dia/ElementView.mjs +2 -1
- package/src/dia/HighlighterView.mjs +54 -11
- package/src/dia/LinkView.mjs +118 -98
- package/src/dia/Paper.mjs +831 -231
- package/src/dia/PaperLayer.mjs +9 -2
- package/src/dia/ToolView.mjs +4 -0
- package/src/dia/ToolsView.mjs +12 -3
- package/src/dia/attributes/text.mjs +16 -5
- package/src/dia/layers/GridLayer.mjs +5 -0
- package/src/dia/ports.mjs +344 -111
- package/src/elementTools/HoverConnect.mjs +14 -8
- package/src/env/index.mjs +7 -4
- package/src/g/rect.mjs +7 -0
- package/src/highlighters/stroke.mjs +1 -1
- package/src/layout/ports/port.mjs +30 -15
- package/src/layout/ports/portLabel.mjs +1 -1
- package/src/linkAnchors/index.mjs +2 -2
- package/src/linkTools/Anchor.mjs +2 -2
- package/src/linkTools/Vertices.mjs +4 -6
- package/src/mvc/View.mjs +4 -0
- package/src/mvc/ViewBase.mjs +1 -1
- package/src/util/util.mjs +1 -1
- package/src/util/utilHelpers.mjs +2 -0
- package/types/geometry.d.ts +65 -59
- package/types/joint.d.ts +278 -102
- package/types/vectorizer.d.ts +11 -1
- package/src/V/annotation.mjs +0 -0
package/src/dia/ports.mjs
CHANGED
|
@@ -4,19 +4,38 @@ import { Rect, Point } from '../g/index.mjs';
|
|
|
4
4
|
import * as Port from '../layout/ports/port.mjs';
|
|
5
5
|
import * as PortLabel from '../layout/ports/portLabel.mjs';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
const DEFAULT_PORT_POSITION_NAME = 'left';
|
|
8
|
+
const DEFAULT_ABSOLUTE_PORT_POSITION_NAME = 'absolute';
|
|
9
|
+
const DEFAULT_PORT_LABEL_POSITION_NAME = 'left';
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
const PortData = function(model) {
|
|
12
|
+
|
|
13
|
+
const { portLayoutNamespace = Port, portLabelLayoutNamespace = PortLabel } = model;
|
|
14
|
+
|
|
15
|
+
const clonedData = util.cloneDeep(model.get('ports')) || {};
|
|
10
16
|
this.ports = [];
|
|
17
|
+
this.portsMap = {};
|
|
11
18
|
this.groups = {};
|
|
12
|
-
this.portLayoutNamespace =
|
|
13
|
-
this.portLabelLayoutNamespace =
|
|
19
|
+
this.portLayoutNamespace = portLayoutNamespace;
|
|
20
|
+
this.portLabelLayoutNamespace = portLabelLayoutNamespace;
|
|
21
|
+
this.metrics = {};
|
|
22
|
+
this.metricsKey = null;
|
|
14
23
|
|
|
15
24
|
this._init(clonedData);
|
|
16
25
|
};
|
|
17
26
|
|
|
18
27
|
PortData.prototype = {
|
|
19
28
|
|
|
29
|
+
hasPort: function(id) {
|
|
30
|
+
return id in this.portsMap;
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
getPort: function(id) {
|
|
34
|
+
const port = this.portsMap[id];
|
|
35
|
+
if (port) return port;
|
|
36
|
+
throw new Error('Element: unable to find port with id ' + id);
|
|
37
|
+
},
|
|
38
|
+
|
|
20
39
|
getPorts: function() {
|
|
21
40
|
return this.ports;
|
|
22
41
|
},
|
|
@@ -32,52 +51,92 @@ PortData.prototype = {
|
|
|
32
51
|
});
|
|
33
52
|
},
|
|
34
53
|
|
|
35
|
-
|
|
54
|
+
// Calculate SVG transformations based on evaluated group + port data
|
|
55
|
+
// NOTE: This function is also called for ports without a group (groupName = undefined)
|
|
56
|
+
getGroupPortsMetrics: function(groupName, rect) {
|
|
36
57
|
|
|
37
|
-
|
|
38
|
-
|
|
58
|
+
const { x = 0, y = 0, width = 0, height = 0 } = rect;
|
|
59
|
+
const metricsKey = `${x}:${y}:${width}:${height}`;
|
|
60
|
+
if (this.metricsKey !== metricsKey) {
|
|
61
|
+
// Clear the cache (the element size has changed)
|
|
62
|
+
this.metrics = {};
|
|
63
|
+
this.metricsKey = metricsKey;
|
|
64
|
+
}
|
|
39
65
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
groupPositionName = 'left';
|
|
66
|
+
let groupPortsMetrics = this.metrics[groupName];
|
|
67
|
+
if (groupPortsMetrics) {
|
|
68
|
+
// Return cached metrics
|
|
69
|
+
return groupPortsMetrics;
|
|
45
70
|
}
|
|
46
71
|
|
|
47
|
-
|
|
48
|
-
|
|
72
|
+
// Calculate the metrics
|
|
73
|
+
groupPortsMetrics = this.resolveGroupPortsMetrics(groupName, new Rect(x, y, width, height));
|
|
74
|
+
this.metrics[groupName] = groupPortsMetrics;
|
|
75
|
+
return groupPortsMetrics;
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
resolveGroupPortsMetrics: function(groupName, elBBox) {
|
|
79
|
+
|
|
80
|
+
// `groupName` of `undefined` (= not a string) means "the group of ports which do not have the `group` property".
|
|
81
|
+
const isNoGroup = (groupName === undefined);
|
|
82
|
+
|
|
83
|
+
const group = this.getGroup(groupName);
|
|
84
|
+
const ports = this.getPortsByGroup(groupName);
|
|
85
|
+
|
|
86
|
+
const portsArgs = ports.map(function(port) {
|
|
49
87
|
return port && port.position && port.position.args;
|
|
50
88
|
});
|
|
51
|
-
var groupPortTransformations = namespace[groupPositionName](portsArgs, elBBox, groupArgs);
|
|
52
89
|
|
|
53
|
-
|
|
90
|
+
// Get an array of transformations of individual ports according to the group's port layout function:
|
|
91
|
+
let groupPortTransformations;
|
|
92
|
+
if (isNoGroup) {
|
|
93
|
+
// Apply default port layout function to the set of ports without `group` property.
|
|
94
|
+
const noGroup = this._evaluateGroup({});
|
|
95
|
+
groupPortTransformations = this._getGroupPortTransformations(noGroup, portsArgs, elBBox);
|
|
96
|
+
|
|
97
|
+
} else {
|
|
98
|
+
groupPortTransformations = this._getGroupPortTransformations(group, portsArgs, elBBox);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let accumulator = {
|
|
54
102
|
ports: ports,
|
|
55
|
-
result:
|
|
103
|
+
result: {}
|
|
56
104
|
};
|
|
57
105
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
res.
|
|
61
|
-
|
|
106
|
+
// For each individual port transformation, find the information necessary to calculate SVG transformations:
|
|
107
|
+
util.toArray(groupPortTransformations).reduce((res, portTransformation, index) => {
|
|
108
|
+
const port = res.ports[index];
|
|
109
|
+
const portId = port.id;
|
|
110
|
+
res.result[portId] = {
|
|
111
|
+
index,
|
|
112
|
+
portId,
|
|
62
113
|
portTransformation: portTransformation,
|
|
63
|
-
labelTransformation: this.
|
|
114
|
+
labelTransformation: this._getPortLabelTransformation(port, Point(portTransformation), elBBox),
|
|
64
115
|
portAttrs: port.attrs,
|
|
65
116
|
portSize: port.size,
|
|
66
117
|
labelSize: port.label.size
|
|
67
|
-
}
|
|
118
|
+
};
|
|
68
119
|
return res;
|
|
69
|
-
}
|
|
120
|
+
}, accumulator);
|
|
70
121
|
|
|
71
122
|
return accumulator.result;
|
|
72
123
|
},
|
|
73
124
|
|
|
74
|
-
|
|
125
|
+
_getGroupPortTransformations: function(group, portsArgs, elBBox) {
|
|
75
126
|
|
|
76
|
-
|
|
77
|
-
|
|
127
|
+
const groupPosition = group.position || {};
|
|
128
|
+
const groupPositionArgs = groupPosition.args || {};
|
|
129
|
+
const groupPositionLayoutCallback = groupPosition.layoutCallback;
|
|
130
|
+
return groupPositionLayoutCallback(portsArgs, elBBox, groupPositionArgs);
|
|
131
|
+
},
|
|
78
132
|
|
|
79
|
-
|
|
80
|
-
|
|
133
|
+
_getPortLabelTransformation: function(port, portPosition, elBBox) {
|
|
134
|
+
|
|
135
|
+
const portLabelPosition = port.label.position || {};
|
|
136
|
+
const portLabelPositionArgs = portLabelPosition.args || {};
|
|
137
|
+
const portLabelPositionLayoutCallback = portLabelPosition.layoutCallback;
|
|
138
|
+
if (portLabelPositionLayoutCallback) {
|
|
139
|
+
return portLabelPositionLayoutCallback(portPosition, elBBox, portLabelPositionArgs);
|
|
81
140
|
}
|
|
82
141
|
|
|
83
142
|
return null;
|
|
@@ -85,7 +144,8 @@ PortData.prototype = {
|
|
|
85
144
|
|
|
86
145
|
_init: function(data) {
|
|
87
146
|
|
|
88
|
-
//
|
|
147
|
+
// Prepare groups:
|
|
148
|
+
// NOTE: This overwrites passed group properties with evaluated group properties.
|
|
89
149
|
if (util.isObject(data.groups)) {
|
|
90
150
|
var groups = Object.keys(data.groups);
|
|
91
151
|
for (var i = 0, n = groups.length; i < n; i++) {
|
|
@@ -94,93 +154,197 @@ PortData.prototype = {
|
|
|
94
154
|
}
|
|
95
155
|
}
|
|
96
156
|
|
|
97
|
-
//
|
|
157
|
+
// Prepare ports:
|
|
158
|
+
// NOTE: This overwrites passed port properties with evaluated port properties, plus mixed-in evaluated group properties (see above).
|
|
98
159
|
var ports = util.toArray(data.items);
|
|
99
160
|
for (var j = 0, m = ports.length; j < m; j++) {
|
|
100
|
-
this.
|
|
161
|
+
const resolvedPort = this._evaluatePort(ports[j]);
|
|
162
|
+
this.ports.push(resolvedPort);
|
|
163
|
+
this.portsMap[resolvedPort.id] = resolvedPort;
|
|
101
164
|
}
|
|
102
165
|
},
|
|
103
166
|
|
|
104
167
|
_evaluateGroup: function(group) {
|
|
105
168
|
|
|
106
|
-
return util.merge(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
169
|
+
return util.merge(
|
|
170
|
+
{},
|
|
171
|
+
group,
|
|
172
|
+
{
|
|
173
|
+
position: this._evaluateGroupPositionProperty(group),
|
|
174
|
+
label: this._evaluateGroupLabelProperty(group)
|
|
175
|
+
}
|
|
176
|
+
);
|
|
110
177
|
},
|
|
111
178
|
|
|
112
|
-
|
|
179
|
+
_evaluateGroupPositionProperty: function(group) {
|
|
113
180
|
|
|
114
|
-
|
|
181
|
+
const namespace = this.portLayoutNamespace;
|
|
182
|
+
const groupPosition = group.position;
|
|
183
|
+
if (groupPosition === undefined) {
|
|
184
|
+
const layoutCallback = this._resolveLayoutCallbackOrThrow(namespace, DEFAULT_PORT_POSITION_NAME, 'Default port group');
|
|
185
|
+
return { layoutCallback };
|
|
115
186
|
|
|
116
|
-
|
|
187
|
+
} else if (util.isFunction(groupPosition)) {
|
|
188
|
+
return { layoutCallback: groupPosition };
|
|
117
189
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
190
|
+
} else if (util.isObject(groupPosition)) {
|
|
191
|
+
if (groupPosition.name) {
|
|
192
|
+
const layoutCallback = this._resolveLayoutCallbackOrThrow(namespace, groupPosition.name, 'Provided port group');
|
|
193
|
+
return { layoutCallback, args: groupPosition.args };
|
|
194
|
+
} else {
|
|
195
|
+
const layoutCallback = this._resolveLayoutCallbackOrThrow(namespace, DEFAULT_PORT_POSITION_NAME, 'Default port group');
|
|
196
|
+
return { layoutCallback, args: groupPosition.args };
|
|
197
|
+
}
|
|
124
198
|
|
|
125
|
-
|
|
199
|
+
} else if (util.isString(groupPosition)) {
|
|
200
|
+
// TODO: Remove legacy signature (see `this._evaluateGroupLabelPositionProperty()`).
|
|
201
|
+
const layoutCallback = this._resolveLayoutCallbackOrThrow(namespace, groupPosition, 'Provided port group');
|
|
202
|
+
return { layoutCallback };
|
|
203
|
+
|
|
204
|
+
} else if (Array.isArray(groupPosition)) {
|
|
205
|
+
// TODO: Remove legacy signature (see `this._evaluateGroupLabelPositionProperty()`).
|
|
206
|
+
const layoutCallback = this._resolveLayoutCallbackOrThrow(namespace, DEFAULT_ABSOLUTE_PORT_POSITION_NAME, 'Default absolute port group');
|
|
207
|
+
return { layoutCallback, args: { x: groupPosition[0], y: groupPosition[1] }};
|
|
208
|
+
|
|
209
|
+
} else {
|
|
210
|
+
throw new Error('dia.Element: Provided port group position value has an invalid type.');
|
|
211
|
+
}
|
|
126
212
|
},
|
|
127
213
|
|
|
128
|
-
|
|
214
|
+
_evaluateGroupLabelProperty: function(group) {
|
|
129
215
|
|
|
130
|
-
|
|
131
|
-
|
|
216
|
+
const groupLabel = group.label;
|
|
217
|
+
if (!groupLabel) {
|
|
218
|
+
return {
|
|
219
|
+
position: this._evaluateGroupLabelPositionProperty({})
|
|
220
|
+
};
|
|
132
221
|
}
|
|
133
|
-
|
|
134
|
-
|
|
222
|
+
|
|
223
|
+
return util.merge(
|
|
224
|
+
{},
|
|
225
|
+
groupLabel,
|
|
226
|
+
{
|
|
227
|
+
position: this._evaluateGroupLabelPositionProperty(groupLabel)
|
|
228
|
+
}
|
|
229
|
+
);
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
_evaluateGroupLabelPositionProperty: function(groupLabel) {
|
|
233
|
+
|
|
234
|
+
const namespace = this.portLabelLayoutNamespace;
|
|
235
|
+
const groupLabelPosition = groupLabel.position;
|
|
236
|
+
if (groupLabelPosition === undefined) {
|
|
237
|
+
const layoutCallback = this._resolveLayoutCallbackOrThrow(namespace, DEFAULT_PORT_LABEL_POSITION_NAME, 'Default port group label');
|
|
238
|
+
return { layoutCallback };
|
|
239
|
+
|
|
240
|
+
} else if (util.isFunction(groupLabelPosition)) {
|
|
241
|
+
return { layoutCallback: groupLabelPosition };
|
|
242
|
+
|
|
243
|
+
} else if (util.isObject(groupLabelPosition)) {
|
|
244
|
+
if (groupLabelPosition.name) {
|
|
245
|
+
const layoutCallback = this._resolveLayoutCallbackOrThrow(namespace, groupLabelPosition.name, 'Provided port group label');
|
|
246
|
+
return { layoutCallback, args: groupLabelPosition.args };
|
|
247
|
+
} else {
|
|
248
|
+
const layoutCallback = this._resolveLayoutCallbackOrThrow(namespace, DEFAULT_PORT_LABEL_POSITION_NAME, 'Default port group label');
|
|
249
|
+
return { layoutCallback, args: groupLabelPosition.args };
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
} else {
|
|
253
|
+
throw new Error('dia.Element: Provided port group label position value has an invalid type.');
|
|
135
254
|
}
|
|
136
|
-
return 'auto';
|
|
137
255
|
},
|
|
138
256
|
|
|
139
|
-
|
|
257
|
+
_evaluatePort: function(port) {
|
|
140
258
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
259
|
+
const group = this.getGroup(port.group);
|
|
260
|
+
|
|
261
|
+
const evaluated = util.assign({}, port);
|
|
262
|
+
evaluated.markup = evaluated.markup || group.markup;
|
|
263
|
+
evaluated.attrs = util.merge({}, group.attrs, evaluated.attrs);
|
|
264
|
+
evaluated.position = this._evaluatePortPositionProperty(group, evaluated);
|
|
265
|
+
evaluated.label = this._evaluatePortLabelProperty(group, evaluated);
|
|
266
|
+
evaluated.z = this._evaluatePortZProperty(group, evaluated);
|
|
267
|
+
evaluated.size = util.assign({}, group.size, evaluated.size);
|
|
268
|
+
return evaluated;
|
|
145
269
|
},
|
|
146
270
|
|
|
147
|
-
|
|
271
|
+
_evaluatePortPositionProperty: function(group, port) {
|
|
148
272
|
|
|
149
|
-
|
|
150
|
-
|
|
273
|
+
return {
|
|
274
|
+
args: util.merge(
|
|
275
|
+
{},
|
|
276
|
+
// NOTE: `x != null` is equivalent to `x !== null && x !== undefined`.
|
|
277
|
+
(group.position != null) ? group.position.args : {},
|
|
278
|
+
// Port can overwrite `group.position.args` via `port.position.args` or `port.args`.
|
|
279
|
+
// TODO: Remove `port.args` backwards compatibility.
|
|
280
|
+
(((port.position != null) && (port.position.args != null)) ? port.position.args : port.args))
|
|
281
|
+
};
|
|
282
|
+
},
|
|
151
283
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
args.x = position[0];
|
|
162
|
-
args.y = position[1];
|
|
163
|
-
} else if (util.isObject(position)) {
|
|
164
|
-
positionName = position.name;
|
|
165
|
-
util.assign(args, position.args);
|
|
284
|
+
_evaluatePortLabelProperty: function(group, port) {
|
|
285
|
+
|
|
286
|
+
const groupLabel = group.label;
|
|
287
|
+
const portLabel = port.label;
|
|
288
|
+
if (!portLabel) {
|
|
289
|
+
return util.assign(
|
|
290
|
+
{},
|
|
291
|
+
groupLabel
|
|
292
|
+
);
|
|
166
293
|
}
|
|
167
294
|
|
|
168
|
-
|
|
295
|
+
return util.merge(
|
|
296
|
+
{},
|
|
297
|
+
groupLabel,
|
|
298
|
+
util.merge(
|
|
299
|
+
{},
|
|
300
|
+
portLabel,
|
|
301
|
+
{
|
|
302
|
+
position: this._evaluatePortLabelPositionProperty(portLabel)
|
|
303
|
+
}
|
|
304
|
+
)
|
|
305
|
+
);
|
|
306
|
+
},
|
|
307
|
+
|
|
308
|
+
_evaluatePortLabelPositionProperty: function(portLabel) {
|
|
309
|
+
|
|
310
|
+
const namespace = this.portLabelLayoutNamespace;
|
|
311
|
+
const portLabelPosition = portLabel.position;
|
|
312
|
+
if (portLabelPosition === undefined) {
|
|
313
|
+
return {};
|
|
314
|
+
|
|
315
|
+
} else if (util.isFunction(portLabelPosition)) {
|
|
316
|
+
return { layoutCallback: portLabelPosition };
|
|
169
317
|
|
|
170
|
-
if (
|
|
171
|
-
|
|
318
|
+
} else if (util.isObject(portLabelPosition)) {
|
|
319
|
+
if (portLabelPosition.name) {
|
|
320
|
+
const layoutCallback = this._resolveLayoutCallbackOrThrow(namespace, portLabelPosition.name, 'Provided port label');
|
|
321
|
+
return { layoutCallback, args: portLabelPosition.args };
|
|
322
|
+
} else {
|
|
323
|
+
return { args: portLabelPosition.args };
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
} else {
|
|
327
|
+
throw new Error('dia.Element: Provided port label position value has an invalid type.');
|
|
172
328
|
}
|
|
173
|
-
return result;
|
|
174
329
|
},
|
|
175
330
|
|
|
176
|
-
|
|
331
|
+
_evaluatePortZProperty: function(group, port) {
|
|
177
332
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
333
|
+
if (util.isNumber(port.z)) {
|
|
334
|
+
return port.z;
|
|
335
|
+
}
|
|
336
|
+
if (util.isNumber(group.z) || group.z === 'auto') {
|
|
337
|
+
return group.z;
|
|
338
|
+
}
|
|
339
|
+
return 'auto';
|
|
340
|
+
},
|
|
182
341
|
|
|
183
|
-
|
|
342
|
+
_resolveLayoutCallbackOrThrow: function(namespace, name, errorSubstring) {
|
|
343
|
+
const layoutCallback = namespace[name];
|
|
344
|
+
if (!layoutCallback) {
|
|
345
|
+
throw new Error(`dia.Element: ${errorSubstring} layout name is not recognized.`);
|
|
346
|
+
}
|
|
347
|
+
return layoutCallback;
|
|
184
348
|
}
|
|
185
349
|
};
|
|
186
350
|
|
|
@@ -240,8 +404,7 @@ export const elementPortPrototype = {
|
|
|
240
404
|
*/
|
|
241
405
|
hasPorts: function() {
|
|
242
406
|
|
|
243
|
-
|
|
244
|
-
return Array.isArray(ports) && ports.length > 0;
|
|
407
|
+
return this._portSettingsData.getPorts().length > 0;
|
|
245
408
|
},
|
|
246
409
|
|
|
247
410
|
/**
|
|
@@ -250,7 +413,7 @@ export const elementPortPrototype = {
|
|
|
250
413
|
*/
|
|
251
414
|
hasPort: function(id) {
|
|
252
415
|
|
|
253
|
-
return this.
|
|
416
|
+
return this._portSettingsData.hasPort(id);
|
|
254
417
|
},
|
|
255
418
|
|
|
256
419
|
/**
|
|
@@ -274,10 +437,8 @@ export const elementPortPrototype = {
|
|
|
274
437
|
* @returns {object}
|
|
275
438
|
*/
|
|
276
439
|
getPort: function(id) {
|
|
277
|
-
|
|
278
|
-
return util.cloneDeep(
|
|
279
|
-
return port.id && port.id === id;
|
|
280
|
-
}));
|
|
440
|
+
const port = util.toArray(this.prop('ports/items')).find(port => port.id && port.id === id);
|
|
441
|
+
return util.cloneDeep(port);
|
|
281
442
|
},
|
|
282
443
|
|
|
283
444
|
getPortGroupNames: function() {
|
|
@@ -290,17 +451,90 @@ export const elementPortPrototype = {
|
|
|
290
451
|
*/
|
|
291
452
|
getPortsPositions: function(groupName) {
|
|
292
453
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
454
|
+
const portsMetrics = this.getGroupPortsMetrics(groupName);
|
|
455
|
+
const portsPosition = {};
|
|
456
|
+
for (const portId in portsMetrics) {
|
|
457
|
+
const {
|
|
458
|
+
portTransformation: { x, y, angle },
|
|
459
|
+
} = portsMetrics[portId];
|
|
460
|
+
portsPosition[portId] = {
|
|
461
|
+
x: x,
|
|
462
|
+
y: y,
|
|
463
|
+
angle
|
|
301
464
|
};
|
|
302
|
-
|
|
303
|
-
|
|
465
|
+
}
|
|
466
|
+
return portsPosition;
|
|
467
|
+
},
|
|
468
|
+
|
|
469
|
+
getPortMetrics: function(portId) {
|
|
470
|
+
const port = this._portSettingsData.getPort(portId);
|
|
471
|
+
return this.getGroupPortsMetrics(port.group)[portId];
|
|
472
|
+
},
|
|
473
|
+
|
|
474
|
+
getGroupPortsMetrics: function(groupName) {
|
|
475
|
+
return this._portSettingsData.getGroupPortsMetrics(groupName, this.size());
|
|
476
|
+
},
|
|
477
|
+
|
|
478
|
+
getPortRelativePosition: function(portId) {
|
|
479
|
+
const { portTransformation: { x, y, angle }} = this.getPortMetrics(portId);
|
|
480
|
+
return { x, y, angle };
|
|
481
|
+
},
|
|
482
|
+
|
|
483
|
+
getPortRelativeRect(portId) {
|
|
484
|
+
const {
|
|
485
|
+
portTransformation: { x, y, angle },
|
|
486
|
+
portSize: { width, height }
|
|
487
|
+
} = this.getPortMetrics(portId);
|
|
488
|
+
const portRect = {
|
|
489
|
+
x: x - width / 2,
|
|
490
|
+
y: y - height / 2,
|
|
491
|
+
width,
|
|
492
|
+
height,
|
|
493
|
+
angle
|
|
494
|
+
};
|
|
495
|
+
return portRect;
|
|
496
|
+
},
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* @param {string} portId
|
|
500
|
+
* @returns {Point}
|
|
501
|
+
* @description Returns the port center in the graph coordinate system.
|
|
502
|
+
* The port center is in the graph coordinate system, and the position
|
|
503
|
+
* already takes into account the element rotation.
|
|
504
|
+
**/
|
|
505
|
+
getPortCenter(portId) {
|
|
506
|
+
const elementBBox = this.getBBox();
|
|
507
|
+
const portPosition = this.getPortRelativePosition(portId);
|
|
508
|
+
const portCenter = new Point(portPosition).offset(elementBBox.x, elementBBox.y);
|
|
509
|
+
const angle = this.angle();
|
|
510
|
+
if (angle) portCenter.rotate(elementBBox.center(), -angle);
|
|
511
|
+
return portCenter;
|
|
512
|
+
},
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* @param {string} portId
|
|
516
|
+
* @param {object} [opt]
|
|
517
|
+
* @param {boolean} [opt.rotate] - If true, the port bounding box is rotated
|
|
518
|
+
* around the port center.
|
|
519
|
+
* @returns {Rect}
|
|
520
|
+
* @description Returns the bounding box of the port in the graph coordinate system.
|
|
521
|
+
* The port center is rotated around the element center, but the port bounding box
|
|
522
|
+
* is not rotated (unless `opt.rotate` is set to true).
|
|
523
|
+
*/
|
|
524
|
+
getPortBBox: function(portId, opt) {
|
|
525
|
+
const portRect = this.getPortRelativeRect(portId);
|
|
526
|
+
const elementBBox = this.getBBox();
|
|
527
|
+
// Note: the `angle` property of the `port` is ignore here for now
|
|
528
|
+
const portBBox = new Rect(portRect);
|
|
529
|
+
portBBox.offset(elementBBox.x, elementBBox.y);
|
|
530
|
+
const angle = this.angle();
|
|
531
|
+
if (angle) {
|
|
532
|
+
portBBox.moveAroundPoint(elementBBox.center(), -angle);
|
|
533
|
+
}
|
|
534
|
+
if (opt && opt.rotate) {
|
|
535
|
+
portBBox.rotateAroundCenter(angle);
|
|
536
|
+
}
|
|
537
|
+
return portBBox;
|
|
304
538
|
},
|
|
305
539
|
|
|
306
540
|
/**
|
|
@@ -499,7 +733,7 @@ export const elementPortPrototype = {
|
|
|
499
733
|
prevPortData = this._portSettingsData.getPorts();
|
|
500
734
|
}
|
|
501
735
|
|
|
502
|
-
this._portSettingsData = new PortData(this
|
|
736
|
+
this._portSettingsData = new PortData(this);
|
|
503
737
|
|
|
504
738
|
var curPortData = this._portSettingsData.getPorts();
|
|
505
739
|
|
|
@@ -822,15 +1056,15 @@ export const elementViewPortPrototype = {
|
|
|
822
1056
|
*/
|
|
823
1057
|
_updatePortGroup: function(groupName) {
|
|
824
1058
|
|
|
825
|
-
|
|
826
|
-
|
|
1059
|
+
const portsMetrics = this.model.getGroupPortsMetrics(groupName);
|
|
1060
|
+
const portsIds = Object.keys(portsMetrics);
|
|
827
1061
|
|
|
828
|
-
for (
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
1062
|
+
for (let i = 0, n = portsIds.length; i < n; i++) {
|
|
1063
|
+
const portId = portsIds[i];
|
|
1064
|
+
const metrics = portsMetrics[portId];
|
|
1065
|
+
const cached = this._portElementsCache[portId] || {};
|
|
1066
|
+
const portTransformation = metrics.portTransformation;
|
|
1067
|
+
const labelTransformation = metrics.labelTransformation;
|
|
834
1068
|
if (labelTransformation && cached.portLabelElement) {
|
|
835
1069
|
this.updateDOMSubtreeAttributes(cached.portLabelElement.node, labelTransformation.attrs, {
|
|
836
1070
|
rootBBox: new Rect(metrics.labelSize),
|
|
@@ -882,4 +1116,3 @@ export const elementViewPortPrototype = {
|
|
|
882
1116
|
return label.markup || this.model.get('portLabelMarkup') || this.model.portLabelMarkup || this.portLabelMarkup;
|
|
883
1117
|
}
|
|
884
1118
|
};
|
|
885
|
-
|
|
@@ -2,30 +2,36 @@ import { HoverConnect as LinkHoverConnect } from '../cellTools/HoverConnect.mjs'
|
|
|
2
2
|
import V from '../V/index.mjs';
|
|
3
3
|
import * as g from '../g/index.mjs';
|
|
4
4
|
import { isCalcExpression, evalCalcExpression } from '../util/calc.mjs';
|
|
5
|
-
import { getViewBBox } from '../cellTools/helpers.mjs';
|
|
5
|
+
import { getToolOptions, getViewBBox } from '../cellTools/helpers.mjs';
|
|
6
6
|
|
|
7
7
|
export const HoverConnect = LinkHoverConnect.extend({
|
|
8
8
|
|
|
9
9
|
getTrackPath() {
|
|
10
|
-
const { relatedView: view
|
|
10
|
+
const { relatedView: view } = this;
|
|
11
11
|
let {
|
|
12
12
|
useModelGeometry,
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
relative,
|
|
14
|
+
trackPath = 'M 0 0 H calc(w) V calc(h) H 0 Z'
|
|
15
|
+
} = getToolOptions(this);
|
|
15
16
|
if (typeof trackPath === 'function') {
|
|
16
17
|
trackPath = trackPath.call(this, view);
|
|
17
18
|
}
|
|
18
19
|
if (isCalcExpression(trackPath)) {
|
|
19
|
-
const bbox = getViewBBox(view, useModelGeometry);
|
|
20
|
+
const bbox = getViewBBox(view, { useModelGeometry, relative });
|
|
20
21
|
trackPath = evalCalcExpression(trackPath, bbox);
|
|
21
22
|
}
|
|
22
23
|
return new g.Path(V.normalizePathData(trackPath));
|
|
23
24
|
},
|
|
24
25
|
|
|
25
26
|
getTrackMatrix() {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
if (this.isOverlay()) return this.getTrackMatrixAbsolute();
|
|
28
|
+
return V.createSVGMatrix();
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
getTrackMatrixAbsolute() {
|
|
32
|
+
const { relatedView: view } = this;
|
|
33
|
+
let { useModelGeometry, rotate } = getToolOptions(this);
|
|
34
|
+
let bbox = getViewBBox(view, { useModelGeometry });
|
|
29
35
|
const angle = view.model.angle();
|
|
30
36
|
if (!rotate) bbox = bbox.bbox(angle);
|
|
31
37
|
let matrix = V.createSVGMatrix().translate(bbox.x + bbox.width / 2, bbox.y + bbox.height / 2);
|
package/src/env/index.mjs
CHANGED
|
@@ -9,9 +9,12 @@ export const env = {
|
|
|
9
9
|
/SVGForeignObject/.test(({}).toString.call(document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject')));
|
|
10
10
|
},
|
|
11
11
|
|
|
12
|
-
// works for iOS
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
// works for: (1) macOS Safari, (2) any WKWebView, (3) any iOS browser (including Safari, CriOS, EdgiOS, OPR, FxiOS)
|
|
13
|
+
isAppleWebKit: function() {
|
|
14
|
+
const userAgent = navigator.userAgent;
|
|
15
|
+
const isAppleWebKit = /applewebkit/i.test(userAgent);
|
|
16
|
+
const isChromium = /chrome/i.test(userAgent); // e.g. Chrome, Edge, Opera, SamsungBrowser
|
|
17
|
+
return isAppleWebKit && !isChromium;
|
|
15
18
|
}
|
|
16
19
|
},
|
|
17
20
|
|
|
@@ -36,7 +39,7 @@ export const env = {
|
|
|
36
39
|
|
|
37
40
|
try {
|
|
38
41
|
result = fn();
|
|
39
|
-
} catch
|
|
42
|
+
} catch {
|
|
40
43
|
result = false;
|
|
41
44
|
}
|
|
42
45
|
|