@metadev/daga 4.2.2 → 4.2.3

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/Changelog.md CHANGED
@@ -6,9 +6,15 @@ List of releases and changes.
6
6
 
7
7
  ## Next release Joyeuse
8
8
 
9
+ ## v. 4.2.3
10
+
11
+ - Enable toggling whether individual sections can be highlighted or entire nodes [#308](https://github.com/metadevpro/daga/pull/308)
12
+ - Enable toggling whether connections tighten automatically and whether they can loop and share ports [#309](https://github.com/metadevpro/daga/pull/309)
13
+ - Enable toggling background color of connection label [#310](https://github.com/metadevpro/daga/pull/310)
14
+
9
15
  ## v. 4.2.2
10
16
 
11
- - Fix zoom on double-click [PR 307](https://github.com/metadevpro/daga/pull/307)
17
+ - Fix zoom on double click [#307](https://github.com/metadevpro/daga/pull/307)
12
18
 
13
19
  ## v. 4.2.1
14
20
 
package/index.cjs.js CHANGED
@@ -2138,11 +2138,14 @@ class DiagramConnection extends DiagramElement {
2138
2138
  * @public
2139
2139
  */
2140
2140
  tighten() {
2141
- var _a, _b;
2142
- if (((_a = this.start) === null || _a === void 0 ? void 0 : _a.rootElement) && this.end) {
2141
+ var _a, _b, _c, _d, _e;
2142
+ const allowConnectionLoops = ((_a = this.model.canvas) === null || _a === void 0 ? void 0 : _a.allowConnectionLoops) || false;
2143
+ const allowSharingPorts = ((_b = this.model.canvas) === null || _b === void 0 ? void 0 : _b.allowSharingPorts) !== false;
2144
+ const allowSharingBothPorts = ((_c = this.model.canvas) === null || _c === void 0 ? void 0 : _c.allowSharingBothPorts) || false;
2145
+ if (((_d = this.start) === null || _d === void 0 ? void 0 : _d.rootElement) && this.end) {
2143
2146
  const alternativeStartPortsSortedByDistanceAscending = this.start.rootElement.ports.map(p => [p, p.distanceTo(this.end.coords)]).sort((a, b) => a[1] - b[1]).map(a => a[0]);
2144
2147
  checkAlternativeStartPorts: for (const alternativeStartPort of alternativeStartPortsSortedByDistanceAscending) {
2145
- if (alternativeStartPort === this.end) {
2148
+ if (!allowConnectionLoops && alternativeStartPort === this.end) {
2146
2149
  // alternative start port not valid, it is the same as the end port
2147
2150
  continue checkAlternativeStartPorts;
2148
2151
  }
@@ -2150,7 +2153,11 @@ class DiagramConnection extends DiagramElement {
2150
2153
  // alternative start port not valid, it doesn't allow outgoing connections
2151
2154
  continue checkAlternativeStartPorts;
2152
2155
  }
2153
- {
2156
+ if (!allowSharingPorts && (alternativeStartPort.incomingConnections.length === 1 && alternativeStartPort.incomingConnections[0] !== this || alternativeStartPort.incomingConnections.length > 1 || alternativeStartPort.outgoingConnections.length === 1 && alternativeStartPort.outgoingConnections[0] !== this || alternativeStartPort.outgoingConnections.length > 1)) {
2157
+ // alternative start port not valid, it already has other connections
2158
+ continue checkAlternativeStartPorts;
2159
+ }
2160
+ if (!allowSharingBothPorts) {
2154
2161
  for (const connection of alternativeStartPort.outgoingConnections) {
2155
2162
  if (connection !== this && connection.end === this.end) {
2156
2163
  // alternative start port not valid, there is a connection whose start and end matches the alternative start port and this connection's end
@@ -2173,10 +2180,10 @@ class DiagramConnection extends DiagramElement {
2173
2180
  }
2174
2181
  }
2175
2182
  }
2176
- if (((_b = this.end) === null || _b === void 0 ? void 0 : _b.rootElement) && this.start) {
2183
+ if (((_e = this.end) === null || _e === void 0 ? void 0 : _e.rootElement) && this.start) {
2177
2184
  const alternativeEndPortsSortedByDistanceAscending = this.end.rootElement.ports.map(p => [p, p.distanceTo(this.start.coords)]).sort((a, b) => a[1] - b[1]).map(a => a[0]);
2178
2185
  checkAlternativeEndPorts: for (const alternativeEndPort of alternativeEndPortsSortedByDistanceAscending) {
2179
- if (alternativeEndPort === this.start) {
2186
+ if (!allowConnectionLoops && alternativeEndPort === this.start) {
2180
2187
  // alternative end port not valid, it is the same as the end port
2181
2188
  continue checkAlternativeEndPorts;
2182
2189
  }
@@ -2184,7 +2191,11 @@ class DiagramConnection extends DiagramElement {
2184
2191
  // alternative end port not valid, it doesn't allow incoming connections
2185
2192
  continue checkAlternativeEndPorts;
2186
2193
  }
2187
- {
2194
+ if (!allowSharingPorts && (alternativeEndPort.outgoingConnections.length === 1 && alternativeEndPort.outgoingConnections[0] !== this || alternativeEndPort.outgoingConnections.length > 1 || alternativeEndPort.incomingConnections.length === 1 && alternativeEndPort.incomingConnections[0] !== this || alternativeEndPort.incomingConnections.length > 1)) {
2195
+ // alternative end port not valid, it already has other connections
2196
+ continue checkAlternativeEndPorts;
2197
+ }
2198
+ if (!allowSharingBothPorts) {
2188
2199
  for (const connection of alternativeEndPort.incomingConnections) {
2189
2200
  if (connection !== this && connection.start === this.start) {
2190
2201
  // alternative end port not valid, there is a connection whose start and end matches the alternative end port and this connection's start
@@ -2292,6 +2303,7 @@ const DIAGRAM_FIELD_DEFAULTS = {
2292
2303
  fontFamily: "'Wonder Unit Sans', sans-serif",
2293
2304
  color: '#000000',
2294
2305
  selectedColor: '#000000',
2306
+ backgroundColor: '#00000000',
2295
2307
  horizontalAlign: exports.HorizontalAlign.Center,
2296
2308
  verticalAlign: exports.VerticalAlign.Center,
2297
2309
  orientation: exports.Side.Top,
@@ -2948,6 +2960,7 @@ class DiagramSection extends DiagramElement {
2948
2960
  * @public
2949
2961
  */
2950
2962
  setGeometry(geometry) {
2963
+ var _a;
2951
2964
  const oldCoordsX = [this.coords[0], this.coords[0] + this.width];
2952
2965
  const oldCoordsY = [this.coords[1], this.coords[1] + this.height];
2953
2966
  this.coords = [...geometry.coords];
@@ -2971,8 +2984,10 @@ class DiagramSection extends DiagramElement {
2971
2984
  for (const decorator of this.decorators) {
2972
2985
  decorator.move(translatePointWithAnchors(decorator.coords, oldCoordsX, oldCoordsY, newCoordsX, newCoordsY, decorator.anchorPointX, decorator.anchorPointY));
2973
2986
  }
2987
+ if (((_a = this.model.canvas) === null || _a === void 0 ? void 0 : _a.autoTightenConnections) !== false) {
2988
+ this.getConnections().forEach(c => c.tighten());
2989
+ }
2974
2990
  // Update canvas.
2975
- this.getConnections().forEach(c => c.tighten());
2976
2991
  this.updateInView();
2977
2992
  }
2978
2993
  }
@@ -3691,6 +3706,7 @@ class DiagramNode extends DiagramElement {
3691
3706
  * @public
3692
3707
  */
3693
3708
  setGeometry(geometry) {
3709
+ var _a;
3694
3710
  this.raise();
3695
3711
  const oldCoordsX = [this.coords[0], this.coords[0] + this.width];
3696
3712
  const oldCoordsY = [this.coords[1], this.coords[1] + this.height];
@@ -3728,8 +3744,10 @@ class DiagramNode extends DiagramElement {
3728
3744
  for (const decorator of this.decorators) {
3729
3745
  decorator.move(translatePointWithAnchors(decorator.coords, oldCoordsX, oldCoordsY, newCoordsX, newCoordsY, decorator.anchorPointX, decorator.anchorPointY));
3730
3746
  }
3747
+ if (((_a = this.model.canvas) === null || _a === void 0 ? void 0 : _a.autoTightenConnections) !== false) {
3748
+ this.getConnections().forEach(c => c.tighten());
3749
+ }
3731
3750
  // Update canvas.
3732
- this.getConnections().forEach(c => c.tighten());
3733
3751
  this.updateInView();
3734
3752
  }
3735
3753
  /**
@@ -6423,10 +6441,11 @@ class DiagramUserHighlight extends DiagramElementSet {
6423
6441
  * @public
6424
6442
  * @param canvas A canvas.
6425
6443
  */
6426
- constructor(canvas) {
6444
+ constructor(canvas, highlightSections = true) {
6427
6445
  super();
6428
6446
  this.focus = undefined;
6429
6447
  this.canvas = canvas;
6448
+ this.highlightSections = highlightSections;
6430
6449
  }
6431
6450
  /**
6432
6451
  * Gets the focus of the user highlight, which is the element where the current user highlight started regardless of which other elements were highlighted as a consequence.
@@ -6452,6 +6471,20 @@ class DiagramUserHighlight extends DiagramElementSet {
6452
6471
  add(element) {
6453
6472
  super.add(element);
6454
6473
  if (element instanceof DiagramNode) {
6474
+ if (!this.highlightSections) {
6475
+ for (const section of element.sections) {
6476
+ super.add(section);
6477
+ for (const port of section.ports) {
6478
+ super.add(port);
6479
+ this.canvas.updatePortsInView(port.id);
6480
+ }
6481
+ if (section.label) {
6482
+ super.add(section.label);
6483
+ this.canvas.updateFieldsInView(section.label.id);
6484
+ }
6485
+ this.canvas.updateSectionsInView(section.id);
6486
+ }
6487
+ }
6455
6488
  for (const port of element.ports) {
6456
6489
  super.add(port);
6457
6490
  this.canvas.updatePortsInView(port.id);
@@ -6462,15 +6495,19 @@ class DiagramUserHighlight extends DiagramElementSet {
6462
6495
  }
6463
6496
  this.canvas.updateNodesInView(element.id);
6464
6497
  } else if (element instanceof DiagramSection) {
6465
- for (const port of element.ports) {
6466
- super.add(port);
6467
- this.canvas.updatePortsInView(port.id);
6468
- }
6469
- if (element.label) {
6470
- super.add(element.label);
6471
- this.canvas.updateFieldsInView(element.label.id);
6498
+ if (!this.highlightSections && element.node) {
6499
+ this.add(element.node);
6500
+ } else {
6501
+ for (const port of element.ports) {
6502
+ super.add(port);
6503
+ this.canvas.updatePortsInView(port.id);
6504
+ }
6505
+ if (element.label) {
6506
+ super.add(element.label);
6507
+ this.canvas.updateFieldsInView(element.label.id);
6508
+ }
6509
+ this.canvas.updateSectionsInView(element.id);
6472
6510
  }
6473
- this.canvas.updateSectionsInView(element.id);
6474
6511
  } else if (element instanceof DiagramPort) {
6475
6512
  if (element.label) {
6476
6513
  super.add(element.label);
@@ -6939,7 +6976,6 @@ const RESIZER_THICKNESS = 6;
6939
6976
  */
6940
6977
  const ACTION_STACK_SIZE = 25;
6941
6978
  const UNFINISHED_CONNECTION_ID = 'diagram-connection-unfinished';
6942
- const MAX_DISTANCE_TO_PORT = 100;
6943
6979
  class DiagramCanvas {
6944
6980
  get connectionType() {
6945
6981
  return this._connectionType;
@@ -6957,7 +6993,7 @@ class DiagramCanvas {
6957
6993
  * @param config The configuration object used to set the parameters of this canvas.
6958
6994
  */
6959
6995
  constructor(parentComponent, config) {
6960
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
6996
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5;
6961
6997
  this.backgroundPatternId = `daga-background-pattern-id-${DiagramCanvas.canvasCount++}`;
6962
6998
  this.zoomTransform = d3__namespace.zoomIdentity;
6963
6999
  // used to distinguish drags from clicks when dragging elements and during multiple selection
@@ -6973,19 +7009,24 @@ class DiagramCanvas {
6973
7009
  this.parentComponent = parentComponent;
6974
7010
  this.model = new DiagramModel(this, undefined, config.name || 'unnamed', '', config.type || '', config.properties || []);
6975
7011
  this.userSelection = new DiagramUserSelection(this);
6976
- this.userHighlight = new DiagramUserHighlight(this);
6977
- this.contextMenu = new DiagramContextMenu(this, (_a = config.canvas) === null || _a === void 0 ? void 0 : _a.contextMenu);
6978
- this.backgroundColor = ((_b = config.canvas) === null || _b === void 0 ? void 0 : _b.backgroundColor) || '#FFFFFF';
6979
- this.gridStyle = (_e = (_d = (_c = config.canvas) === null || _c === void 0 ? void 0 : _c.grid) === null || _d === void 0 ? void 0 : _d.style) !== null && _e !== void 0 ? _e : GRID_DEFAULTS.style;
6980
- this.gridSize = ((_g = (_f = config.canvas) === null || _f === void 0 ? void 0 : _f.grid) === null || _g === void 0 ? void 0 : _g.enabled) === false || ((_h = config.canvas) === null || _h === void 0 ? void 0 : _h.grid) === undefined ? 0 : Math.abs(((_k = (_j = config.canvas) === null || _j === void 0 ? void 0 : _j.grid) === null || _k === void 0 ? void 0 : _k.spacing) || GRID_DEFAULTS.spacing);
6981
- this.gridThickness = Math.abs(((_m = (_l = config.canvas) === null || _l === void 0 ? void 0 : _l.grid) === null || _m === void 0 ? void 0 : _m.thickness) || GRID_DEFAULTS.thickness);
6982
- this.gridColor = ((_p = (_o = config.canvas) === null || _o === void 0 ? void 0 : _o.grid) === null || _p === void 0 ? void 0 : _p.color) || GRID_DEFAULTS.color;
6983
- this.snapToGrid = ((_r = (_q = config.canvas) === null || _q === void 0 ? void 0 : _q.grid) === null || _r === void 0 ? void 0 : _r.enabled) === false || ((_s = config.canvas) === null || _s === void 0 ? void 0 : _s.grid) === undefined ? false : ((_u = (_t = config.canvas) === null || _t === void 0 ? void 0 : _t.grid) === null || _u === void 0 ? void 0 : _u.snap) || GRID_DEFAULTS.snap;
6984
- this.zoomFactor = ((_v = config.canvas) === null || _v === void 0 ? void 0 : _v.zoomFactor) || 2;
6985
- this.panRate = ((_w = config.canvas) === null || _w === void 0 ? void 0 : _w.panRate) || 100;
6986
- this.inferConnectionType = config.inferConnectionType || false;
7012
+ this.userHighlight = new DiagramUserHighlight(this, ((_a = config.canvas) === null || _a === void 0 ? void 0 : _a.highlightSections) !== false);
7013
+ this.contextMenu = new DiagramContextMenu(this, (_b = config.canvas) === null || _b === void 0 ? void 0 : _b.contextMenu);
7014
+ this.backgroundColor = ((_c = config.canvas) === null || _c === void 0 ? void 0 : _c.backgroundColor) || '#FFFFFF';
7015
+ this.gridStyle = (_f = (_e = (_d = config.canvas) === null || _d === void 0 ? void 0 : _d.grid) === null || _e === void 0 ? void 0 : _e.style) !== null && _f !== void 0 ? _f : GRID_DEFAULTS.style;
7016
+ this.gridSize = ((_h = (_g = config.canvas) === null || _g === void 0 ? void 0 : _g.grid) === null || _h === void 0 ? void 0 : _h.enabled) === false || ((_j = config.canvas) === null || _j === void 0 ? void 0 : _j.grid) === undefined ? 0 : Math.abs(((_l = (_k = config.canvas) === null || _k === void 0 ? void 0 : _k.grid) === null || _l === void 0 ? void 0 : _l.spacing) || GRID_DEFAULTS.spacing);
7017
+ this.gridThickness = Math.abs(((_o = (_m = config.canvas) === null || _m === void 0 ? void 0 : _m.grid) === null || _o === void 0 ? void 0 : _o.thickness) || GRID_DEFAULTS.thickness);
7018
+ this.gridColor = ((_q = (_p = config.canvas) === null || _p === void 0 ? void 0 : _p.grid) === null || _q === void 0 ? void 0 : _q.color) || GRID_DEFAULTS.color;
7019
+ this.snapToGrid = ((_s = (_r = config.canvas) === null || _r === void 0 ? void 0 : _r.grid) === null || _s === void 0 ? void 0 : _s.enabled) === false || ((_t = config.canvas) === null || _t === void 0 ? void 0 : _t.grid) === undefined ? false : ((_v = (_u = config.canvas) === null || _u === void 0 ? void 0 : _u.grid) === null || _v === void 0 ? void 0 : _v.snap) || GRID_DEFAULTS.snap;
7020
+ this.zoomFactor = ((_w = config.canvas) === null || _w === void 0 ? void 0 : _w.zoomFactor) || 2;
7021
+ this.panRate = ((_x = config.canvas) === null || _x === void 0 ? void 0 : _x.panRate) || 100;
7022
+ this.inferConnectionType = ((_y = config.connectionSettings) === null || _y === void 0 ? void 0 : _y.inferConnectionType) || false;
7023
+ this.autoTightenConnections = ((_z = config.connectionSettings) === null || _z === void 0 ? void 0 : _z.autoTighten) !== false;
7024
+ this.allowConnectionLoops = ((_0 = config.connectionSettings) === null || _0 === void 0 ? void 0 : _0.allowLoops) || false;
7025
+ this.allowSharingPorts = ((_1 = config.connectionSettings) === null || _1 === void 0 ? void 0 : _1.sharePorts) !== false;
7026
+ this.allowSharingBothPorts = ((_2 = config.connectionSettings) === null || _2 === void 0 ? void 0 : _2.shareBothPorts) || false;
7027
+ this.portHighlightRadius = ((_3 = config.connectionSettings) === null || _3 === void 0 ? void 0 : _3.portHighlightRadius) || 100;
6987
7028
  this.multipleSelectionOn = false;
6988
- this.priorityThresholds = ((_x = config.canvas) === null || _x === void 0 ? void 0 : _x.priorityThresholds) || [];
7029
+ this.priorityThresholds = ((_4 = config.canvas) === null || _4 === void 0 ? void 0 : _4.priorityThresholds) || [];
6989
7030
  this.priorityThreshold = this.priorityThresholds ? this.priorityThresholds[0] : undefined;
6990
7031
  this.layoutFormat = config.layoutFormat;
6991
7032
  this.userActions = config.userActions || {};
@@ -7012,7 +7053,7 @@ class DiagramCanvas {
7012
7053
  const connectionType = new DiagramConnectionType(Object.assign(Object.assign({}, config.connectionTypeDefaults), connectionTypeConfig));
7013
7054
  this.model.connections.types.add(connectionType);
7014
7055
  }
7015
- this._connectionType = config.defaultConnection !== undefined ? this.model.connections.types.get(config.defaultConnection) : undefined;
7056
+ this._connectionType = ((_5 = config === null || config === void 0 ? void 0 : config.connectionSettings) === null || _5 === void 0 ? void 0 : _5.defaultConnection) !== undefined ? this.model.connections.types.get(config.connectionSettings.defaultConnection) : undefined;
7016
7057
  }
7017
7058
  }
7018
7059
  addValidator(validator) {
@@ -7860,7 +7901,7 @@ class DiagramCanvas {
7860
7901
  if (this.multipleSelectionOn || this.secondaryButton) {
7861
7902
  this.startMultipleSelection(event);
7862
7903
  } else {
7863
- if (this.canUserPerformAction(exports.DiagramActions.AddConnection) && !d.removed) {
7904
+ if (this.canUserPerformAction(exports.DiagramActions.AddConnection) && (this.allowSharingPorts || d.incomingConnections.length === 0 && d.outgoingConnections.length === 0) && !d.removed) {
7864
7905
  setCursorStyle(exports.CursorStyle.Grabbing);
7865
7906
  this.startConnection(d);
7866
7907
  // should be true after having called this.startConnection()
@@ -7906,7 +7947,7 @@ class DiagramCanvas {
7906
7947
  closestPortFound = port;
7907
7948
  }
7908
7949
  }
7909
- if (closestPortFound && minDistanceFound < MAX_DISTANCE_TO_PORT) {
7950
+ if (closestPortFound && minDistanceFound < this.portHighlightRadius) {
7910
7951
  this.userHighlight.focusOn(closestPortFound);
7911
7952
  } else {
7912
7953
  this.userHighlight.clear();
@@ -8311,6 +8352,77 @@ class DiagramCanvas {
8311
8352
  const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), connection.type.label);
8312
8353
  if (pathNode) {
8313
8354
  const pathLength = pathNode.getTotalLength();
8355
+ let startLabelShiftX = 0;
8356
+ let startLabelShiftY = 0;
8357
+ let middleLabelShiftX = 0;
8358
+ let middleLabelShiftY = 0;
8359
+ let endLabelShiftX = 0;
8360
+ let endLabelShiftY = 0;
8361
+ if (labelConfiguration.backgroundColor === '#00000000') {
8362
+ // background color is transparent / not set, so we find an alternative position for the label
8363
+ const deltaX = connection.endCoords[0] - connection.startCoords[0];
8364
+ const deltaY = connection.endCoords[1] - connection.startCoords[1];
8365
+ switch (connection.startDirection) {
8366
+ case exports.Side.Top:
8367
+ startLabelShiftX = deltaX >= 0 ? 1 : -1;
8368
+ middleLabelShiftX = startLabelShiftX;
8369
+ endLabelShiftX = startLabelShiftX;
8370
+ startLabelShiftY = -1;
8371
+ break;
8372
+ case exports.Side.Bottom:
8373
+ startLabelShiftX = deltaX >= 0 ? 1 : -1;
8374
+ middleLabelShiftX = startLabelShiftX;
8375
+ endLabelShiftX = startLabelShiftX;
8376
+ startLabelShiftY = 1;
8377
+ break;
8378
+ case exports.Side.Left:
8379
+ startLabelShiftX = -1;
8380
+ startLabelShiftY = deltaY > 0 ? 1 : -1;
8381
+ middleLabelShiftY = startLabelShiftY;
8382
+ endLabelShiftY = startLabelShiftY;
8383
+ break;
8384
+ case exports.Side.Right:
8385
+ startLabelShiftX = 1;
8386
+ startLabelShiftY = deltaY > 0 ? 1 : -1;
8387
+ middleLabelShiftY = startLabelShiftY;
8388
+ endLabelShiftY = startLabelShiftY;
8389
+ break;
8390
+ default:
8391
+ startLabelShiftX = 1;
8392
+ middleLabelShiftX = startLabelShiftX;
8393
+ endLabelShiftX = startLabelShiftX;
8394
+ startLabelShiftY = -1;
8395
+ middleLabelShiftY = startLabelShiftY;
8396
+ endLabelShiftY = startLabelShiftY;
8397
+ }
8398
+ switch (connection.endDirection) {
8399
+ case exports.Side.Top:
8400
+ endLabelShiftX = deltaX >= 0 ? 1 : -1;
8401
+ middleLabelShiftX = endLabelShiftX;
8402
+ endLabelShiftY = 1;
8403
+ break;
8404
+ case exports.Side.Bottom:
8405
+ endLabelShiftX = deltaX >= 0 ? 1 : -1;
8406
+ middleLabelShiftX = endLabelShiftX;
8407
+ endLabelShiftY = -1;
8408
+ break;
8409
+ case exports.Side.Left:
8410
+ endLabelShiftX = -1;
8411
+ endLabelShiftY = deltaY > 0 ? 1 : -1;
8412
+ middleLabelShiftY = endLabelShiftY;
8413
+ break;
8414
+ case exports.Side.Right:
8415
+ endLabelShiftX = 1;
8416
+ endLabelShiftY = deltaY > 0 ? 1 : -1;
8417
+ middleLabelShiftY = endLabelShiftY;
8418
+ break;
8419
+ default:
8420
+ endLabelShiftX = 1;
8421
+ middleLabelShiftX = endLabelShiftX;
8422
+ endLabelShiftY = -1;
8423
+ middleLabelShiftY = endLabelShiftY;
8424
+ }
8425
+ }
8314
8426
  // bind start labels
8315
8427
  connectionSelection.select('g.diagram-connection-start-label text').attr('x', 0).attr('y', labelConfiguration.fontSize / 3).attr('text-anchor', 'middle').attr('font-family', labelConfiguration.fontFamily).attr('font-size', labelConfiguration.fontSize).attr('fill', connection.selected ? labelConfiguration.selectedColor : labelConfiguration.color).style('font-kerning', 'none').text(connection.startLabel);
8316
8428
  const startLabelBoundingRect = (_a = connectionSelection.select('g.diagram-connection-start-label text').node()) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
@@ -8319,8 +8431,8 @@ class DiagramCanvas {
8319
8431
  const boundingWidth = !connection.startLabel ? 0 : startLabelBoundingRect.width / this.zoomTransform.k + getLeftPadding$1(labelConfiguration) + getRightPadding$1(labelConfiguration);
8320
8432
  const boundingHeight = !connection.startLabel ? 0 : startLabelBoundingRect.height / this.zoomTransform.k + getTopPadding$1(labelConfiguration) + getBottomPadding$1(labelConfiguration);
8321
8433
  const pathStartLabelPoint = pathNode.getPointAtLength(Math.max(getLeftMargin(labelConfiguration) + boundingWidth / 2, getRightMargin(labelConfiguration) + boundingWidth / 2, getTopMargin(labelConfiguration) + boundingHeight / 2, getBottomMargin(labelConfiguration) + boundingHeight / 2));
8322
- connectionSelection.select('g.diagram-connection-start-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', connection.look.color).attr('stroke', 'none');
8323
- connectionSelection.select('g.diagram-connection-start-label').attr('transform', `translate(${pathStartLabelPoint.x},${pathStartLabelPoint.y})`);
8434
+ connectionSelection.select('g.diagram-connection-start-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', labelConfiguration.backgroundColor).attr('stroke', 'none');
8435
+ connectionSelection.select('g.diagram-connection-start-label').attr('transform', `translate(${pathStartLabelPoint.x + startLabelShiftX * boundingWidth},${pathStartLabelPoint.y + startLabelShiftY * boundingHeight})`);
8324
8436
  }
8325
8437
  // bind middle labels
8326
8438
  connectionSelection.select('g.diagram-connection-middle-label text').attr('x', 0).attr('y', labelConfiguration.fontSize / 3).attr('text-anchor', 'middle').attr('font-family', labelConfiguration.fontFamily).attr('font-size', labelConfiguration.fontSize).attr('fill', connection.selected ? labelConfiguration.selectedColor : labelConfiguration.color).style('font-kerning', 'none').text(connection.middleLabel);
@@ -8330,8 +8442,8 @@ class DiagramCanvas {
8330
8442
  const boundingWidth = !connection.middleLabel ? 0 : middleLabelBoundingRect.width / this.zoomTransform.k + getLeftPadding$1(labelConfiguration) + getRightPadding$1(labelConfiguration);
8331
8443
  const boundingHeight = !connection.middleLabel ? 0 : middleLabelBoundingRect.height / this.zoomTransform.k + getTopPadding$1(labelConfiguration) + getBottomPadding$1(labelConfiguration);
8332
8444
  const pathMiddleLabelPoint = pathNode.getPointAtLength(pathLength / 2);
8333
- connectionSelection.select('g.diagram-connection-middle-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', connection.look.color).attr('stroke', 'none');
8334
- connectionSelection.select('g.diagram-connection-middle-label').attr('transform', `translate(${pathMiddleLabelPoint.x},${pathMiddleLabelPoint.y})`);
8445
+ connectionSelection.select('g.diagram-connection-middle-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', labelConfiguration.backgroundColor).attr('stroke', 'none');
8446
+ connectionSelection.select('g.diagram-connection-middle-label').attr('transform', `translate(${pathMiddleLabelPoint.x + middleLabelShiftX * boundingWidth},${pathMiddleLabelPoint.y + middleLabelShiftY * boundingHeight})`);
8335
8447
  }
8336
8448
  // bind end labels
8337
8449
  connectionSelection.select('g.diagram-connection-end-label text').attr('x', 0).attr('y', labelConfiguration.fontSize / 3).attr('text-anchor', 'middle').attr('font-family', labelConfiguration.fontFamily).attr('font-size', labelConfiguration.fontSize).attr('fill', connection.selected ? labelConfiguration.selectedColor : labelConfiguration.color).style('font-kerning', 'none').text(connection.endLabel);
@@ -8341,8 +8453,8 @@ class DiagramCanvas {
8341
8453
  const boundingWidth = !connection.endLabel ? 0 : endLabelBoundingRect.width / this.zoomTransform.k + getLeftPadding$1(labelConfiguration) + getRightPadding$1(labelConfiguration);
8342
8454
  const boundingHeight = !connection.endLabel ? 0 : endLabelBoundingRect.height / this.zoomTransform.k + getTopPadding$1(labelConfiguration) + getBottomPadding$1(labelConfiguration);
8343
8455
  const pathEndLabelPoint = pathNode.getPointAtLength(pathLength - Math.max(getLeftMargin(labelConfiguration) + boundingWidth / 2, getRightMargin(labelConfiguration) + boundingWidth / 2, getTopMargin(labelConfiguration) + boundingHeight / 2, getBottomMargin(labelConfiguration) + boundingHeight / 2));
8344
- connectionSelection.select('g.diagram-connection-end-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', connection.look.color).attr('stroke', 'none');
8345
- connectionSelection.select('g.diagram-connection-end-label').attr('transform', `translate(${pathEndLabelPoint.x},${pathEndLabelPoint.y})`);
8456
+ connectionSelection.select('g.diagram-connection-end-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', labelConfiguration.backgroundColor).attr('stroke', 'none');
8457
+ connectionSelection.select('g.diagram-connection-end-label').attr('transform', `translate(${pathEndLabelPoint.x + endLabelShiftX * boundingWidth},${pathEndLabelPoint.y + endLabelShiftY * boundingHeight})`);
8346
8458
  }
8347
8459
  }
8348
8460
  }
@@ -8514,51 +8626,61 @@ class DiagramCanvas {
8514
8626
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
8515
8627
  this.userHighlight.clear();
8516
8628
  if (this.unfinishedConnection !== undefined) {
8517
- if (this.unfinishedConnection.start !== port) {
8518
- if (this.unfinishedConnection.type.canStartFromType(((_d = (_c = (_b = (_a = this.unfinishedConnection) === null || _a === void 0 ? void 0 : _a.start) === null || _b === void 0 ? void 0 : _b.getNode()) === null || _c === void 0 ? void 0 : _c.type) === null || _d === void 0 ? void 0 : _d.id) || '') && ((_f = (_e = this.unfinishedConnection) === null || _e === void 0 ? void 0 : _e.start) === null || _f === void 0 ? void 0 : _f.allowsOutgoing) && this.unfinishedConnection.type.canFinishOnType(((_h = (_g = port.getNode()) === null || _g === void 0 ? void 0 : _g.type) === null || _h === void 0 ? void 0 : _h.id) || '') && port.allowsIncoming) {
8519
- const addConnectionAction = new AddConnectionAction(this, this.unfinishedConnection.type, (_j = this.unfinishedConnection.start) === null || _j === void 0 ? void 0 : _j.id, port.id);
8520
- // clean up the previous unfinished connection
8521
- this.dropConnection();
8522
- addConnectionAction.do();
8523
- this.actionStack.add(addConnectionAction);
8524
- } else if (this.unfinishedConnection.type.canFinishOnType(((_o = (_m = (_l = (_k = this.unfinishedConnection) === null || _k === void 0 ? void 0 : _k.start) === null || _l === void 0 ? void 0 : _l.getNode()) === null || _m === void 0 ? void 0 : _m.type) === null || _o === void 0 ? void 0 : _o.id) || '') && ((_q = (_p = this.unfinishedConnection) === null || _p === void 0 ? void 0 : _p.start) === null || _q === void 0 ? void 0 : _q.allowsIncoming) && this.unfinishedConnection.type.canStartFromType(((_s = (_r = port.getNode()) === null || _r === void 0 ? void 0 : _r.type) === null || _s === void 0 ? void 0 : _s.id) || '') && port.allowsOutgoing) {
8525
- const addConnectionAction = new AddConnectionAction(this, this.unfinishedConnection.type, port.id, (_t = this.unfinishedConnection.start) === null || _t === void 0 ? void 0 : _t.id);
8526
- // clean up the previous unfinished connection
8527
- this.dropConnection();
8528
- addConnectionAction.do();
8529
- this.actionStack.add(addConnectionAction);
8530
- } else {
8531
- if (this.inferConnectionType) {
8532
- let differentConnectionType = this.model.connections.types.all().find(t => {
8629
+ if (!this.allowConnectionLoops && this.unfinishedConnection.start === port) {
8630
+ this.dropConnection();
8631
+ return;
8632
+ }
8633
+ if (!this.allowSharingPorts && (port.incomingConnections.length > 0 || port.outgoingConnections.length > 0)) {
8634
+ this.dropConnection();
8635
+ return;
8636
+ }
8637
+ if (!this.allowSharingBothPorts && this.model.connections.find(c => {
8638
+ var _a, _b;
8639
+ return c.start === ((_a = this.unfinishedConnection) === null || _a === void 0 ? void 0 : _a.start) && c.end === port || c.end === ((_b = this.unfinishedConnection) === null || _b === void 0 ? void 0 : _b.start) && c.start === port;
8640
+ }) !== undefined) {
8641
+ this.dropConnection();
8642
+ return;
8643
+ }
8644
+ if (this.unfinishedConnection.type.canStartFromType(((_d = (_c = (_b = (_a = this.unfinishedConnection) === null || _a === void 0 ? void 0 : _a.start) === null || _b === void 0 ? void 0 : _b.getNode()) === null || _c === void 0 ? void 0 : _c.type) === null || _d === void 0 ? void 0 : _d.id) || '') && ((_f = (_e = this.unfinishedConnection) === null || _e === void 0 ? void 0 : _e.start) === null || _f === void 0 ? void 0 : _f.allowsOutgoing) && this.unfinishedConnection.type.canFinishOnType(((_h = (_g = port.getNode()) === null || _g === void 0 ? void 0 : _g.type) === null || _h === void 0 ? void 0 : _h.id) || '') && port.allowsIncoming) {
8645
+ const addConnectionAction = new AddConnectionAction(this, this.unfinishedConnection.type, (_j = this.unfinishedConnection.start) === null || _j === void 0 ? void 0 : _j.id, port.id);
8646
+ // clean up the previous unfinished connection
8647
+ this.dropConnection();
8648
+ addConnectionAction.do();
8649
+ this.actionStack.add(addConnectionAction);
8650
+ } else if (this.unfinishedConnection.type.canFinishOnType(((_o = (_m = (_l = (_k = this.unfinishedConnection) === null || _k === void 0 ? void 0 : _k.start) === null || _l === void 0 ? void 0 : _l.getNode()) === null || _m === void 0 ? void 0 : _m.type) === null || _o === void 0 ? void 0 : _o.id) || '') && ((_q = (_p = this.unfinishedConnection) === null || _p === void 0 ? void 0 : _p.start) === null || _q === void 0 ? void 0 : _q.allowsIncoming) && this.unfinishedConnection.type.canStartFromType(((_s = (_r = port.getNode()) === null || _r === void 0 ? void 0 : _r.type) === null || _s === void 0 ? void 0 : _s.id) || '') && port.allowsOutgoing) {
8651
+ const addConnectionAction = new AddConnectionAction(this, this.unfinishedConnection.type, port.id, (_t = this.unfinishedConnection.start) === null || _t === void 0 ? void 0 : _t.id);
8652
+ // clean up the previous unfinished connection
8653
+ this.dropConnection();
8654
+ addConnectionAction.do();
8655
+ this.actionStack.add(addConnectionAction);
8656
+ } else {
8657
+ if (this.inferConnectionType) {
8658
+ let differentConnectionType = this.model.connections.types.all().find(t => {
8659
+ var _a, _b, _c, _d, _e, _f, _g, _h;
8660
+ return t.canStartFromType(((_d = (_c = (_b = (_a = this.unfinishedConnection) === null || _a === void 0 ? void 0 : _a.start) === null || _b === void 0 ? void 0 : _b.getNode()) === null || _c === void 0 ? void 0 : _c.type) === null || _d === void 0 ? void 0 : _d.id) || '') && ((_f = (_e = this.unfinishedConnection) === null || _e === void 0 ? void 0 : _e.start) === null || _f === void 0 ? void 0 : _f.allowsOutgoing) && t.canFinishOnType(((_h = (_g = port.getNode()) === null || _g === void 0 ? void 0 : _g.type) === null || _h === void 0 ? void 0 : _h.id) || '') && port.allowsIncoming;
8661
+ });
8662
+ let invertConnection = false;
8663
+ if (differentConnectionType === undefined) {
8664
+ differentConnectionType = this.model.connections.types.all().find(t => {
8533
8665
  var _a, _b, _c, _d, _e, _f, _g, _h;
8534
- return t.canStartFromType(((_d = (_c = (_b = (_a = this.unfinishedConnection) === null || _a === void 0 ? void 0 : _a.start) === null || _b === void 0 ? void 0 : _b.getNode()) === null || _c === void 0 ? void 0 : _c.type) === null || _d === void 0 ? void 0 : _d.id) || '') && ((_f = (_e = this.unfinishedConnection) === null || _e === void 0 ? void 0 : _e.start) === null || _f === void 0 ? void 0 : _f.allowsOutgoing) && t.canFinishOnType(((_h = (_g = port.getNode()) === null || _g === void 0 ? void 0 : _g.type) === null || _h === void 0 ? void 0 : _h.id) || '') && port.allowsIncoming;
8666
+ return t.canFinishOnType(((_d = (_c = (_b = (_a = this.unfinishedConnection) === null || _a === void 0 ? void 0 : _a.start) === null || _b === void 0 ? void 0 : _b.getNode()) === null || _c === void 0 ? void 0 : _c.type) === null || _d === void 0 ? void 0 : _d.id) || '') && ((_f = (_e = this.unfinishedConnection) === null || _e === void 0 ? void 0 : _e.start) === null || _f === void 0 ? void 0 : _f.allowsIncoming) && t.canStartFromType(((_h = (_g = port.getNode()) === null || _g === void 0 ? void 0 : _g.type) === null || _h === void 0 ? void 0 : _h.id) || '') && port.allowsOutgoing;
8535
8667
  });
8536
- let invertConnection = false;
8537
- if (differentConnectionType === undefined) {
8538
- differentConnectionType = this.model.connections.types.all().find(t => {
8539
- var _a, _b, _c, _d, _e, _f, _g, _h;
8540
- return t.canFinishOnType(((_d = (_c = (_b = (_a = this.unfinishedConnection) === null || _a === void 0 ? void 0 : _a.start) === null || _b === void 0 ? void 0 : _b.getNode()) === null || _c === void 0 ? void 0 : _c.type) === null || _d === void 0 ? void 0 : _d.id) || '') && ((_f = (_e = this.unfinishedConnection) === null || _e === void 0 ? void 0 : _e.start) === null || _f === void 0 ? void 0 : _f.allowsIncoming) && t.canStartFromType(((_h = (_g = port.getNode()) === null || _g === void 0 ? void 0 : _g.type) === null || _h === void 0 ? void 0 : _h.id) || '') && port.allowsOutgoing;
8541
- });
8542
- invertConnection = true;
8543
- }
8544
- if (differentConnectionType !== undefined) {
8545
- const addConnectionAction = new AddConnectionAction(this, differentConnectionType, invertConnection ? port.id : (_u = this.unfinishedConnection.start) === null || _u === void 0 ? void 0 : _u.id, invertConnection ? (_v = this.unfinishedConnection.start) === null || _v === void 0 ? void 0 : _v.id : port.id);
8546
- // clean up the previous unfinished connection
8547
- this.dropConnection();
8548
- addConnectionAction.do();
8549
- this.actionStack.add(addConnectionAction);
8550
- } else {
8551
- // error: connection target of wrong type and no allowed type can be found
8552
- this.dropConnection();
8553
- }
8668
+ invertConnection = true;
8669
+ }
8670
+ if (differentConnectionType !== undefined) {
8671
+ const addConnectionAction = new AddConnectionAction(this, differentConnectionType, invertConnection ? port.id : (_u = this.unfinishedConnection.start) === null || _u === void 0 ? void 0 : _u.id, invertConnection ? (_v = this.unfinishedConnection.start) === null || _v === void 0 ? void 0 : _v.id : port.id);
8672
+ // clean up the previous unfinished connection
8673
+ this.dropConnection();
8674
+ addConnectionAction.do();
8675
+ this.actionStack.add(addConnectionAction);
8554
8676
  } else {
8555
- // error: connection target of wrong type and can't guess for a different type
8677
+ // error: connection target of wrong type and no allowed type can be found
8556
8678
  this.dropConnection();
8557
8679
  }
8680
+ } else {
8681
+ // error: connection target of wrong type and can't guess for a different type
8682
+ this.dropConnection();
8558
8683
  }
8559
- } else {
8560
- // error: start port of a connection can't also be the end port
8561
- this.dropConnection();
8562
8684
  }
8563
8685
  }
8564
8686
  }
package/index.esm.js CHANGED
@@ -2117,11 +2117,14 @@ class DiagramConnection extends DiagramElement {
2117
2117
  * @public
2118
2118
  */
2119
2119
  tighten() {
2120
- var _a, _b;
2121
- if (((_a = this.start) === null || _a === void 0 ? void 0 : _a.rootElement) && this.end) {
2120
+ var _a, _b, _c, _d, _e;
2121
+ const allowConnectionLoops = ((_a = this.model.canvas) === null || _a === void 0 ? void 0 : _a.allowConnectionLoops) || false;
2122
+ const allowSharingPorts = ((_b = this.model.canvas) === null || _b === void 0 ? void 0 : _b.allowSharingPorts) !== false;
2123
+ const allowSharingBothPorts = ((_c = this.model.canvas) === null || _c === void 0 ? void 0 : _c.allowSharingBothPorts) || false;
2124
+ if (((_d = this.start) === null || _d === void 0 ? void 0 : _d.rootElement) && this.end) {
2122
2125
  const alternativeStartPortsSortedByDistanceAscending = this.start.rootElement.ports.map(p => [p, p.distanceTo(this.end.coords)]).sort((a, b) => a[1] - b[1]).map(a => a[0]);
2123
2126
  checkAlternativeStartPorts: for (const alternativeStartPort of alternativeStartPortsSortedByDistanceAscending) {
2124
- if (alternativeStartPort === this.end) {
2127
+ if (!allowConnectionLoops && alternativeStartPort === this.end) {
2125
2128
  // alternative start port not valid, it is the same as the end port
2126
2129
  continue checkAlternativeStartPorts;
2127
2130
  }
@@ -2129,7 +2132,11 @@ class DiagramConnection extends DiagramElement {
2129
2132
  // alternative start port not valid, it doesn't allow outgoing connections
2130
2133
  continue checkAlternativeStartPorts;
2131
2134
  }
2132
- {
2135
+ if (!allowSharingPorts && (alternativeStartPort.incomingConnections.length === 1 && alternativeStartPort.incomingConnections[0] !== this || alternativeStartPort.incomingConnections.length > 1 || alternativeStartPort.outgoingConnections.length === 1 && alternativeStartPort.outgoingConnections[0] !== this || alternativeStartPort.outgoingConnections.length > 1)) {
2136
+ // alternative start port not valid, it already has other connections
2137
+ continue checkAlternativeStartPorts;
2138
+ }
2139
+ if (!allowSharingBothPorts) {
2133
2140
  for (const connection of alternativeStartPort.outgoingConnections) {
2134
2141
  if (connection !== this && connection.end === this.end) {
2135
2142
  // alternative start port not valid, there is a connection whose start and end matches the alternative start port and this connection's end
@@ -2152,10 +2159,10 @@ class DiagramConnection extends DiagramElement {
2152
2159
  }
2153
2160
  }
2154
2161
  }
2155
- if (((_b = this.end) === null || _b === void 0 ? void 0 : _b.rootElement) && this.start) {
2162
+ if (((_e = this.end) === null || _e === void 0 ? void 0 : _e.rootElement) && this.start) {
2156
2163
  const alternativeEndPortsSortedByDistanceAscending = this.end.rootElement.ports.map(p => [p, p.distanceTo(this.start.coords)]).sort((a, b) => a[1] - b[1]).map(a => a[0]);
2157
2164
  checkAlternativeEndPorts: for (const alternativeEndPort of alternativeEndPortsSortedByDistanceAscending) {
2158
- if (alternativeEndPort === this.start) {
2165
+ if (!allowConnectionLoops && alternativeEndPort === this.start) {
2159
2166
  // alternative end port not valid, it is the same as the end port
2160
2167
  continue checkAlternativeEndPorts;
2161
2168
  }
@@ -2163,7 +2170,11 @@ class DiagramConnection extends DiagramElement {
2163
2170
  // alternative end port not valid, it doesn't allow incoming connections
2164
2171
  continue checkAlternativeEndPorts;
2165
2172
  }
2166
- {
2173
+ if (!allowSharingPorts && (alternativeEndPort.outgoingConnections.length === 1 && alternativeEndPort.outgoingConnections[0] !== this || alternativeEndPort.outgoingConnections.length > 1 || alternativeEndPort.incomingConnections.length === 1 && alternativeEndPort.incomingConnections[0] !== this || alternativeEndPort.incomingConnections.length > 1)) {
2174
+ // alternative end port not valid, it already has other connections
2175
+ continue checkAlternativeEndPorts;
2176
+ }
2177
+ if (!allowSharingBothPorts) {
2167
2178
  for (const connection of alternativeEndPort.incomingConnections) {
2168
2179
  if (connection !== this && connection.start === this.start) {
2169
2180
  // alternative end port not valid, there is a connection whose start and end matches the alternative end port and this connection's start
@@ -2271,6 +2282,7 @@ const DIAGRAM_FIELD_DEFAULTS = {
2271
2282
  fontFamily: "'Wonder Unit Sans', sans-serif",
2272
2283
  color: '#000000',
2273
2284
  selectedColor: '#000000',
2285
+ backgroundColor: '#00000000',
2274
2286
  horizontalAlign: HorizontalAlign.Center,
2275
2287
  verticalAlign: VerticalAlign.Center,
2276
2288
  orientation: Side.Top,
@@ -2927,6 +2939,7 @@ class DiagramSection extends DiagramElement {
2927
2939
  * @public
2928
2940
  */
2929
2941
  setGeometry(geometry) {
2942
+ var _a;
2930
2943
  const oldCoordsX = [this.coords[0], this.coords[0] + this.width];
2931
2944
  const oldCoordsY = [this.coords[1], this.coords[1] + this.height];
2932
2945
  this.coords = [...geometry.coords];
@@ -2950,8 +2963,10 @@ class DiagramSection extends DiagramElement {
2950
2963
  for (const decorator of this.decorators) {
2951
2964
  decorator.move(translatePointWithAnchors(decorator.coords, oldCoordsX, oldCoordsY, newCoordsX, newCoordsY, decorator.anchorPointX, decorator.anchorPointY));
2952
2965
  }
2966
+ if (((_a = this.model.canvas) === null || _a === void 0 ? void 0 : _a.autoTightenConnections) !== false) {
2967
+ this.getConnections().forEach(c => c.tighten());
2968
+ }
2953
2969
  // Update canvas.
2954
- this.getConnections().forEach(c => c.tighten());
2955
2970
  this.updateInView();
2956
2971
  }
2957
2972
  }
@@ -3670,6 +3685,7 @@ class DiagramNode extends DiagramElement {
3670
3685
  * @public
3671
3686
  */
3672
3687
  setGeometry(geometry) {
3688
+ var _a;
3673
3689
  this.raise();
3674
3690
  const oldCoordsX = [this.coords[0], this.coords[0] + this.width];
3675
3691
  const oldCoordsY = [this.coords[1], this.coords[1] + this.height];
@@ -3707,8 +3723,10 @@ class DiagramNode extends DiagramElement {
3707
3723
  for (const decorator of this.decorators) {
3708
3724
  decorator.move(translatePointWithAnchors(decorator.coords, oldCoordsX, oldCoordsY, newCoordsX, newCoordsY, decorator.anchorPointX, decorator.anchorPointY));
3709
3725
  }
3726
+ if (((_a = this.model.canvas) === null || _a === void 0 ? void 0 : _a.autoTightenConnections) !== false) {
3727
+ this.getConnections().forEach(c => c.tighten());
3728
+ }
3710
3729
  // Update canvas.
3711
- this.getConnections().forEach(c => c.tighten());
3712
3730
  this.updateInView();
3713
3731
  }
3714
3732
  /**
@@ -6402,10 +6420,11 @@ class DiagramUserHighlight extends DiagramElementSet {
6402
6420
  * @public
6403
6421
  * @param canvas A canvas.
6404
6422
  */
6405
- constructor(canvas) {
6423
+ constructor(canvas, highlightSections = true) {
6406
6424
  super();
6407
6425
  this.focus = undefined;
6408
6426
  this.canvas = canvas;
6427
+ this.highlightSections = highlightSections;
6409
6428
  }
6410
6429
  /**
6411
6430
  * Gets the focus of the user highlight, which is the element where the current user highlight started regardless of which other elements were highlighted as a consequence.
@@ -6431,6 +6450,20 @@ class DiagramUserHighlight extends DiagramElementSet {
6431
6450
  add(element) {
6432
6451
  super.add(element);
6433
6452
  if (element instanceof DiagramNode) {
6453
+ if (!this.highlightSections) {
6454
+ for (const section of element.sections) {
6455
+ super.add(section);
6456
+ for (const port of section.ports) {
6457
+ super.add(port);
6458
+ this.canvas.updatePortsInView(port.id);
6459
+ }
6460
+ if (section.label) {
6461
+ super.add(section.label);
6462
+ this.canvas.updateFieldsInView(section.label.id);
6463
+ }
6464
+ this.canvas.updateSectionsInView(section.id);
6465
+ }
6466
+ }
6434
6467
  for (const port of element.ports) {
6435
6468
  super.add(port);
6436
6469
  this.canvas.updatePortsInView(port.id);
@@ -6441,15 +6474,19 @@ class DiagramUserHighlight extends DiagramElementSet {
6441
6474
  }
6442
6475
  this.canvas.updateNodesInView(element.id);
6443
6476
  } else if (element instanceof DiagramSection) {
6444
- for (const port of element.ports) {
6445
- super.add(port);
6446
- this.canvas.updatePortsInView(port.id);
6447
- }
6448
- if (element.label) {
6449
- super.add(element.label);
6450
- this.canvas.updateFieldsInView(element.label.id);
6477
+ if (!this.highlightSections && element.node) {
6478
+ this.add(element.node);
6479
+ } else {
6480
+ for (const port of element.ports) {
6481
+ super.add(port);
6482
+ this.canvas.updatePortsInView(port.id);
6483
+ }
6484
+ if (element.label) {
6485
+ super.add(element.label);
6486
+ this.canvas.updateFieldsInView(element.label.id);
6487
+ }
6488
+ this.canvas.updateSectionsInView(element.id);
6451
6489
  }
6452
- this.canvas.updateSectionsInView(element.id);
6453
6490
  } else if (element instanceof DiagramPort) {
6454
6491
  if (element.label) {
6455
6492
  super.add(element.label);
@@ -6918,7 +6955,6 @@ const RESIZER_THICKNESS = 6;
6918
6955
  */
6919
6956
  const ACTION_STACK_SIZE = 25;
6920
6957
  const UNFINISHED_CONNECTION_ID = 'diagram-connection-unfinished';
6921
- const MAX_DISTANCE_TO_PORT = 100;
6922
6958
  class DiagramCanvas {
6923
6959
  get connectionType() {
6924
6960
  return this._connectionType;
@@ -6936,7 +6972,7 @@ class DiagramCanvas {
6936
6972
  * @param config The configuration object used to set the parameters of this canvas.
6937
6973
  */
6938
6974
  constructor(parentComponent, config) {
6939
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
6975
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5;
6940
6976
  this.backgroundPatternId = `daga-background-pattern-id-${DiagramCanvas.canvasCount++}`;
6941
6977
  this.zoomTransform = d3.zoomIdentity;
6942
6978
  // used to distinguish drags from clicks when dragging elements and during multiple selection
@@ -6952,19 +6988,24 @@ class DiagramCanvas {
6952
6988
  this.parentComponent = parentComponent;
6953
6989
  this.model = new DiagramModel(this, undefined, config.name || 'unnamed', '', config.type || '', config.properties || []);
6954
6990
  this.userSelection = new DiagramUserSelection(this);
6955
- this.userHighlight = new DiagramUserHighlight(this);
6956
- this.contextMenu = new DiagramContextMenu(this, (_a = config.canvas) === null || _a === void 0 ? void 0 : _a.contextMenu);
6957
- this.backgroundColor = ((_b = config.canvas) === null || _b === void 0 ? void 0 : _b.backgroundColor) || '#FFFFFF';
6958
- this.gridStyle = (_e = (_d = (_c = config.canvas) === null || _c === void 0 ? void 0 : _c.grid) === null || _d === void 0 ? void 0 : _d.style) !== null && _e !== void 0 ? _e : GRID_DEFAULTS.style;
6959
- this.gridSize = ((_g = (_f = config.canvas) === null || _f === void 0 ? void 0 : _f.grid) === null || _g === void 0 ? void 0 : _g.enabled) === false || ((_h = config.canvas) === null || _h === void 0 ? void 0 : _h.grid) === undefined ? 0 : Math.abs(((_k = (_j = config.canvas) === null || _j === void 0 ? void 0 : _j.grid) === null || _k === void 0 ? void 0 : _k.spacing) || GRID_DEFAULTS.spacing);
6960
- this.gridThickness = Math.abs(((_m = (_l = config.canvas) === null || _l === void 0 ? void 0 : _l.grid) === null || _m === void 0 ? void 0 : _m.thickness) || GRID_DEFAULTS.thickness);
6961
- this.gridColor = ((_p = (_o = config.canvas) === null || _o === void 0 ? void 0 : _o.grid) === null || _p === void 0 ? void 0 : _p.color) || GRID_DEFAULTS.color;
6962
- this.snapToGrid = ((_r = (_q = config.canvas) === null || _q === void 0 ? void 0 : _q.grid) === null || _r === void 0 ? void 0 : _r.enabled) === false || ((_s = config.canvas) === null || _s === void 0 ? void 0 : _s.grid) === undefined ? false : ((_u = (_t = config.canvas) === null || _t === void 0 ? void 0 : _t.grid) === null || _u === void 0 ? void 0 : _u.snap) || GRID_DEFAULTS.snap;
6963
- this.zoomFactor = ((_v = config.canvas) === null || _v === void 0 ? void 0 : _v.zoomFactor) || 2;
6964
- this.panRate = ((_w = config.canvas) === null || _w === void 0 ? void 0 : _w.panRate) || 100;
6965
- this.inferConnectionType = config.inferConnectionType || false;
6991
+ this.userHighlight = new DiagramUserHighlight(this, ((_a = config.canvas) === null || _a === void 0 ? void 0 : _a.highlightSections) !== false);
6992
+ this.contextMenu = new DiagramContextMenu(this, (_b = config.canvas) === null || _b === void 0 ? void 0 : _b.contextMenu);
6993
+ this.backgroundColor = ((_c = config.canvas) === null || _c === void 0 ? void 0 : _c.backgroundColor) || '#FFFFFF';
6994
+ this.gridStyle = (_f = (_e = (_d = config.canvas) === null || _d === void 0 ? void 0 : _d.grid) === null || _e === void 0 ? void 0 : _e.style) !== null && _f !== void 0 ? _f : GRID_DEFAULTS.style;
6995
+ this.gridSize = ((_h = (_g = config.canvas) === null || _g === void 0 ? void 0 : _g.grid) === null || _h === void 0 ? void 0 : _h.enabled) === false || ((_j = config.canvas) === null || _j === void 0 ? void 0 : _j.grid) === undefined ? 0 : Math.abs(((_l = (_k = config.canvas) === null || _k === void 0 ? void 0 : _k.grid) === null || _l === void 0 ? void 0 : _l.spacing) || GRID_DEFAULTS.spacing);
6996
+ this.gridThickness = Math.abs(((_o = (_m = config.canvas) === null || _m === void 0 ? void 0 : _m.grid) === null || _o === void 0 ? void 0 : _o.thickness) || GRID_DEFAULTS.thickness);
6997
+ this.gridColor = ((_q = (_p = config.canvas) === null || _p === void 0 ? void 0 : _p.grid) === null || _q === void 0 ? void 0 : _q.color) || GRID_DEFAULTS.color;
6998
+ this.snapToGrid = ((_s = (_r = config.canvas) === null || _r === void 0 ? void 0 : _r.grid) === null || _s === void 0 ? void 0 : _s.enabled) === false || ((_t = config.canvas) === null || _t === void 0 ? void 0 : _t.grid) === undefined ? false : ((_v = (_u = config.canvas) === null || _u === void 0 ? void 0 : _u.grid) === null || _v === void 0 ? void 0 : _v.snap) || GRID_DEFAULTS.snap;
6999
+ this.zoomFactor = ((_w = config.canvas) === null || _w === void 0 ? void 0 : _w.zoomFactor) || 2;
7000
+ this.panRate = ((_x = config.canvas) === null || _x === void 0 ? void 0 : _x.panRate) || 100;
7001
+ this.inferConnectionType = ((_y = config.connectionSettings) === null || _y === void 0 ? void 0 : _y.inferConnectionType) || false;
7002
+ this.autoTightenConnections = ((_z = config.connectionSettings) === null || _z === void 0 ? void 0 : _z.autoTighten) !== false;
7003
+ this.allowConnectionLoops = ((_0 = config.connectionSettings) === null || _0 === void 0 ? void 0 : _0.allowLoops) || false;
7004
+ this.allowSharingPorts = ((_1 = config.connectionSettings) === null || _1 === void 0 ? void 0 : _1.sharePorts) !== false;
7005
+ this.allowSharingBothPorts = ((_2 = config.connectionSettings) === null || _2 === void 0 ? void 0 : _2.shareBothPorts) || false;
7006
+ this.portHighlightRadius = ((_3 = config.connectionSettings) === null || _3 === void 0 ? void 0 : _3.portHighlightRadius) || 100;
6966
7007
  this.multipleSelectionOn = false;
6967
- this.priorityThresholds = ((_x = config.canvas) === null || _x === void 0 ? void 0 : _x.priorityThresholds) || [];
7008
+ this.priorityThresholds = ((_4 = config.canvas) === null || _4 === void 0 ? void 0 : _4.priorityThresholds) || [];
6968
7009
  this.priorityThreshold = this.priorityThresholds ? this.priorityThresholds[0] : undefined;
6969
7010
  this.layoutFormat = config.layoutFormat;
6970
7011
  this.userActions = config.userActions || {};
@@ -6991,7 +7032,7 @@ class DiagramCanvas {
6991
7032
  const connectionType = new DiagramConnectionType(Object.assign(Object.assign({}, config.connectionTypeDefaults), connectionTypeConfig));
6992
7033
  this.model.connections.types.add(connectionType);
6993
7034
  }
6994
- this._connectionType = config.defaultConnection !== undefined ? this.model.connections.types.get(config.defaultConnection) : undefined;
7035
+ this._connectionType = ((_5 = config === null || config === void 0 ? void 0 : config.connectionSettings) === null || _5 === void 0 ? void 0 : _5.defaultConnection) !== undefined ? this.model.connections.types.get(config.connectionSettings.defaultConnection) : undefined;
6995
7036
  }
6996
7037
  }
6997
7038
  addValidator(validator) {
@@ -7839,7 +7880,7 @@ class DiagramCanvas {
7839
7880
  if (this.multipleSelectionOn || this.secondaryButton) {
7840
7881
  this.startMultipleSelection(event);
7841
7882
  } else {
7842
- if (this.canUserPerformAction(DiagramActions.AddConnection) && !d.removed) {
7883
+ if (this.canUserPerformAction(DiagramActions.AddConnection) && (this.allowSharingPorts || d.incomingConnections.length === 0 && d.outgoingConnections.length === 0) && !d.removed) {
7843
7884
  setCursorStyle(CursorStyle.Grabbing);
7844
7885
  this.startConnection(d);
7845
7886
  // should be true after having called this.startConnection()
@@ -7885,7 +7926,7 @@ class DiagramCanvas {
7885
7926
  closestPortFound = port;
7886
7927
  }
7887
7928
  }
7888
- if (closestPortFound && minDistanceFound < MAX_DISTANCE_TO_PORT) {
7929
+ if (closestPortFound && minDistanceFound < this.portHighlightRadius) {
7889
7930
  this.userHighlight.focusOn(closestPortFound);
7890
7931
  } else {
7891
7932
  this.userHighlight.clear();
@@ -8290,6 +8331,77 @@ class DiagramCanvas {
8290
8331
  const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), connection.type.label);
8291
8332
  if (pathNode) {
8292
8333
  const pathLength = pathNode.getTotalLength();
8334
+ let startLabelShiftX = 0;
8335
+ let startLabelShiftY = 0;
8336
+ let middleLabelShiftX = 0;
8337
+ let middleLabelShiftY = 0;
8338
+ let endLabelShiftX = 0;
8339
+ let endLabelShiftY = 0;
8340
+ if (labelConfiguration.backgroundColor === '#00000000') {
8341
+ // background color is transparent / not set, so we find an alternative position for the label
8342
+ const deltaX = connection.endCoords[0] - connection.startCoords[0];
8343
+ const deltaY = connection.endCoords[1] - connection.startCoords[1];
8344
+ switch (connection.startDirection) {
8345
+ case Side.Top:
8346
+ startLabelShiftX = deltaX >= 0 ? 1 : -1;
8347
+ middleLabelShiftX = startLabelShiftX;
8348
+ endLabelShiftX = startLabelShiftX;
8349
+ startLabelShiftY = -1;
8350
+ break;
8351
+ case Side.Bottom:
8352
+ startLabelShiftX = deltaX >= 0 ? 1 : -1;
8353
+ middleLabelShiftX = startLabelShiftX;
8354
+ endLabelShiftX = startLabelShiftX;
8355
+ startLabelShiftY = 1;
8356
+ break;
8357
+ case Side.Left:
8358
+ startLabelShiftX = -1;
8359
+ startLabelShiftY = deltaY > 0 ? 1 : -1;
8360
+ middleLabelShiftY = startLabelShiftY;
8361
+ endLabelShiftY = startLabelShiftY;
8362
+ break;
8363
+ case Side.Right:
8364
+ startLabelShiftX = 1;
8365
+ startLabelShiftY = deltaY > 0 ? 1 : -1;
8366
+ middleLabelShiftY = startLabelShiftY;
8367
+ endLabelShiftY = startLabelShiftY;
8368
+ break;
8369
+ default:
8370
+ startLabelShiftX = 1;
8371
+ middleLabelShiftX = startLabelShiftX;
8372
+ endLabelShiftX = startLabelShiftX;
8373
+ startLabelShiftY = -1;
8374
+ middleLabelShiftY = startLabelShiftY;
8375
+ endLabelShiftY = startLabelShiftY;
8376
+ }
8377
+ switch (connection.endDirection) {
8378
+ case Side.Top:
8379
+ endLabelShiftX = deltaX >= 0 ? 1 : -1;
8380
+ middleLabelShiftX = endLabelShiftX;
8381
+ endLabelShiftY = 1;
8382
+ break;
8383
+ case Side.Bottom:
8384
+ endLabelShiftX = deltaX >= 0 ? 1 : -1;
8385
+ middleLabelShiftX = endLabelShiftX;
8386
+ endLabelShiftY = -1;
8387
+ break;
8388
+ case Side.Left:
8389
+ endLabelShiftX = -1;
8390
+ endLabelShiftY = deltaY > 0 ? 1 : -1;
8391
+ middleLabelShiftY = endLabelShiftY;
8392
+ break;
8393
+ case Side.Right:
8394
+ endLabelShiftX = 1;
8395
+ endLabelShiftY = deltaY > 0 ? 1 : -1;
8396
+ middleLabelShiftY = endLabelShiftY;
8397
+ break;
8398
+ default:
8399
+ endLabelShiftX = 1;
8400
+ middleLabelShiftX = endLabelShiftX;
8401
+ endLabelShiftY = -1;
8402
+ middleLabelShiftY = endLabelShiftY;
8403
+ }
8404
+ }
8293
8405
  // bind start labels
8294
8406
  connectionSelection.select('g.diagram-connection-start-label text').attr('x', 0).attr('y', labelConfiguration.fontSize / 3).attr('text-anchor', 'middle').attr('font-family', labelConfiguration.fontFamily).attr('font-size', labelConfiguration.fontSize).attr('fill', connection.selected ? labelConfiguration.selectedColor : labelConfiguration.color).style('font-kerning', 'none').text(connection.startLabel);
8295
8407
  const startLabelBoundingRect = (_a = connectionSelection.select('g.diagram-connection-start-label text').node()) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
@@ -8298,8 +8410,8 @@ class DiagramCanvas {
8298
8410
  const boundingWidth = !connection.startLabel ? 0 : startLabelBoundingRect.width / this.zoomTransform.k + getLeftPadding$1(labelConfiguration) + getRightPadding$1(labelConfiguration);
8299
8411
  const boundingHeight = !connection.startLabel ? 0 : startLabelBoundingRect.height / this.zoomTransform.k + getTopPadding$1(labelConfiguration) + getBottomPadding$1(labelConfiguration);
8300
8412
  const pathStartLabelPoint = pathNode.getPointAtLength(Math.max(getLeftMargin(labelConfiguration) + boundingWidth / 2, getRightMargin(labelConfiguration) + boundingWidth / 2, getTopMargin(labelConfiguration) + boundingHeight / 2, getBottomMargin(labelConfiguration) + boundingHeight / 2));
8301
- connectionSelection.select('g.diagram-connection-start-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', connection.look.color).attr('stroke', 'none');
8302
- connectionSelection.select('g.diagram-connection-start-label').attr('transform', `translate(${pathStartLabelPoint.x},${pathStartLabelPoint.y})`);
8413
+ connectionSelection.select('g.diagram-connection-start-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', labelConfiguration.backgroundColor).attr('stroke', 'none');
8414
+ connectionSelection.select('g.diagram-connection-start-label').attr('transform', `translate(${pathStartLabelPoint.x + startLabelShiftX * boundingWidth},${pathStartLabelPoint.y + startLabelShiftY * boundingHeight})`);
8303
8415
  }
8304
8416
  // bind middle labels
8305
8417
  connectionSelection.select('g.diagram-connection-middle-label text').attr('x', 0).attr('y', labelConfiguration.fontSize / 3).attr('text-anchor', 'middle').attr('font-family', labelConfiguration.fontFamily).attr('font-size', labelConfiguration.fontSize).attr('fill', connection.selected ? labelConfiguration.selectedColor : labelConfiguration.color).style('font-kerning', 'none').text(connection.middleLabel);
@@ -8309,8 +8421,8 @@ class DiagramCanvas {
8309
8421
  const boundingWidth = !connection.middleLabel ? 0 : middleLabelBoundingRect.width / this.zoomTransform.k + getLeftPadding$1(labelConfiguration) + getRightPadding$1(labelConfiguration);
8310
8422
  const boundingHeight = !connection.middleLabel ? 0 : middleLabelBoundingRect.height / this.zoomTransform.k + getTopPadding$1(labelConfiguration) + getBottomPadding$1(labelConfiguration);
8311
8423
  const pathMiddleLabelPoint = pathNode.getPointAtLength(pathLength / 2);
8312
- connectionSelection.select('g.diagram-connection-middle-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', connection.look.color).attr('stroke', 'none');
8313
- connectionSelection.select('g.diagram-connection-middle-label').attr('transform', `translate(${pathMiddleLabelPoint.x},${pathMiddleLabelPoint.y})`);
8424
+ connectionSelection.select('g.diagram-connection-middle-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', labelConfiguration.backgroundColor).attr('stroke', 'none');
8425
+ connectionSelection.select('g.diagram-connection-middle-label').attr('transform', `translate(${pathMiddleLabelPoint.x + middleLabelShiftX * boundingWidth},${pathMiddleLabelPoint.y + middleLabelShiftY * boundingHeight})`);
8314
8426
  }
8315
8427
  // bind end labels
8316
8428
  connectionSelection.select('g.diagram-connection-end-label text').attr('x', 0).attr('y', labelConfiguration.fontSize / 3).attr('text-anchor', 'middle').attr('font-family', labelConfiguration.fontFamily).attr('font-size', labelConfiguration.fontSize).attr('fill', connection.selected ? labelConfiguration.selectedColor : labelConfiguration.color).style('font-kerning', 'none').text(connection.endLabel);
@@ -8320,8 +8432,8 @@ class DiagramCanvas {
8320
8432
  const boundingWidth = !connection.endLabel ? 0 : endLabelBoundingRect.width / this.zoomTransform.k + getLeftPadding$1(labelConfiguration) + getRightPadding$1(labelConfiguration);
8321
8433
  const boundingHeight = !connection.endLabel ? 0 : endLabelBoundingRect.height / this.zoomTransform.k + getTopPadding$1(labelConfiguration) + getBottomPadding$1(labelConfiguration);
8322
8434
  const pathEndLabelPoint = pathNode.getPointAtLength(pathLength - Math.max(getLeftMargin(labelConfiguration) + boundingWidth / 2, getRightMargin(labelConfiguration) + boundingWidth / 2, getTopMargin(labelConfiguration) + boundingHeight / 2, getBottomMargin(labelConfiguration) + boundingHeight / 2));
8323
- connectionSelection.select('g.diagram-connection-end-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', connection.look.color).attr('stroke', 'none');
8324
- connectionSelection.select('g.diagram-connection-end-label').attr('transform', `translate(${pathEndLabelPoint.x},${pathEndLabelPoint.y})`);
8435
+ connectionSelection.select('g.diagram-connection-end-label path').attr('d', pillPath(-boundingWidth / 2, -boundingHeight / 2, boundingWidth, boundingHeight)).attr('fill', labelConfiguration.backgroundColor).attr('stroke', 'none');
8436
+ connectionSelection.select('g.diagram-connection-end-label').attr('transform', `translate(${pathEndLabelPoint.x + endLabelShiftX * boundingWidth},${pathEndLabelPoint.y + endLabelShiftY * boundingHeight})`);
8325
8437
  }
8326
8438
  }
8327
8439
  }
@@ -8493,51 +8605,61 @@ class DiagramCanvas {
8493
8605
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
8494
8606
  this.userHighlight.clear();
8495
8607
  if (this.unfinishedConnection !== undefined) {
8496
- if (this.unfinishedConnection.start !== port) {
8497
- if (this.unfinishedConnection.type.canStartFromType(((_d = (_c = (_b = (_a = this.unfinishedConnection) === null || _a === void 0 ? void 0 : _a.start) === null || _b === void 0 ? void 0 : _b.getNode()) === null || _c === void 0 ? void 0 : _c.type) === null || _d === void 0 ? void 0 : _d.id) || '') && ((_f = (_e = this.unfinishedConnection) === null || _e === void 0 ? void 0 : _e.start) === null || _f === void 0 ? void 0 : _f.allowsOutgoing) && this.unfinishedConnection.type.canFinishOnType(((_h = (_g = port.getNode()) === null || _g === void 0 ? void 0 : _g.type) === null || _h === void 0 ? void 0 : _h.id) || '') && port.allowsIncoming) {
8498
- const addConnectionAction = new AddConnectionAction(this, this.unfinishedConnection.type, (_j = this.unfinishedConnection.start) === null || _j === void 0 ? void 0 : _j.id, port.id);
8499
- // clean up the previous unfinished connection
8500
- this.dropConnection();
8501
- addConnectionAction.do();
8502
- this.actionStack.add(addConnectionAction);
8503
- } else if (this.unfinishedConnection.type.canFinishOnType(((_o = (_m = (_l = (_k = this.unfinishedConnection) === null || _k === void 0 ? void 0 : _k.start) === null || _l === void 0 ? void 0 : _l.getNode()) === null || _m === void 0 ? void 0 : _m.type) === null || _o === void 0 ? void 0 : _o.id) || '') && ((_q = (_p = this.unfinishedConnection) === null || _p === void 0 ? void 0 : _p.start) === null || _q === void 0 ? void 0 : _q.allowsIncoming) && this.unfinishedConnection.type.canStartFromType(((_s = (_r = port.getNode()) === null || _r === void 0 ? void 0 : _r.type) === null || _s === void 0 ? void 0 : _s.id) || '') && port.allowsOutgoing) {
8504
- const addConnectionAction = new AddConnectionAction(this, this.unfinishedConnection.type, port.id, (_t = this.unfinishedConnection.start) === null || _t === void 0 ? void 0 : _t.id);
8505
- // clean up the previous unfinished connection
8506
- this.dropConnection();
8507
- addConnectionAction.do();
8508
- this.actionStack.add(addConnectionAction);
8509
- } else {
8510
- if (this.inferConnectionType) {
8511
- let differentConnectionType = this.model.connections.types.all().find(t => {
8608
+ if (!this.allowConnectionLoops && this.unfinishedConnection.start === port) {
8609
+ this.dropConnection();
8610
+ return;
8611
+ }
8612
+ if (!this.allowSharingPorts && (port.incomingConnections.length > 0 || port.outgoingConnections.length > 0)) {
8613
+ this.dropConnection();
8614
+ return;
8615
+ }
8616
+ if (!this.allowSharingBothPorts && this.model.connections.find(c => {
8617
+ var _a, _b;
8618
+ return c.start === ((_a = this.unfinishedConnection) === null || _a === void 0 ? void 0 : _a.start) && c.end === port || c.end === ((_b = this.unfinishedConnection) === null || _b === void 0 ? void 0 : _b.start) && c.start === port;
8619
+ }) !== undefined) {
8620
+ this.dropConnection();
8621
+ return;
8622
+ }
8623
+ if (this.unfinishedConnection.type.canStartFromType(((_d = (_c = (_b = (_a = this.unfinishedConnection) === null || _a === void 0 ? void 0 : _a.start) === null || _b === void 0 ? void 0 : _b.getNode()) === null || _c === void 0 ? void 0 : _c.type) === null || _d === void 0 ? void 0 : _d.id) || '') && ((_f = (_e = this.unfinishedConnection) === null || _e === void 0 ? void 0 : _e.start) === null || _f === void 0 ? void 0 : _f.allowsOutgoing) && this.unfinishedConnection.type.canFinishOnType(((_h = (_g = port.getNode()) === null || _g === void 0 ? void 0 : _g.type) === null || _h === void 0 ? void 0 : _h.id) || '') && port.allowsIncoming) {
8624
+ const addConnectionAction = new AddConnectionAction(this, this.unfinishedConnection.type, (_j = this.unfinishedConnection.start) === null || _j === void 0 ? void 0 : _j.id, port.id);
8625
+ // clean up the previous unfinished connection
8626
+ this.dropConnection();
8627
+ addConnectionAction.do();
8628
+ this.actionStack.add(addConnectionAction);
8629
+ } else if (this.unfinishedConnection.type.canFinishOnType(((_o = (_m = (_l = (_k = this.unfinishedConnection) === null || _k === void 0 ? void 0 : _k.start) === null || _l === void 0 ? void 0 : _l.getNode()) === null || _m === void 0 ? void 0 : _m.type) === null || _o === void 0 ? void 0 : _o.id) || '') && ((_q = (_p = this.unfinishedConnection) === null || _p === void 0 ? void 0 : _p.start) === null || _q === void 0 ? void 0 : _q.allowsIncoming) && this.unfinishedConnection.type.canStartFromType(((_s = (_r = port.getNode()) === null || _r === void 0 ? void 0 : _r.type) === null || _s === void 0 ? void 0 : _s.id) || '') && port.allowsOutgoing) {
8630
+ const addConnectionAction = new AddConnectionAction(this, this.unfinishedConnection.type, port.id, (_t = this.unfinishedConnection.start) === null || _t === void 0 ? void 0 : _t.id);
8631
+ // clean up the previous unfinished connection
8632
+ this.dropConnection();
8633
+ addConnectionAction.do();
8634
+ this.actionStack.add(addConnectionAction);
8635
+ } else {
8636
+ if (this.inferConnectionType) {
8637
+ let differentConnectionType = this.model.connections.types.all().find(t => {
8638
+ var _a, _b, _c, _d, _e, _f, _g, _h;
8639
+ return t.canStartFromType(((_d = (_c = (_b = (_a = this.unfinishedConnection) === null || _a === void 0 ? void 0 : _a.start) === null || _b === void 0 ? void 0 : _b.getNode()) === null || _c === void 0 ? void 0 : _c.type) === null || _d === void 0 ? void 0 : _d.id) || '') && ((_f = (_e = this.unfinishedConnection) === null || _e === void 0 ? void 0 : _e.start) === null || _f === void 0 ? void 0 : _f.allowsOutgoing) && t.canFinishOnType(((_h = (_g = port.getNode()) === null || _g === void 0 ? void 0 : _g.type) === null || _h === void 0 ? void 0 : _h.id) || '') && port.allowsIncoming;
8640
+ });
8641
+ let invertConnection = false;
8642
+ if (differentConnectionType === undefined) {
8643
+ differentConnectionType = this.model.connections.types.all().find(t => {
8512
8644
  var _a, _b, _c, _d, _e, _f, _g, _h;
8513
- return t.canStartFromType(((_d = (_c = (_b = (_a = this.unfinishedConnection) === null || _a === void 0 ? void 0 : _a.start) === null || _b === void 0 ? void 0 : _b.getNode()) === null || _c === void 0 ? void 0 : _c.type) === null || _d === void 0 ? void 0 : _d.id) || '') && ((_f = (_e = this.unfinishedConnection) === null || _e === void 0 ? void 0 : _e.start) === null || _f === void 0 ? void 0 : _f.allowsOutgoing) && t.canFinishOnType(((_h = (_g = port.getNode()) === null || _g === void 0 ? void 0 : _g.type) === null || _h === void 0 ? void 0 : _h.id) || '') && port.allowsIncoming;
8645
+ return t.canFinishOnType(((_d = (_c = (_b = (_a = this.unfinishedConnection) === null || _a === void 0 ? void 0 : _a.start) === null || _b === void 0 ? void 0 : _b.getNode()) === null || _c === void 0 ? void 0 : _c.type) === null || _d === void 0 ? void 0 : _d.id) || '') && ((_f = (_e = this.unfinishedConnection) === null || _e === void 0 ? void 0 : _e.start) === null || _f === void 0 ? void 0 : _f.allowsIncoming) && t.canStartFromType(((_h = (_g = port.getNode()) === null || _g === void 0 ? void 0 : _g.type) === null || _h === void 0 ? void 0 : _h.id) || '') && port.allowsOutgoing;
8514
8646
  });
8515
- let invertConnection = false;
8516
- if (differentConnectionType === undefined) {
8517
- differentConnectionType = this.model.connections.types.all().find(t => {
8518
- var _a, _b, _c, _d, _e, _f, _g, _h;
8519
- return t.canFinishOnType(((_d = (_c = (_b = (_a = this.unfinishedConnection) === null || _a === void 0 ? void 0 : _a.start) === null || _b === void 0 ? void 0 : _b.getNode()) === null || _c === void 0 ? void 0 : _c.type) === null || _d === void 0 ? void 0 : _d.id) || '') && ((_f = (_e = this.unfinishedConnection) === null || _e === void 0 ? void 0 : _e.start) === null || _f === void 0 ? void 0 : _f.allowsIncoming) && t.canStartFromType(((_h = (_g = port.getNode()) === null || _g === void 0 ? void 0 : _g.type) === null || _h === void 0 ? void 0 : _h.id) || '') && port.allowsOutgoing;
8520
- });
8521
- invertConnection = true;
8522
- }
8523
- if (differentConnectionType !== undefined) {
8524
- const addConnectionAction = new AddConnectionAction(this, differentConnectionType, invertConnection ? port.id : (_u = this.unfinishedConnection.start) === null || _u === void 0 ? void 0 : _u.id, invertConnection ? (_v = this.unfinishedConnection.start) === null || _v === void 0 ? void 0 : _v.id : port.id);
8525
- // clean up the previous unfinished connection
8526
- this.dropConnection();
8527
- addConnectionAction.do();
8528
- this.actionStack.add(addConnectionAction);
8529
- } else {
8530
- // error: connection target of wrong type and no allowed type can be found
8531
- this.dropConnection();
8532
- }
8647
+ invertConnection = true;
8648
+ }
8649
+ if (differentConnectionType !== undefined) {
8650
+ const addConnectionAction = new AddConnectionAction(this, differentConnectionType, invertConnection ? port.id : (_u = this.unfinishedConnection.start) === null || _u === void 0 ? void 0 : _u.id, invertConnection ? (_v = this.unfinishedConnection.start) === null || _v === void 0 ? void 0 : _v.id : port.id);
8651
+ // clean up the previous unfinished connection
8652
+ this.dropConnection();
8653
+ addConnectionAction.do();
8654
+ this.actionStack.add(addConnectionAction);
8533
8655
  } else {
8534
- // error: connection target of wrong type and can't guess for a different type
8656
+ // error: connection target of wrong type and no allowed type can be found
8535
8657
  this.dropConnection();
8536
8658
  }
8659
+ } else {
8660
+ // error: connection target of wrong type and can't guess for a different type
8661
+ this.dropConnection();
8537
8662
  }
8538
- } else {
8539
- // error: start port of a connection can't also be the end port
8540
- this.dropConnection();
8541
8663
  }
8542
8664
  }
8543
8665
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metadev/daga",
3
- "version": "4.2.2",
3
+ "version": "4.2.3",
4
4
  "dependencies": {},
5
5
  "peerDependencies": {
6
6
  "d3": "^7.9.0",
@@ -49,10 +49,15 @@ export declare class DiagramCanvas implements Canvas {
49
49
  zoomFactor: number;
50
50
  panRate: number;
51
51
  inferConnectionType: boolean;
52
- multipleSelectionOn: boolean;
53
52
  private _connectionType?;
54
53
  get connectionType(): DiagramConnectionType | undefined;
55
54
  set connectionType(value: DiagramConnectionType | undefined);
55
+ autoTightenConnections: boolean;
56
+ allowConnectionLoops: boolean;
57
+ allowSharingPorts: boolean;
58
+ allowSharingBothPorts: boolean;
59
+ portHighlightRadius: number;
60
+ multipleSelectionOn: boolean;
56
61
  layoutFormat?: string;
57
62
  validators: DiagramValidator[];
58
63
  userActions: {
@@ -8,12 +8,16 @@ import { DiagramElement, DiagramElementSet } from '../model/diagram-element';
8
8
  export declare class DiagramUserHighlight extends DiagramElementSet<DiagramElement> {
9
9
  private readonly canvas;
10
10
  private focus?;
11
+ /**
12
+ * Whether sections can be highlighted individually or the whole node must be highlighted when highlighting a section.
13
+ */
14
+ private highlightSections;
11
15
  /**
12
16
  * Constructs a user highlight object.
13
17
  * @public
14
18
  * @param canvas A canvas.
15
19
  */
16
- constructor(canvas: Canvas);
20
+ constructor(canvas: Canvas, highlightSections?: boolean);
17
21
  /**
18
22
  * Gets the focus of the user highlight, which is the element where the current user highlight started regardless of which other elements were highlighted as a consequence.
19
23
  * @public
@@ -30,6 +30,11 @@ export interface CanvasConfig {
30
30
  * @default 100
31
31
  */
32
32
  panRate?: number;
33
+ /**
34
+ * Whether sections can be highlighted individually or the whole node must be highlighted when highlighting a section.
35
+ * @default true
36
+ */
37
+ highlightSections?: boolean;
33
38
  /**
34
39
  * Possible values of the priority threshold that the user can toggle between to hide nodes whose priority value is below it.
35
40
  * If it is possible to toggle the priority threshold via the filter button, it should have at least two values.
@@ -26,15 +26,10 @@ export interface DiagramConfig {
26
26
  */
27
27
  canvas?: CanvasConfig;
28
28
  /**
29
- * When true, connections made by the user will have their type assumed based on the type of the source and target nodes.
30
- * @default false
31
- */
32
- inferConnectionType?: boolean;
33
- /**
34
- * Id of the type of connection that is initially selected for the user to draw when drawing connections. By default, no type is selected.
35
- * @default undefined
29
+ * Configuration regarding the general settings of connections.
30
+ * @default {}
36
31
  */
37
- defaultConnection?: string;
32
+ connectionSettings?: ConnectionSettingsConfig;
38
33
  /**
39
34
  * Name of the layout format used to arrange the nodes of this diagram when pressing the layout button in the diagram buttons component.
40
35
  * @default undefined
@@ -88,6 +83,47 @@ export interface DiagramConfig {
88
83
  */
89
84
  properties?: Property[];
90
85
  }
86
+ /**
87
+ * Configuration regarding the general settings of connections.
88
+ * @public
89
+ */
90
+ export interface ConnectionSettingsConfig {
91
+ /**
92
+ * When true, connections made by the user will have their type assumed based on the type of the source and target nodes.
93
+ * @default false
94
+ */
95
+ inferConnectionType?: boolean;
96
+ /**
97
+ * Id of the type of connection that is initially selected for the user to draw when drawing connections. By default, no type is selected.
98
+ * @default undefined
99
+ */
100
+ defaultConnection?: string;
101
+ /**
102
+ * Automatically try to change the start and end ports of a connection to minimize the distance between them.
103
+ * @default true
104
+ */
105
+ autoTighten?: boolean;
106
+ /**
107
+ * Whether a connection can use the same port as start and end.
108
+ * @default false
109
+ */
110
+ allowLoops?: boolean;
111
+ /**
112
+ * Whether the same port can be used by two different connections.
113
+ * @default true
114
+ */
115
+ sharePorts?: boolean;
116
+ /**
117
+ * Whether two connections can use the same ports.
118
+ * @default false
119
+ */
120
+ shareBothPorts?: boolean;
121
+ /**
122
+ * Within what radius the closest port may be highlighted when drawing a new connection as a guide to the user.
123
+ * @default 100
124
+ */
125
+ portHighlightRadius?: number;
126
+ }
91
127
  /**
92
128
  * Configuration for which user actions are allowed in a diagram.
93
129
  * @public
@@ -314,6 +350,11 @@ export interface FieldConfig {
314
350
  * @default '#000000'
315
351
  */
316
352
  color?: string;
353
+ /**
354
+ * The background color of the text of this field.
355
+ * @default '#00000000'
356
+ */
357
+ backgroundColor?: string;
317
358
  /**
318
359
  * The color of the text of this field when selected.
319
360
  * @default '#000000'
@@ -36,22 +36,6 @@ export declare const DIAGRAM_CONNECTION_TYPE_DEFAULTS: {
36
36
  endTypes: never[];
37
37
  properties: never[];
38
38
  };
39
- /**
40
- * Whether a connection can have the same port as both its start port and its end port.
41
- */
42
- export declare const CAN_A_CONNECTION_END_ON_THE_SAME_PORT_IT_STARTS = false;
43
- /**
44
- * Whether a connection can have the same ports as another connection.
45
- */
46
- export declare const CAN_A_CONNECTION_HAVE_THE_SAME_PORTS_AS_ANOTHER = false;
47
- /**
48
- * Whether a port can have multiple connections.
49
- */
50
- export declare const CAN_CONNECTIONS_SHARE_PORTS = true;
51
- /**
52
- * Whether tightening connections is allowed.
53
- */
54
- export declare const CAN_TIGHTEN_CONNECTIONS = true;
55
39
  /**
56
40
  * The types allowed for the look of the markers of a connection.
57
41
  * @public
@@ -17,6 +17,7 @@ export declare const DIAGRAM_FIELD_DEFAULTS: {
17
17
  fontFamily: string;
18
18
  color: string;
19
19
  selectedColor: string;
20
+ backgroundColor: string;
20
21
  horizontalAlign: HorizontalAlign;
21
22
  verticalAlign: VerticalAlign;
22
23
  orientation: Side;
@@ -98,15 +98,40 @@ export interface Canvas {
98
98
  * @public
99
99
  */
100
100
  inferConnectionType: boolean;
101
- /**
102
- * If true, the next drag action will create a multiple selection rectangle.
103
- */
104
- multipleSelectionOn: boolean;
105
101
  /**
106
102
  * When a new connection is made, it should have this type.
107
103
  * @public
108
104
  */
109
105
  connectionType?: DiagramConnectionType;
106
+ /**
107
+ * Whether the start and end ports should automatically change to try to minimize the distance between them.
108
+ * @public
109
+ */
110
+ autoTightenConnections: boolean;
111
+ /**
112
+ * Whether a connection can use the same port as start and end.
113
+ * @public
114
+ */
115
+ allowConnectionLoops: boolean;
116
+ /**
117
+ * Whether the same port can be used by two different connections.
118
+ * @public
119
+ */
120
+ allowSharingPorts: boolean;
121
+ /**
122
+ * Whether two connections can use the same ports.
123
+ * @public
124
+ */
125
+ allowSharingBothPorts: boolean;
126
+ /**
127
+ * Within what radius the closest port may be highlighted when drawing a new connection as a guide to the user.
128
+ * @public
129
+ */
130
+ portHighlightRadius: number;
131
+ /**
132
+ * If true, the next drag action will create a multiple selection rectangle.
133
+ */
134
+ multipleSelectionOn: boolean;
110
135
  /**
111
136
  * Identifier of the current layout format used by the diagram.
112
137
  * @public