@joint/core 4.2.0-alpha.0 → 4.2.0-beta.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.
Files changed (54) hide show
  1. package/README.md +3 -1
  2. package/dist/geometry.js +2 -2
  3. package/dist/geometry.min.js +3 -3
  4. package/dist/joint.d.ts +595 -198
  5. package/dist/joint.js +3895 -1304
  6. package/dist/joint.min.js +3 -3
  7. package/dist/joint.nowrap.js +3895 -1304
  8. package/dist/joint.nowrap.min.js +3 -3
  9. package/dist/vectorizer.js +21 -8
  10. package/dist/vectorizer.min.js +3 -3
  11. package/dist/version.mjs +1 -1
  12. package/package.json +13 -13
  13. package/src/V/index.mjs +20 -5
  14. package/src/alg/Deque.mjs +126 -0
  15. package/src/cellTools/Boundary.mjs +15 -13
  16. package/src/cellTools/Button.mjs +7 -5
  17. package/src/cellTools/Control.mjs +37 -14
  18. package/src/cellTools/HoverConnect.mjs +5 -1
  19. package/src/cellTools/helpers.mjs +44 -3
  20. package/src/config/index.mjs +11 -1
  21. package/src/dia/Cell.mjs +96 -83
  22. package/src/dia/CellCollection.mjs +136 -0
  23. package/src/dia/CellView.mjs +6 -0
  24. package/src/dia/Element.mjs +6 -5
  25. package/src/dia/ElementView.mjs +2 -1
  26. package/src/dia/Graph.mjs +610 -317
  27. package/src/dia/GraphLayer.mjs +53 -0
  28. package/src/dia/GraphLayerCollection.mjs +313 -0
  29. package/src/dia/GraphLayerView.mjs +128 -0
  30. package/src/dia/GraphLayersController.mjs +166 -0
  31. package/src/dia/GraphTopologyIndex.mjs +222 -0
  32. package/src/dia/{layers/GridLayer.mjs → GridLayerView.mjs} +23 -16
  33. package/src/dia/HighlighterView.mjs +22 -0
  34. package/src/dia/{PaperLayer.mjs → LayerView.mjs} +52 -17
  35. package/src/dia/LegacyGraphLayerView.mjs +14 -0
  36. package/src/dia/LinkView.mjs +118 -98
  37. package/src/dia/Paper.mjs +1441 -620
  38. package/src/dia/ToolView.mjs +4 -0
  39. package/src/dia/ToolsView.mjs +14 -5
  40. package/src/dia/attributes/text.mjs +4 -2
  41. package/src/dia/index.mjs +6 -1
  42. package/src/dia/ports.mjs +213 -84
  43. package/src/dia/symbols.mjs +24 -0
  44. package/src/elementTools/HoverConnect.mjs +14 -8
  45. package/src/env/index.mjs +6 -3
  46. package/src/layout/ports/port.mjs +30 -15
  47. package/src/layout/ports/portLabel.mjs +1 -1
  48. package/src/mvc/Collection.mjs +19 -19
  49. package/src/mvc/Model.mjs +13 -10
  50. package/src/mvc/View.mjs +4 -0
  51. package/src/mvc/ViewBase.mjs +1 -1
  52. package/types/geometry.d.ts +64 -60
  53. package/types/joint.d.ts +520 -137
  54. package/types/vectorizer.d.ts +11 -1
@@ -69,6 +69,10 @@ export const ToolView = mvc.View.extend({
69
69
  return !!this._visible;
70
70
  },
71
71
 
72
+ isOverlay: function() {
73
+ return !!this.parentView && this.parentView.hasLayer();
74
+ },
75
+
72
76
  focus: function() {
73
77
  var opacity = this.options.focusOpacity;
74
78
  if (isFinite(opacity)) this.el.style.opacity = opacity;
@@ -1,7 +1,7 @@
1
1
  import * as mvc from '../mvc/index.mjs';
2
2
  import * as util from '../util/index.mjs';
3
3
  import { CellView } from './CellView.mjs';
4
- import { LayersNames } from './PaperLayer.mjs';
4
+ import { Paper } from './Paper.mjs';
5
5
  import { ToolView } from './ToolView.mjs';
6
6
 
7
7
  export const ToolsView = mvc.View.extend({
@@ -14,7 +14,7 @@ export const ToolsView = mvc.View.extend({
14
14
  tools: null,
15
15
  relatedView: null,
16
16
  name: null,
17
- // layer?: LayersNames.TOOLS
17
+ // layer?: Paper.Layers.TOOLS
18
18
  // z?: number
19
19
  },
20
20
 
@@ -138,12 +138,21 @@ export const ToolsView = mvc.View.extend({
138
138
  this.tools = null;
139
139
  },
140
140
 
141
+ getLayer() {
142
+ const { layer = Paper.Layers.TOOLS } = this.options;
143
+ return layer;
144
+ },
145
+
146
+ hasLayer() {
147
+ return !!this.getLayer();
148
+ },
149
+
141
150
  mount: function() {
142
151
  const { options, el } = this;
143
- const { relatedView, layer = LayersNames.TOOLS, z } = options;
152
+ const { relatedView, z } = options;
144
153
  if (relatedView) {
145
- if (layer) {
146
- relatedView.paper.getLayerView(layer).insertSortedNode(el, z);
154
+ if (this.hasLayer()) {
155
+ relatedView.paper.getLayerView(this.getLayer()).insertSortedNode(el, z);
147
156
  } else {
148
157
  relatedView.el.appendChild(el);
149
158
  }
@@ -54,9 +54,10 @@ const textAttributesNS = {
54
54
  const eol = attrs.eol;
55
55
  const x = attrs.x;
56
56
  let textPath = attrs['text-path'];
57
+ const useNoBreakSpace = attrs['use-no-break-space'] === true;
57
58
  // Update the text only if there was a change in the string
58
59
  // or any of its attributes.
59
- const textHash = JSON.stringify([text, lineHeight, annotations, textVerticalAnchor, eol, displayEmpty, textPath, x, fontSize]);
60
+ const textHash = JSON.stringify([text, lineHeight, annotations, textVerticalAnchor, eol, displayEmpty, textPath, x, fontSize, useNoBreakSpace]);
60
61
  if (cache === undefined || cache !== textHash) {
61
62
  // Chrome bug:
62
63
  // <tspan> positions defined as `em` are not updated
@@ -79,7 +80,8 @@ const textAttributesNS = {
79
80
  x,
80
81
  textVerticalAnchor,
81
82
  eol,
82
- displayEmpty
83
+ displayEmpty,
84
+ useNoBreakSpace
83
85
  });
84
86
  $.data.set(node, cacheName, textHash);
85
87
  }
package/src/dia/index.mjs CHANGED
@@ -1,6 +1,5 @@
1
1
  export * from './Graph.mjs';
2
2
  export * from './attributes/index.mjs';
3
- export * from './PaperLayer.mjs';
4
3
  export * from './Cell.mjs';
5
4
  export * from './CellView.mjs';
6
5
  export * from './Element.mjs';
@@ -11,3 +10,9 @@ export * from './Paper.mjs';
11
10
  export * from './ToolView.mjs';
12
11
  export * from './ToolsView.mjs';
13
12
  export * from './HighlighterView.mjs';
13
+ export * from './GraphLayerView.mjs';
14
+ export * from './LayerView.mjs';
15
+ export * from './GridLayerView.mjs';
16
+ export * from './GraphLayer.mjs';
17
+ export * from './GraphLayerCollection.mjs';
18
+ export * from './CellCollection.mjs';
package/src/dia/ports.mjs CHANGED
@@ -4,14 +4,20 @@ 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
- var PortData = function(data) {
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
- var clonedData = util.cloneDeep(data) || {};
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 = [];
11
17
  this.portsMap = {};
12
18
  this.groups = {};
13
- this.portLayoutNamespace = Port;
14
- this.portLabelLayoutNamespace = PortLabel;
19
+ this.portLayoutNamespace = portLayoutNamespace;
20
+ this.portLabelLayoutNamespace = portLabelLayoutNamespace;
15
21
  this.metrics = {};
16
22
  this.metricsKey = null;
17
23
 
@@ -45,7 +51,10 @@ PortData.prototype = {
45
51
  });
46
52
  },
47
53
 
54
+ // Calculate SVG transformations based on evaluated group + port data
55
+ // NOTE: This function is also called for ports without a group (groupName = undefined)
48
56
  getGroupPortsMetrics: function(groupName, rect) {
57
+
49
58
  const { x = 0, y = 0, width = 0, height = 0 } = rect;
50
59
  const metricsKey = `${x}:${y}:${width}:${height}`;
51
60
  if (this.metricsKey !== metricsKey) {
@@ -53,11 +62,13 @@ PortData.prototype = {
53
62
  this.metrics = {};
54
63
  this.metricsKey = metricsKey;
55
64
  }
65
+
56
66
  let groupPortsMetrics = this.metrics[groupName];
57
67
  if (groupPortsMetrics) {
58
68
  // Return cached metrics
59
69
  return groupPortsMetrics;
60
70
  }
71
+
61
72
  // Calculate the metrics
62
73
  groupPortsMetrics = this.resolveGroupPortsMetrics(groupName, new Rect(x, y, width, height));
63
74
  this.metrics[groupName] = groupPortsMetrics;
@@ -66,27 +77,33 @@ PortData.prototype = {
66
77
 
67
78
  resolveGroupPortsMetrics: function(groupName, elBBox) {
68
79
 
69
- var group = this.getGroup(groupName);
70
- var ports = this.getPortsByGroup(groupName);
80
+ // `groupName` of `undefined` (= not a string) means "the group of ports which do not have the `group` property".
81
+ const isNoGroup = (groupName === undefined);
71
82
 
72
- var groupPosition = group.position || {};
73
- var groupPositionName = groupPosition.name;
74
- var namespace = this.portLayoutNamespace;
75
- if (!namespace[groupPositionName]) {
76
- groupPositionName = 'left';
77
- }
83
+ const group = this.getGroup(groupName);
84
+ const ports = this.getPortsByGroup(groupName);
78
85
 
79
- var groupArgs = groupPosition.args || {};
80
- var portsArgs = ports.map(function(port) {
86
+ const portsArgs = ports.map(function(port) {
81
87
  return port && port.position && port.position.args;
82
88
  });
83
- var groupPortTransformations = namespace[groupPositionName](portsArgs, elBBox, groupArgs);
84
89
 
85
- var accumulator = {
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 = {
86
102
  ports: ports,
87
103
  result: {}
88
104
  };
89
105
 
106
+ // For each individual port transformation, find the information necessary to calculate SVG transformations:
90
107
  util.toArray(groupPortTransformations).reduce((res, portTransformation, index) => {
91
108
  const port = res.ports[index];
92
109
  const portId = port.id;
@@ -94,7 +111,7 @@ PortData.prototype = {
94
111
  index,
95
112
  portId,
96
113
  portTransformation: portTransformation,
97
- labelTransformation: this._getPortLabelLayout(port, Point(portTransformation), elBBox),
114
+ labelTransformation: this._getPortLabelTransformation(port, Point(portTransformation), elBBox),
98
115
  portAttrs: port.attrs,
99
116
  portSize: port.size,
100
117
  labelSize: port.label.size
@@ -105,13 +122,21 @@ PortData.prototype = {
105
122
  return accumulator.result;
106
123
  },
107
124
 
108
- _getPortLabelLayout: function(port, portPosition, elBBox) {
125
+ _getGroupPortTransformations: function(group, portsArgs, elBBox) {
109
126
 
110
- var namespace = this.portLabelLayoutNamespace;
111
- var labelPosition = port.label.position.name || 'left';
127
+ const groupPosition = group.position || {};
128
+ const groupPositionArgs = groupPosition.args || {};
129
+ const groupPositionLayoutCallback = groupPosition.layoutCallback;
130
+ return groupPositionLayoutCallback(portsArgs, elBBox, groupPositionArgs);
131
+ },
112
132
 
113
- if (namespace[labelPosition]) {
114
- return namespace[labelPosition](portPosition, elBBox, port.label.position.args);
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);
115
140
  }
116
141
 
117
142
  return null;
@@ -119,7 +144,8 @@ PortData.prototype = {
119
144
 
120
145
  _init: function(data) {
121
146
 
122
- // prepare groups
147
+ // Prepare groups:
148
+ // NOTE: This overwrites passed group properties with evaluated group properties.
123
149
  if (util.isObject(data.groups)) {
124
150
  var groups = Object.keys(data.groups);
125
151
  for (var i = 0, n = groups.length; i < n; i++) {
@@ -128,7 +154,8 @@ PortData.prototype = {
128
154
  }
129
155
  }
130
156
 
131
- // prepare ports
157
+ // Prepare ports:
158
+ // NOTE: This overwrites passed port properties with evaluated port properties, plus mixed-in evaluated group properties (see above).
132
159
  var ports = util.toArray(data.items);
133
160
  for (var j = 0, m = ports.length; j < m; j++) {
134
161
  const resolvedPort = this._evaluatePort(ports[j]);
@@ -139,99 +166,201 @@ PortData.prototype = {
139
166
 
140
167
  _evaluateGroup: function(group) {
141
168
 
142
- return util.merge(group, {
143
- position: this._getPosition(group.position, true),
144
- label: this._getLabel(group, true)
145
- });
169
+ return util.merge(
170
+ {},
171
+ group,
172
+ {
173
+ position: this._evaluateGroupPositionProperty(group),
174
+ label: this._evaluateGroupLabelProperty(group)
175
+ }
176
+ );
146
177
  },
147
178
 
148
- _evaluatePort: function(port) {
179
+ _evaluateGroupPositionProperty: function(group) {
149
180
 
150
- var evaluated = util.assign({}, port);
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 };
151
186
 
152
- var group = this.getGroup(port.group);
187
+ } else if (util.isFunction(groupPosition)) {
188
+ return { layoutCallback: groupPosition };
153
189
 
154
- evaluated.markup = evaluated.markup || group.markup;
155
- evaluated.attrs = util.merge({}, group.attrs, evaluated.attrs);
156
- evaluated.position = this._createPositionNode(group, evaluated);
157
- evaluated.label = util.merge({}, group.label, this._getLabel(evaluated));
158
- evaluated.z = this._getZIndex(group, evaluated);
159
- evaluated.size = util.assign({}, group.size, evaluated.size);
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
+ }
160
198
 
161
- return evaluated;
162
- },
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 };
163
203
 
164
- _getZIndex: function(group, port) {
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] }};
165
208
 
166
- if (util.isNumber(port.z)) {
167
- return port.z;
168
- }
169
- if (util.isNumber(group.z) || group.z === 'auto') {
170
- return group.z;
209
+ } else {
210
+ throw new Error('dia.Element: Provided port group position value has an invalid type.');
171
211
  }
172
- return 'auto';
173
212
  },
174
213
 
175
- _createPositionNode: function(group, port) {
214
+ _evaluateGroupLabelProperty: function(group) {
215
+
216
+ const groupLabel = group.label;
217
+ if (!groupLabel) {
218
+ return {
219
+ position: this._evaluateGroupLabelPositionProperty({})
220
+ };
221
+ }
176
222
 
177
223
  return util.merge(
224
+ {},
225
+ groupLabel,
178
226
  {
179
- name: 'left',
180
- args: {}
181
- },
182
- group.position,
183
- {
184
- // TODO: remove `port.args` backwards compatibility
185
- // NOTE: `x != null` is equivalent to `x !== null && x !== undefined`
186
- args: (((port.position != null) && (port.position.args != null)) ? port.position.args : port.args)
227
+ position: this._evaluateGroupLabelPositionProperty(groupLabel)
187
228
  }
188
229
  );
189
230
  },
190
231
 
191
- _getPosition: function(position, setDefault) {
232
+ _evaluateGroupLabelPositionProperty: function(groupLabel) {
192
233
 
193
- var args = {};
194
- var positionName;
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 };
195
239
 
196
- if (util.isFunction(position)) {
197
- positionName = 'fn';
198
- args.fn = position;
199
- } else if (util.isString(position)) {
200
- positionName = position;
201
- } else if (position === undefined) {
202
- positionName = setDefault ? 'left' : null;
203
- } else if (Array.isArray(position)) {
204
- positionName = 'absolute';
205
- args.x = position[0];
206
- args.y = position[1];
207
- } else if (util.isObject(position)) {
208
- positionName = position.name;
209
- util.assign(args, position.args);
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.');
210
254
  }
255
+ },
256
+
257
+ _evaluatePort: function(port) {
211
258
 
212
- var result = { args: args };
259
+ const group = this.getGroup(port.group);
213
260
 
214
- if (positionName) {
215
- result.name = positionName;
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;
269
+ },
270
+
271
+ _evaluatePortPositionProperty: function(group, port) {
272
+
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
+ },
283
+
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
+ );
216
293
  }
217
- return result;
294
+
295
+ return util.merge(
296
+ {},
297
+ groupLabel,
298
+ util.merge(
299
+ {},
300
+ portLabel,
301
+ {
302
+ position: this._evaluatePortLabelPositionProperty(portLabel)
303
+ }
304
+ )
305
+ );
218
306
  },
219
307
 
220
- _getLabel: function(item, setDefaults) {
308
+ _evaluatePortLabelPositionProperty: function(portLabel) {
309
+
310
+ const namespace = this.portLabelLayoutNamespace;
311
+ const portLabelPosition = portLabel.position;
312
+ if (portLabelPosition === undefined) {
313
+ return {};
221
314
 
222
- var label = item.label || {};
315
+ } else if (util.isFunction(portLabelPosition)) {
316
+ return { layoutCallback: portLabelPosition };
223
317
 
224
- var ret = label;
225
- ret.position = this._getPosition(label.position, setDefaults);
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
+ }
226
325
 
227
- return ret;
326
+ } else {
327
+ throw new Error('dia.Element: Provided port label position value has an invalid type.');
328
+ }
329
+ },
330
+
331
+ _evaluatePortZProperty: function(group, port) {
332
+
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
+ },
341
+
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;
228
348
  }
229
349
  };
230
350
 
231
351
  export const elementPortPrototype = {
232
352
 
233
- _initializePorts: function() {
234
-
353
+ _initializePorts: function(options) {
354
+ if (options) {
355
+ // Override port layout namespaces if provided in options
356
+ if (options.portLayoutNamespace) {
357
+ this.portLayoutNamespace = options.portLayoutNamespace;
358
+ }
359
+ // Override port label layout namespaces if provided in options
360
+ if (options.portLabelLayoutNamespace) {
361
+ this.portLabelLayoutNamespace = options.portLabelLayoutNamespace;
362
+ }
363
+ }
235
364
  this._createPortData();
236
365
  this.on('change:ports', function() {
237
366
 
@@ -613,7 +742,7 @@ export const elementPortPrototype = {
613
742
  prevPortData = this._portSettingsData.getPorts();
614
743
  }
615
744
 
616
- this._portSettingsData = new PortData(this.get('ports'));
745
+ this._portSettingsData = new PortData(this);
617
746
 
618
747
  var curPortData = this._portSettingsData.getPorts();
619
748
 
@@ -0,0 +1,24 @@
1
+ // Internal tags to identify objects as specific JointJS types.
2
+ // Used instead of `instanceof` for performance and cross-frame safety.
3
+
4
+ // dia.Cell
5
+ export const CELL_MARKER = Symbol('joint.cellMarker');
6
+
7
+ // dia.CellCollection
8
+ export const CELL_COLLECTION_MARKER = Symbol('joint.cellCollectionMarker');
9
+
10
+ // dia.GraphLayer
11
+ export const GRAPH_LAYER_MARKER = Symbol('joint.graphLayerMarker');
12
+
13
+ // dia.GraphLayerCollection
14
+ export const GRAPH_LAYER_COLLECTION_MARKER = Symbol('joint.graphLayerCollectionMarker');
15
+
16
+ // dia.CellView
17
+ export const CELL_VIEW_MARKER = Symbol('joint.cellViewMarker');
18
+
19
+ // dia.LayerView
20
+ export const LAYER_VIEW_MARKER = Symbol('joint.layerViewMarker');
21
+
22
+ // dia.GraphLayerView
23
+ export const GRAPH_LAYER_VIEW_MARKER = Symbol('joint.graphLayerViewMarker');
24
+
@@ -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, options } = this;
10
+ const { relatedView: view } = this;
11
11
  let {
12
12
  useModelGeometry,
13
- trackPath = 'M 0 0 H calc(w) V calc(h) H 0 Z'
14
- } = options;
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
- const { relatedView: view, options } = this;
27
- let { useModelGeometry, rotate } = options;
28
- let bbox = getViewBBox(view, useModelGeometry);
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 browsers too
13
- isSafari: function() {
14
- return /Safari/.test(navigator.userAgent) && /Apple Computer/.test(navigator.vendor);
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