@metadev/daga 4.0.1 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/Changelog.md +25 -0
  2. package/index.cjs.js +478 -194
  3. package/index.esm.js +478 -194
  4. package/package.json +1 -1
  5. package/src/index.d.ts +8 -5
  6. package/src/lib/diagram/canvas/diagram-canvas-util.d.ts +10 -0
  7. package/src/lib/diagram/canvas/diagram-canvas.d.ts +4 -1
  8. package/src/lib/diagram/canvas/diagram-user-selection.d.ts +1 -1
  9. package/src/lib/diagram/collab/collab-action.d.ts +32 -2
  10. package/src/lib/diagram/config/diagram-canvas-config.d.ts +6 -0
  11. package/src/lib/diagram/config/diagram-components-config.d.ts +249 -0
  12. package/src/lib/diagram/config/diagram-config.d.ts +33 -248
  13. package/src/lib/diagram/diagram-action.d.ts +23 -0
  14. package/src/lib/diagram/layout/adjacency-layout.d.ts +2 -0
  15. package/src/lib/diagram/layout/breadth-adjacency-layout.d.ts +2 -0
  16. package/src/lib/diagram/layout/breadth-layout.d.ts +2 -0
  17. package/src/lib/diagram/layout/force-layout.d.ts +2 -0
  18. package/src/lib/diagram/layout/horizontal-layout.d.ts +2 -0
  19. package/src/lib/diagram/layout/priority-layout.d.ts +2 -0
  20. package/src/lib/diagram/layout/tree-layout.d.ts +2 -0
  21. package/src/lib/diagram/layout/vertical-layout.d.ts +2 -0
  22. package/src/lib/diagram/model/diagram-connection.d.ts +2 -1
  23. package/src/lib/diagram/model/diagram-model.d.ts +2 -1
  24. package/src/lib/diagram/model/diagram-node.d.ts +25 -2
  25. package/src/lib/diagram/property/property-util.d.ts +61 -0
  26. package/src/lib/diagram/property/property.d.ts +146 -0
  27. package/src/lib/diagram/property/value.d.ts +163 -0
  28. package/src/lib/interfaces/canvas.d.ts +14 -1
  29. package/src/lib/interfaces/property-editor.d.ts +1 -1
  30. package/src/lib/diagram/model/diagram-property.d.ts +0 -368
package/index.cjs.js CHANGED
@@ -1167,24 +1167,6 @@ class DiagramElementSet extends DiagramEntitySet {
1167
1167
  }
1168
1168
  }
1169
1169
 
1170
- /**
1171
- * Returns whether the incoming timestamp wins over the existing timestamp.
1172
- *
1173
- * In the DiagramModel, timestamps that have never been set are left null;
1174
- * `timestampWins` treats that as an "initial timestamp" that loses to all LogicalTimestamps.
1175
- */
1176
- function timestampWins(incoming, existing) {
1177
- if (!existing) return true;
1178
- if (incoming[0] > existing[0]) return true;
1179
- if (incoming[0] === existing[0]) {
1180
- // In case of equality, declare the incoming timestamp the "winner".
1181
- // This occurs if a client reuses a timestamp for multiple actions in a row,
1182
- // in which case the last created should win.
1183
- return incoming[1] >= existing[1];
1184
- }
1185
- return false;
1186
- }
1187
-
1188
1170
  /**
1189
1171
  * A property which is part of a property set and defines what values a value in a value set can take.
1190
1172
  * @public
@@ -1301,6 +1283,121 @@ class PropertySet {
1301
1283
  return this.propertyList.length > 0;
1302
1284
  }
1303
1285
  }
1286
+
1287
+ /**
1288
+ * Returns whether the incoming timestamp wins over the existing timestamp.
1289
+ *
1290
+ * In the DiagramModel, timestamps that have never been set are left null;
1291
+ * `timestampWins` treats that as an "initial timestamp" that loses to all LogicalTimestamps.
1292
+ */
1293
+ function timestampWins(incoming, existing) {
1294
+ if (!existing) return true;
1295
+ if (incoming[0] > existing[0]) return true;
1296
+ if (incoming[0] === existing[0]) {
1297
+ // In case of equality, declare the incoming timestamp the "winner".
1298
+ // This occurs if a client reuses a timestamp for multiple actions in a row,
1299
+ // in which case the last created should win.
1300
+ return incoming[1] >= existing[1];
1301
+ }
1302
+ return false;
1303
+ }
1304
+
1305
+ /**
1306
+ * Checks if the given value is not empty.
1307
+ * @private
1308
+ * @param a A value.
1309
+ * @returns `true` if the given value is not `undefined`, `null`, `''`, `[]` or `{}`; `false` otherwise.
1310
+ */
1311
+ const empty = a => {
1312
+ return a === undefined || a === null || a === '' || a instanceof Array && a.length === 0 || a instanceof Object && Object.keys(a).length === 0;
1313
+ };
1314
+ /**
1315
+ * Checks whether the given values are equal.
1316
+ * @public
1317
+ * @param a A value.
1318
+ * @param b A value.
1319
+ * @returns `true` if the given values are equal, `false` otherwise.
1320
+ */
1321
+ const equals = (a, b) => {
1322
+ return a === b || JSON.stringify(a) === JSON.stringify(b);
1323
+ };
1324
+ /**
1325
+ * Calculates the differences between the two given objects and returns two objects containing the differences in each relative to the other.
1326
+ *
1327
+ * For each key that holds a different value in the two objects, the resulting objects will contain the differences in the values under that key.
1328
+ *
1329
+ * This function is recursive, that is, if the value under the key is an object, the function will be applied to that value recursively.
1330
+ *
1331
+ * @public
1332
+ * @param a An object.
1333
+ * @param b An object.
1334
+ * @returns A tuple of two objects with each containing the keys that have a different value in the corresponding argument compared to the other argument.
1335
+ */
1336
+ const diff = (a, b) => {
1337
+ const aDiff = {};
1338
+ const bDiff = {};
1339
+ const allKeys = [];
1340
+ for (const key in a) {
1341
+ allKeys.push(key);
1342
+ }
1343
+ for (const key in b) {
1344
+ if (!(key in a)) {
1345
+ allKeys.push(key);
1346
+ }
1347
+ }
1348
+ for (const key of allKeys) {
1349
+ if (isObject(a[key]) && isObject(b[key])) {
1350
+ const diffAB = diff(a[key], b[key]);
1351
+ // only add the key if differences are detected
1352
+ if (Object.keys(diffAB[0]).length > 0 && Object.keys(diffAB[1]).length > 0) {
1353
+ aDiff[key] = diffAB[0];
1354
+ bDiff[key] = diffAB[1];
1355
+ }
1356
+ } else {
1357
+ if (!equals(a[key], b[key])) {
1358
+ aDiff[key] = a[key];
1359
+ bDiff[key] = b[key];
1360
+ }
1361
+ }
1362
+ }
1363
+ return [aDiff, bDiff];
1364
+ };
1365
+ /**
1366
+ * Calculates the differences between the two given values of a valueset and returns two objects containing the differences in each relative to the other.
1367
+ *
1368
+ * @param a An object.
1369
+ * @param b An object.
1370
+ * @param valueSet A ValueSet to use as reference for the keys and types of each property.
1371
+ * @returns A tuple of two objects with each containing the keys that have a different value in the corresponding argument compared to the other argument.
1372
+ */
1373
+ const diffProperties = (a, b, valueSet) => {
1374
+ const aDiff = {};
1375
+ const bDiff = {};
1376
+ for (const key in valueSet.propertySet.propertyMap) {
1377
+ if (valueSet.propertySet.propertyMap[key].type === exports.Type.Object) {
1378
+ const diffAB = diffProperties(a[key], b[key], valueSet.getSubValueSet(key));
1379
+ // only add the key if differences are detected
1380
+ if (Object.keys(diffAB[0]).length > 0 && Object.keys(diffAB[1]).length > 0) {
1381
+ aDiff[key] = diffAB[0];
1382
+ bDiff[key] = diffAB[1];
1383
+ }
1384
+ } else {
1385
+ if (!equals(a[key], b[key])) {
1386
+ aDiff[key] = a[key];
1387
+ bDiff[key] = b[key];
1388
+ }
1389
+ }
1390
+ }
1391
+ return [aDiff, bDiff];
1392
+ };
1393
+ /**
1394
+ * Checks if the given value is an object.
1395
+ * @public
1396
+ * @param x A value.
1397
+ * @returns `true` if the given value is an object, `false` otherwise.
1398
+ */
1399
+ const isObject = x => x !== undefined && x !== null && x.constructor === Object;
1400
+
1304
1401
  /**
1305
1402
  * A set of values corresponding to a set of properties.
1306
1403
  * @public
@@ -1594,10 +1691,8 @@ class ValueSet {
1594
1691
  this.values[key] = structuredClone(property.defaultValue);
1595
1692
  }
1596
1693
  if (rootAttribute !== undefined && rootAttribute !== null) {
1597
- if (property.defaultValue !== undefined && !equals(this.values[key], property.defaultValue)) {
1694
+ if (property.defaultValue !== undefined && !equals(this.getRootElementValue(rootAttribute), property.defaultValue)) {
1598
1695
  this.setRootElementValue(rootAttribute, this.values[key]);
1599
- } else {
1600
- this.values[key] = this.getRootElementValue(rootAttribute);
1601
1696
  }
1602
1697
  }
1603
1698
  if (property.basic) {
@@ -1652,101 +1747,6 @@ class ValueSet {
1652
1747
  }
1653
1748
  }
1654
1749
  }
1655
- /**
1656
- * Checks if the given value is not empty.
1657
- * @private
1658
- * @param a A value.
1659
- * @returns `true` if the given value is not `undefined`, `null`, `''`, `[]` or `{}`; `false` otherwise.
1660
- */
1661
- const empty = a => {
1662
- return a === undefined || a === null || a === '' || a instanceof Array && a.length === 0 || a instanceof Object && Object.keys(a).length === 0;
1663
- };
1664
- /**
1665
- * Checks whether the given values are equal.
1666
- * @public
1667
- * @param a A value.
1668
- * @param b A value.
1669
- * @returns `true` if the given values are equal, `false` otherwise.
1670
- */
1671
- const equals = (a, b) => {
1672
- return a === b || JSON.stringify(a) === JSON.stringify(b);
1673
- };
1674
- /**
1675
- * Calculates the differences between the two given objects and returns two objects containing the differences in each relative to the other.
1676
- *
1677
- * For each key that holds a different value in the two objects, the resulting objects will contain the differences in the values under that key.
1678
- *
1679
- * This function is recursive, that is, if the value under the key is an object, the function will be applied to that value recursively.
1680
- *
1681
- * @public
1682
- * @param a An object.
1683
- * @param b An object.
1684
- * @returns A tuple of two objects with each containing the keys that have a different value in the corresponding argument compared to the other argument.
1685
- */
1686
- const diff = (a, b) => {
1687
- const aDiff = {};
1688
- const bDiff = {};
1689
- const allKeys = [];
1690
- for (const key in a) {
1691
- allKeys.push(key);
1692
- }
1693
- for (const key in b) {
1694
- if (!(key in a)) {
1695
- allKeys.push(key);
1696
- }
1697
- }
1698
- for (const key of allKeys) {
1699
- if (isObject(a[key]) && isObject(b[key])) {
1700
- const diffAB = diff(a[key], b[key]);
1701
- // only add the key if differences are detected
1702
- if (Object.keys(diffAB[0]).length > 0 && Object.keys(diffAB[1]).length > 0) {
1703
- aDiff[key] = diffAB[0];
1704
- bDiff[key] = diffAB[1];
1705
- }
1706
- } else {
1707
- if (!equals(a[key], b[key])) {
1708
- aDiff[key] = a[key];
1709
- bDiff[key] = b[key];
1710
- }
1711
- }
1712
- }
1713
- return [aDiff, bDiff];
1714
- };
1715
- /**
1716
- * Calculates the differences between the two given values of a valueset and returns two objects containing the differences in each relative to the other.
1717
- *
1718
- * @param a An object.
1719
- * @param b An object.
1720
- * @param valueSet A ValueSet to use as reference for the keys and types of each property.
1721
- * @returns A tuple of two objects with each containing the keys that have a different value in the corresponding argument compared to the other argument.
1722
- */
1723
- const diffProperties = (a, b, valueSet) => {
1724
- const aDiff = {};
1725
- const bDiff = {};
1726
- for (const key in valueSet.propertySet.propertyMap) {
1727
- if (valueSet.propertySet.propertyMap[key].type === exports.Type.Object) {
1728
- const diffAB = diffProperties(a[key], b[key], valueSet.getSubValueSet(key));
1729
- // only add the key if differences are detected
1730
- if (Object.keys(diffAB[0]).length > 0 && Object.keys(diffAB[1]).length > 0) {
1731
- aDiff[key] = diffAB[0];
1732
- bDiff[key] = diffAB[1];
1733
- }
1734
- } else {
1735
- if (!equals(a[key], b[key])) {
1736
- aDiff[key] = a[key];
1737
- bDiff[key] = b[key];
1738
- }
1739
- }
1740
- }
1741
- return [aDiff, bDiff];
1742
- };
1743
- /**
1744
- * Checks if the given value is an object.
1745
- * @public
1746
- * @param x A value.
1747
- * @returns `true` if the given value is an object, `false` otherwise.
1748
- */
1749
- const isObject = x => x !== undefined && x !== null && x.constructor === Object;
1750
1750
 
1751
1751
  /**
1752
1752
  * Default values of the parameters of a diagram connection.
@@ -2983,6 +2983,7 @@ const DIAGRAM_NODE_TYPE_DEFAULTS = {
2983
2983
  padding: 0,
2984
2984
  label: null,
2985
2985
  ports: [],
2986
+ decorators: [],
2986
2987
  sectionGrid: null,
2987
2988
  look: DIAGRAM_NODE_LOOK_DEFAULTS,
2988
2989
  isUnique: false,
@@ -3013,6 +3014,7 @@ class DiagramNodeType {
3013
3014
  this.topPadding = getTopPadding(values);
3014
3015
  this.label = values.label;
3015
3016
  this.ports = values.ports;
3017
+ this.decorators = values.decorators;
3016
3018
  this.sectionGrid = values.sectionGrid ? new DiagramSectionGrid(values.sectionGrid) : null;
3017
3019
  const looks = extractLooksFromConfig(values.look);
3018
3020
  this.defaultLook = looks.defaultLook;
@@ -3156,15 +3158,15 @@ class DiagramNode extends DiagramElement {
3156
3158
  raise() {
3157
3159
  var _a;
3158
3160
  (_a = this.select()) === null || _a === undefined ? undefined : _a.raise();
3161
+ for (const section of this.sections) {
3162
+ section.raise();
3163
+ }
3159
3164
  if (this.label) {
3160
3165
  this.label.raise();
3161
3166
  }
3162
3167
  for (const port of this.ports) {
3163
3168
  port.raise();
3164
3169
  }
3165
- for (const section of this.sections) {
3166
- section.raise();
3167
- }
3168
3170
  for (const decorator of this.decorators) {
3169
3171
  decorator.raise();
3170
3172
  }
@@ -3598,6 +3600,106 @@ class DiagramNode extends DiagramElement {
3598
3600
  this.getConnections().forEach(c => c.tighten());
3599
3601
  this.updateInView();
3600
3602
  }
3603
+ /**
3604
+ * Removes all sections with the given index along the x axis.
3605
+ * @public
3606
+ */
3607
+ removeSectionColumn(columnIndex) {
3608
+ var _a;
3609
+ const margin = ((_a = this.type.sectionGrid) === null || _a === undefined ? undefined : _a.margin) || 0;
3610
+ let columnWidth = 0;
3611
+ const sections = [...this.sections];
3612
+ for (const section of sections) {
3613
+ if (section.indexYInNode === columnIndex) {
3614
+ columnWidth = Math.max(columnWidth, section.width);
3615
+ this.model.sections.remove(section.id);
3616
+ }
3617
+ }
3618
+ for (const section of sections) {
3619
+ if (section.indexYInNode > columnIndex) {
3620
+ --section.indexYInNode;
3621
+ section.move([section.coords[0] - columnWidth - margin, section.coords[1]]);
3622
+ }
3623
+ }
3624
+ this.stretch(exports.Side.Right, -margin - columnWidth);
3625
+ }
3626
+ /**
3627
+ * Removes all sections with the given index along the y axis.
3628
+ * @public
3629
+ */
3630
+ removeSectionRow(rowIndex) {
3631
+ var _a;
3632
+ const margin = ((_a = this.type.sectionGrid) === null || _a === undefined ? undefined : _a.margin) || 0;
3633
+ let rowHeight = 0;
3634
+ const sections = [...this.sections];
3635
+ for (const section of sections) {
3636
+ if (section.indexXInNode === rowIndex) {
3637
+ rowHeight = Math.max(rowHeight, section.height);
3638
+ this.model.sections.remove(section.id);
3639
+ }
3640
+ }
3641
+ for (const section of sections) {
3642
+ if (section.indexYInNode > rowIndex) {
3643
+ --section.indexXInNode;
3644
+ section.move([section.coords[0], section.coords[1] - rowHeight - margin]);
3645
+ }
3646
+ }
3647
+ this.stretch(exports.Side.Bottom, -margin - rowHeight);
3648
+ }
3649
+ /**
3650
+ * Creates a copy of all sections with the given index along the x axis.
3651
+ * @public
3652
+ */
3653
+ copySectionColumn(columnIndex) {
3654
+ var _a;
3655
+ const margin = ((_a = this.type.sectionGrid) === null || _a === undefined ? undefined : _a.margin) || 0;
3656
+ let columnWidth = 0;
3657
+ const sections = [...this.sections];
3658
+ for (const section of sections) {
3659
+ if (section.indexXInNode === columnIndex) {
3660
+ columnWidth = Math.max(columnWidth, section.width);
3661
+ let newSectionIdIndexX = section.indexXInNode + 1;
3662
+ while (this.model.sections.get(`${section.id}_copy_${newSectionIdIndexX}_${section.indexYInNode}`, true) !== undefined) {
3663
+ ++newSectionIdIndexX;
3664
+ }
3665
+ this.model.sections.new(this, section.indexXInNode + 1, section.indexYInNode, [section.coords[0] + section.width + margin, section.coords[1]], section.width, section.height, `${section.id}_copy_${newSectionIdIndexX}_${section.indexYInNode}`);
3666
+ }
3667
+ }
3668
+ for (const section of sections) {
3669
+ if (section.indexXInNode > columnIndex) {
3670
+ ++section.indexXInNode;
3671
+ section.move([section.coords[0] + columnWidth + margin, section.coords[1]]);
3672
+ }
3673
+ }
3674
+ this.stretch(exports.Side.Right, margin + columnWidth);
3675
+ }
3676
+ /**
3677
+ * Creates a copy of all sections with the given index along the y axis.
3678
+ * @public
3679
+ */
3680
+ copySectionRow(rowIndex) {
3681
+ var _a;
3682
+ const margin = ((_a = this.type.sectionGrid) === null || _a === undefined ? undefined : _a.margin) || 0;
3683
+ let rowHeight = 0;
3684
+ const sections = [...this.sections];
3685
+ for (const section of sections) {
3686
+ if (section.indexYInNode === rowIndex) {
3687
+ rowHeight = Math.max(rowHeight, section.height);
3688
+ let newSectionIdIndexY = section.indexYInNode + 1;
3689
+ while (this.model.sections.get(`${section.id}_copy_${section.indexXInNode}_${newSectionIdIndexY}`, true) !== undefined) {
3690
+ ++newSectionIdIndexY;
3691
+ }
3692
+ this.model.sections.new(this, section.indexXInNode, section.indexYInNode + 1, [section.coords[0], section.coords[1] + section.height + margin], section.width, section.height, `${section.id}_copy_${section.indexXInNode}_${newSectionIdIndexY}`);
3693
+ }
3694
+ }
3695
+ for (const section of sections) {
3696
+ if (section.indexYInNode > rowIndex) {
3697
+ ++section.indexYInNode;
3698
+ section.move([section.coords[0], section.coords[1] + rowHeight + margin]);
3699
+ }
3700
+ }
3701
+ this.stretch(exports.Side.Bottom, margin + rowHeight);
3702
+ }
3601
3703
  }
3602
3704
  class DiagramNodeSet extends DiagramElementSet {
3603
3705
  /**
@@ -3654,7 +3756,7 @@ class DiagramNodeSet extends DiagramElementSet {
3654
3756
  for (let i = 0; i < nodeType.ports.length; ++i) {
3655
3757
  const portConfig = nodeType.ports[i];
3656
3758
  const portType = portConfig.type !== undefined ? this.model.ports.types.get(portConfig.type) : undefined;
3657
- const port = this.model.ports.new(portType, node, [node.coords[0] + portConfig.coords[0], node.coords[1] + portConfig.coords[1]], portConfig.connectionPoint !== undefined ? [node.coords[0] + (portConfig.connectionPoint[0] || 0), node.coords[1] + (portConfig.connectionPoint[1] || 0)] : undefined, portConfig.direction, `${node.id}_${i}`);
3759
+ const port = this.model.ports.new(portType, node, [node.coords[0] + portConfig.coords[0], node.coords[1] + portConfig.coords[1]], portConfig.connectionPoint !== undefined ? [node.coords[0] + (portConfig.connectionPoint[0] || 0), node.coords[1] + (portConfig.connectionPoint[1] || 0)] : undefined, portConfig.direction, `${node.id}_port_${i}`);
3658
3760
  if ((_e = port.type) === null || _e === undefined ? undefined : _e.label) {
3659
3761
  const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), (_f = port.type) === null || _f === undefined ? undefined : _f.label);
3660
3762
  const labelWidth = 6 * labelConfiguration.fontSize + getLeftPadding$1(labelConfiguration) + getRightPadding$1(labelConfiguration);
@@ -3681,6 +3783,13 @@ class DiagramNodeSet extends DiagramElementSet {
3681
3783
  const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), nodeType.label);
3682
3784
  this.model.fields.new(node, [node.coords[0] + getLeftMargin(labelConfiguration), node.coords[1] + getTopMargin(labelConfiguration)], labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, node.width - getLeftMargin(labelConfiguration) - getRightMargin(labelConfiguration), node.height - getTopMargin(labelConfiguration) - getBottomMargin(labelConfiguration), labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, labelConfiguration.fit);
3683
3785
  }
3786
+ // add node decorators
3787
+ if (nodeType.decorators.length > 0) {
3788
+ for (let i = 0; i < nodeType.decorators.length; ++i) {
3789
+ const decoratorConfig = nodeType.decorators[i];
3790
+ this.model.decorators.new(node, [node.coords[0] + decoratorConfig.coords[0], node.coords[1] + decoratorConfig.coords[1]], decoratorConfig.width, decoratorConfig.height, node.getPriority(), decoratorConfig.html, `${node.id}_decorator_${i}`);
3791
+ }
3792
+ }
3684
3793
  node.valueSet.resetValues();
3685
3794
  (_g = node.model.canvas) === null || _g === undefined ? undefined : _g.fitNodeInView(node.id);
3686
3795
  return node;
@@ -4209,6 +4318,13 @@ class DagaImporter {
4209
4318
  newNode.width = node.width;
4210
4319
  newNode.height = node.height;
4211
4320
  if (node.label) {
4321
+ // add node decorators
4322
+ if (newNodeType.decorators) {
4323
+ for (let i = 0; i < newNodeType.decorators.length; ++i) {
4324
+ const decoratorConfig = newNodeType.decorators[i];
4325
+ model.decorators.new(newNode, [newNode.coords[0] + decoratorConfig.coords[0], newNode.coords[1] + decoratorConfig.coords[1]], decoratorConfig.width, decoratorConfig.height, newNode.getPriority(), decoratorConfig.html, `${newNode.id}_decorator_${i}`);
4326
+ }
4327
+ }
4212
4328
  // add node label
4213
4329
  if (newNodeType.label) {
4214
4330
  const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), newNodeType.label);
@@ -4421,6 +4537,54 @@ class AddNodeCollabAction {
4421
4537
  return new AddNodeCollabAction(canvas, serialized.id, serialized.typeId, serialized.coords, serialized.parentId, serialized.label, serialized.values);
4422
4538
  }
4423
4539
  }
4540
+ /**
4541
+ * Collaborative action which consists of adding or removing sections in a node.
4542
+ * @private
4543
+ * @see AddNodeAction
4544
+ */
4545
+ class AddSectionCollabAction {
4546
+ constructor(canvas, nodeId, copyColumnIndex, copyRowIndex, removeColumnIndex, removeRowIndex, timestamp) {
4547
+ this.canvas = canvas;
4548
+ this.nodeId = nodeId;
4549
+ this.copyColumnIndex = copyColumnIndex;
4550
+ this.copyRowIndex = copyRowIndex;
4551
+ this.removeColumnIndex = removeColumnIndex;
4552
+ this.removeRowIndex = removeRowIndex;
4553
+ this.timestamp = timestamp;
4554
+ }
4555
+ do() {
4556
+ const node = this.canvas.model.nodes.get(this.nodeId);
4557
+ if (node && timestampWins(this.timestamp, node.geometryTimestamp)) {
4558
+ if (this.copyColumnIndex !== undefined) {
4559
+ node.copySectionColumn(this.copyColumnIndex);
4560
+ }
4561
+ if (this.copyRowIndex !== undefined) {
4562
+ node.copySectionRow(this.copyRowIndex);
4563
+ }
4564
+ if (this.removeColumnIndex !== undefined) {
4565
+ node.removeSectionColumn(this.removeColumnIndex);
4566
+ }
4567
+ if (this.removeRowIndex !== undefined) {
4568
+ node.removeSectionRow(this.removeRowIndex);
4569
+ }
4570
+ node.geometryTimestamp = this.timestamp;
4571
+ }
4572
+ }
4573
+ serialize() {
4574
+ return {
4575
+ type: 'addSection',
4576
+ nodeId: this.nodeId,
4577
+ copyColumnIndex: this.copyColumnIndex,
4578
+ copyRowIndex: this.copyRowIndex,
4579
+ removeColumnIndex: this.removeColumnIndex,
4580
+ removeRowIndex: this.removeRowIndex,
4581
+ timestamp: this.timestamp
4582
+ };
4583
+ }
4584
+ static deserialize(canvas, serialized) {
4585
+ return new AddSectionCollabAction(canvas, serialized.nodeId, serialized.copyColumnIndex, serialized.copyRowIndex, serialized.removeColumnIndex, serialized.removeRowIndex, serialized.timestamp);
4586
+ }
4587
+ }
4424
4588
  /**
4425
4589
  * Collaborative which consists of applying a layout to the diagram which can change the location of several nodes.
4426
4590
  * @private
@@ -4837,6 +5001,12 @@ class CollabEngine {
4837
5001
  action.do();
4838
5002
  break;
4839
5003
  }
5004
+ case 'addSection':
5005
+ {
5006
+ const action = AddSectionCollabAction.deserialize(this.canvas, message);
5007
+ action.do();
5008
+ break;
5009
+ }
4840
5010
  case 'applyLayout':
4841
5011
  {
4842
5012
  const action = ApplyLayoutCollabAction.deserialize(this.canvas, message);
@@ -4999,6 +5169,12 @@ exports.DiagramActions = void 0;
4999
5169
  * @see AddNodeAction
5000
5170
  */
5001
5171
  DiagramActions["AddNode"] = "add-node";
5172
+ /**
5173
+ * Action that corresponds to the addition or removal of sections in a node.
5174
+ * @public
5175
+ * @see AddSectionAction
5176
+ */
5177
+ DiagramActions["AddSectionAction"] = "add-section";
5002
5178
  /**
5003
5179
  * Action that corresponds to applying a layout which changes the location of several nodes.
5004
5180
  * @public
@@ -5930,6 +6106,32 @@ const updateLook = selection => {
5930
6106
  selection.filter('.stretchable-image-look').select('image.bottom-image').attr('x', d => d.look.leftMargin).attr('y', d => d.height - d.look.bottomMargin).attr('width', d => d.width - d.look.rightMargin - d.look.leftMargin).attr('height', d => d.look.bottomMargin).attr('href', d => d.look.backgroundImageBottom);
5931
6107
  selection.filter('.stretchable-image-look').select('image.bottom-right-image').attr('x', d => d.width - d.look.rightMargin).attr('y', d => d.height - d.look.bottomMargin).attr('width', d => d.look.rightMargin).attr('height', d => d.look.bottomMargin).attr('href', d => d.look.backgroundImageBottomRight);
5932
6108
  };
6109
+ const GRID_DEFAULTS = {
6110
+ enabled: true,
6111
+ style: 'dots',
6112
+ color: 'rgba(0, 0, 0, 0.1)',
6113
+ snap: false,
6114
+ spacing: 10,
6115
+ thickness: 0.05
6116
+ };
6117
+ const initializeGrid = (canvas, canvasView, backgroundPatternId) => {
6118
+ const canvasDefs = canvasView.append('defs');
6119
+ if (canvas.gridSize > 0 && isFinite(canvas.gridSize)) {
6120
+ const canvasBackgroundPattern = canvasDefs.append('pattern').attr('id', backgroundPatternId).attr('x', -canvas.gridSize / 2).attr('y', -canvas.gridSize / 2).attr('width', canvas.gridSize).attr('height', canvas.gridSize).attr('patternUnits', 'userSpaceOnUse');
6121
+ canvasBackgroundPattern.append('rect').attr('x', 0).attr('y', 0).attr('width', canvas.gridSize).attr('height', canvas.gridSize).attr('fill', canvas.backgroundColor);
6122
+ switch (canvas.gridStyle) {
6123
+ case 'dots':
6124
+ canvasBackgroundPattern.append('circle').attr('cx', canvas.gridSize / 2).attr('cy', canvas.gridSize / 2).attr('r', canvas.gridSize * canvas.gridThickness).attr('fill', canvas.gridColor);
6125
+ break;
6126
+ case 'lines':
6127
+ canvasBackgroundPattern.append('line').attr('x1', canvas.gridSize / 2).attr('x2', canvas.gridSize / 2).attr('y1', 0).attr('y2', canvas.gridSize).attr('stroke-width', canvas.gridSize * canvas.gridThickness).attr('stroke', canvas.gridColor);
6128
+ canvasBackgroundPattern.append('line').attr('x1', 0).attr('x2', (canvas.gridSize - canvas.gridSize * canvas.gridThickness) / 2).attr('y1', canvas.gridSize / 2).attr('y2', canvas.gridSize / 2).attr('stroke-width', canvas.gridSize * canvas.gridThickness).attr('stroke', canvas.gridColor);
6129
+ canvasBackgroundPattern.append('line').attr('x1', (canvas.gridSize + canvas.gridSize * canvas.gridThickness) / 2).attr('x2', canvas.gridSize).attr('y1', canvas.gridSize / 2).attr('y2', canvas.gridSize / 2).attr('stroke-width', canvas.gridSize * canvas.gridThickness).attr('stroke', canvas.gridColor);
6130
+ break;
6131
+ }
6132
+ canvasView.select('rect').attr('fill', `url(#${backgroundPatternId})`);
6133
+ }
6134
+ };
5933
6135
 
5934
6136
  const CONTEXT_MENU_MENU_RADIUS = 96;
5935
6137
  const CONTEXT_MENU_BUTTON_RADIUS = 32;
@@ -6099,7 +6301,7 @@ class DiagramUserHighlight extends DiagramElementSet {
6099
6301
  focusOn(element) {
6100
6302
  this.clear();
6101
6303
  this.focus = element;
6102
- if (element instanceof DiagramField && element.rootElement) {
6304
+ if ((element instanceof DiagramField || element instanceof DiagramDecorator) && element.rootElement) {
6103
6305
  this.focusOn(element.rootElement);
6104
6306
  } else {
6105
6307
  this.add(element);
@@ -6587,7 +6789,7 @@ class DiagramCanvas {
6587
6789
  * @param config The configuration object used to set the parameters of this canvas.
6588
6790
  */
6589
6791
  constructor(parentComponent, config) {
6590
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
6792
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
6591
6793
  this.backgroundPatternId = `daga-background-pattern-id-${DiagramCanvas.canvasCount++}`;
6592
6794
  this.zoomTransform = d3__namespace.zoomIdentity;
6593
6795
  // used to distinguish drags from clicks when dragging elements and during multiple selection
@@ -6606,15 +6808,16 @@ class DiagramCanvas {
6606
6808
  this.userHighlight = new DiagramUserHighlight(this);
6607
6809
  this.contextMenu = new DiagramContextMenu(this, (_a = config.canvas) === null || _a === undefined ? undefined : _a.contextMenu);
6608
6810
  this.backgroundColor = ((_b = config.canvas) === null || _b === undefined ? undefined : _b.backgroundColor) || '#FFFFFF';
6609
- this.gridSize = ((_d = (_c = config.canvas) === null || _c === undefined ? undefined : _c.grid) === null || _d === undefined ? undefined : _d.enabled) === false || ((_e = config.canvas) === null || _e === undefined ? undefined : _e.grid) === undefined ? 0 : Math.abs(((_g = (_f = config.canvas) === null || _f === undefined ? undefined : _f.grid) === null || _g === undefined ? undefined : _g.spacing) || 10);
6610
- this.gridThickness = Math.abs(((_j = (_h = config.canvas) === null || _h === undefined ? undefined : _h.grid) === null || _j === undefined ? undefined : _j.thickness) || 0.05);
6611
- this.gridColor = ((_l = (_k = config.canvas) === null || _k === undefined ? undefined : _k.grid) === null || _l === undefined ? undefined : _l.color) || 'rgba(0, 0, 0, 0.1)';
6612
- this.snapToGrid = ((_o = (_m = config.canvas) === null || _m === undefined ? undefined : _m.grid) === null || _o === undefined ? undefined : _o.enabled) === false || ((_p = config.canvas) === null || _p === undefined ? undefined : _p.grid) === undefined ? false : ((_r = (_q = config.canvas) === null || _q === undefined ? undefined : _q.grid) === null || _r === undefined ? undefined : _r.snap) || false;
6613
- this.zoomFactor = ((_s = config.canvas) === null || _s === undefined ? undefined : _s.zoomFactor) || 2;
6614
- this.panRate = ((_t = config.canvas) === null || _t === undefined ? undefined : _t.panRate) || 100;
6811
+ this.gridStyle = (_e = (_d = (_c = config.canvas) === null || _c === undefined ? undefined : _c.grid) === null || _d === undefined ? undefined : _d.style) !== null && _e !== undefined ? _e : GRID_DEFAULTS.style;
6812
+ this.gridSize = ((_g = (_f = config.canvas) === null || _f === undefined ? undefined : _f.grid) === null || _g === undefined ? undefined : _g.enabled) === false || ((_h = config.canvas) === null || _h === undefined ? undefined : _h.grid) === undefined ? 0 : Math.abs(((_k = (_j = config.canvas) === null || _j === undefined ? undefined : _j.grid) === null || _k === undefined ? undefined : _k.spacing) || GRID_DEFAULTS.spacing);
6813
+ this.gridThickness = Math.abs(((_m = (_l = config.canvas) === null || _l === undefined ? undefined : _l.grid) === null || _m === undefined ? undefined : _m.thickness) || GRID_DEFAULTS.thickness);
6814
+ this.gridColor = ((_p = (_o = config.canvas) === null || _o === undefined ? undefined : _o.grid) === null || _p === undefined ? undefined : _p.color) || GRID_DEFAULTS.color;
6815
+ this.snapToGrid = ((_r = (_q = config.canvas) === null || _q === undefined ? undefined : _q.grid) === null || _r === undefined ? undefined : _r.enabled) === false || ((_s = config.canvas) === null || _s === undefined ? undefined : _s.grid) === undefined ? false : ((_u = (_t = config.canvas) === null || _t === undefined ? undefined : _t.grid) === null || _u === undefined ? undefined : _u.snap) || GRID_DEFAULTS.snap;
6816
+ this.zoomFactor = ((_v = config.canvas) === null || _v === undefined ? undefined : _v.zoomFactor) || 2;
6817
+ this.panRate = ((_w = config.canvas) === null || _w === undefined ? undefined : _w.panRate) || 100;
6615
6818
  this.inferConnectionType = config.inferConnectionType || false;
6616
6819
  this.multipleSelectionOn = false;
6617
- this.priorityThresholds = ((_u = config.canvas) === null || _u === undefined ? undefined : _u.priorityThresholds) || [];
6820
+ this.priorityThresholds = ((_x = config.canvas) === null || _x === undefined ? undefined : _x.priorityThresholds) || [];
6618
6821
  this.priorityThreshold = this.priorityThresholds ? this.priorityThresholds[0] : undefined;
6619
6822
  this.layoutFormat = config.layoutFormat;
6620
6823
  this.userActions = config.userActions || {};
@@ -6741,23 +6944,29 @@ class DiagramCanvas {
6741
6944
  }
6742
6945
  }
6743
6946
  if (event.ctrlKey && event.key === 'c') {
6744
- event.preventDefault();
6745
- // copy
6746
- this.userSelection.copyToClipboard();
6747
- this.cancelAllUserActions();
6947
+ if (this.canUserPerformAction(exports.DiagramActions.Clipboard)) {
6948
+ event.preventDefault();
6949
+ // copy
6950
+ this.userSelection.copyToClipboard();
6951
+ this.cancelAllUserActions();
6952
+ }
6748
6953
  }
6749
6954
  if (event.ctrlKey && event.key === 'x') {
6750
- event.preventDefault();
6751
- // cut
6752
- this.userSelection.cutToClipboard();
6753
- this.cancelAllUserActions();
6955
+ if (this.canUserPerformAction(exports.DiagramActions.Clipboard) && this.canUserPerformAction(exports.DiagramActions.Remove)) {
6956
+ event.preventDefault();
6957
+ // cut
6958
+ this.userSelection.cutToClipboard();
6959
+ this.cancelAllUserActions();
6960
+ }
6754
6961
  }
6755
6962
  if (event.ctrlKey && event.key === 'v') {
6756
- event.preventDefault();
6757
- // paste
6758
- const coordinateRange = this.getCoordinatesOnScreen();
6759
- this.userSelection.pasteFromClipboard(this.getClosestGridPoint([(coordinateRange[0][0] + coordinateRange[1][0]) / 2, (coordinateRange[0][1] + coordinateRange[1][1]) / 2]));
6760
- this.cancelAllUserActions();
6963
+ if (this.canUserPerformAction(exports.DiagramActions.Paste)) {
6964
+ event.preventDefault();
6965
+ // paste
6966
+ const coordinateRange = this.getCoordinatesOnScreen();
6967
+ this.userSelection.pasteFromClipboard(this.getClosestGridPoint([(coordinateRange[0][0] + coordinateRange[1][0]) / 2, (coordinateRange[0][1] + coordinateRange[1][1]) / 2]));
6968
+ this.cancelAllUserActions();
6969
+ }
6761
6970
  }
6762
6971
  if (event.ctrlKey && event.key === 'y') {
6763
6972
  event.preventDefault();
@@ -6770,38 +6979,50 @@ class DiagramCanvas {
6770
6979
  this.actionStack.undo();
6771
6980
  }
6772
6981
  if (event.key === '+') {
6773
- event.preventDefault();
6774
- // zoom in
6775
- this.zoomBy(this.zoomFactor);
6982
+ if (this.canUserPerformAction(exports.DiagramActions.Zoom)) {
6983
+ event.preventDefault();
6984
+ // zoom in
6985
+ this.zoomBy(this.zoomFactor);
6986
+ }
6776
6987
  }
6777
6988
  if (event.key === '-') {
6778
- event.preventDefault();
6779
- // zoom out
6780
- this.zoomBy(1 / this.zoomFactor);
6989
+ if (this.canUserPerformAction(exports.DiagramActions.Zoom)) {
6990
+ event.preventDefault();
6991
+ // zoom out
6992
+ this.zoomBy(1 / this.zoomFactor);
6993
+ }
6781
6994
  }
6782
6995
  if (event.key === exports.Keys.ArrowLeft) {
6783
- event.preventDefault();
6784
- // move left, faster if we're zoomed out and slower if we're zoomed in
6785
- this.translateBy(this.panRate / this.zoomTransform.k, 0);
6996
+ if (this.canUserPerformAction(exports.DiagramActions.Zoom)) {
6997
+ event.preventDefault();
6998
+ // move left, faster if we're zoomed out and slower if we're zoomed in
6999
+ this.translateBy(this.panRate / this.zoomTransform.k, 0);
7000
+ }
6786
7001
  }
6787
7002
  if (event.key === exports.Keys.ArrowRight) {
6788
- event.preventDefault();
6789
- // move right, faster if we're zoomed out and slower if we're zoomed in
6790
- this.translateBy(-this.panRate / this.zoomTransform.k, 0);
7003
+ if (this.canUserPerformAction(exports.DiagramActions.Zoom)) {
7004
+ event.preventDefault();
7005
+ // move right, faster if we're zoomed out and slower if we're zoomed in
7006
+ this.translateBy(-this.panRate / this.zoomTransform.k, 0);
7007
+ }
6791
7008
  }
6792
7009
  if (event.key === exports.Keys.ArrowDown) {
6793
- event.preventDefault();
6794
- // move down, faster if we're zoomed out and slower if we're zoomed in
6795
- this.translateBy(0, -this.panRate / this.zoomTransform.k);
7010
+ if (this.canUserPerformAction(exports.DiagramActions.Zoom)) {
7011
+ event.preventDefault();
7012
+ // move down, faster if we're zoomed out and slower if we're zoomed in
7013
+ this.translateBy(0, -this.panRate / this.zoomTransform.k);
7014
+ }
6796
7015
  }
6797
7016
  if (event.key === exports.Keys.ArrowUp) {
6798
- event.preventDefault();
6799
- // move up, faster if we're zoomed out and slower if we're zoomed in
6800
- this.translateBy(0, this.panRate / this.zoomTransform.k);
7017
+ if (this.canUserPerformAction(exports.DiagramActions.Zoom)) {
7018
+ event.preventDefault();
7019
+ // move up, faster if we're zoomed out and slower if we're zoomed in
7020
+ this.translateBy(0, this.panRate / this.zoomTransform.k);
7021
+ }
6801
7022
  }
6802
7023
  });
6803
7024
  const canvasView = this.selectSVGElement().append('g').attr('class', 'daga-canvas-view').attr('width', `100%`).attr('height', `100%`);
6804
- const canvasBackground = canvasView.append('rect').attr('x', 0).attr('y', 0).attr('width', `100%`).attr('height', `100%`).attr('fill', this.backgroundColor).attr('stroke-width', '0').on(exports.Events.MouseMove, event => {
7025
+ canvasView.append('rect').attr('x', 0).attr('y', 0).attr('width', `100%`).attr('height', `100%`).attr('fill', this.backgroundColor).attr('stroke-width', '0').on(exports.Events.MouseMove, event => {
6805
7026
  if (this.unfinishedConnection !== undefined) {
6806
7027
  const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
6807
7028
  this.unfinishedConnection.endCoords = pointerCoords;
@@ -6857,13 +7078,7 @@ class DiagramCanvas {
6857
7078
  }).on(exports.ZoomEvents.End, () => {
6858
7079
  setCursorStyle();
6859
7080
  }));
6860
- const canvasDefs = canvasView.append('defs');
6861
- if (this.gridSize > 0 && isFinite(this.gridSize)) {
6862
- const canvasBackgroundPattern = canvasDefs.append('pattern').attr('id', this.backgroundPatternId).attr('x', -this.gridSize / 2).attr('y', -this.gridSize / 2).attr('width', this.gridSize).attr('height', this.gridSize).attr('patternUnits', 'userSpaceOnUse');
6863
- canvasBackgroundPattern.append('rect').attr('x', 0).attr('y', 0).attr('width', this.gridSize).attr('height', this.gridSize).attr('fill', this.backgroundColor);
6864
- canvasBackgroundPattern.append('circle').attr('cx', this.gridSize / 2).attr('cy', this.gridSize / 2).attr('r', this.gridSize * this.gridThickness).attr('fill', this.gridColor);
6865
- canvasBackground.attr('fill', `url(#${this.backgroundPatternId})`);
6866
- }
7081
+ initializeGrid(this, canvasView, this.backgroundPatternId);
6867
7082
  canvasView.append('g').attr('class', 'daga-canvas-elements');
6868
7083
  }
6869
7084
  zoomBy(factor) {
@@ -7839,7 +8054,23 @@ class DiagramCanvas {
7839
8054
  const mergeSelection = enterSelection.merge(updateSelection);
7840
8055
  mergeSelection.attr('width', d => `${d.width}px`).attr('height', d => `${d.height}px`).attr('transform', d => `translate(${d.coords[0]},${d.coords[1]})`).html(d => d.html);
7841
8056
  exitSelection.remove();
7842
- enterSelection.on(exports.Events.ContextMenu, (event, d) => {
8057
+ enterSelection.on(exports.Events.MouseOver, (_event, d) => {
8058
+ if (!this.dragging) {
8059
+ this.userHighlight.focusOn(d);
8060
+ this.diagramEvent$.next(new DiagramHighlightedEvent(d));
8061
+ }
8062
+ }).on(exports.Events.Click, (event, d) => {
8063
+ if (!event.ctrlKey && !event.shiftKey) {
8064
+ const deselectedElements = this.userSelection.all();
8065
+ this.userSelection.clear();
8066
+ this.diagramEvent$.next(new DiagramSelectionEvent(deselectedElements, false));
8067
+ }
8068
+ if (d.rootElement) {
8069
+ const elementToBeToggled = getRelatedNodeOrItself(d.rootElement);
8070
+ this.userSelection.toggle(elementToBeToggled);
8071
+ this.diagramEvent$.next(new DiagramSelectionEvent([elementToBeToggled], elementToBeToggled.selected));
8072
+ }
8073
+ }).on(exports.Events.ContextMenu, (event, d) => {
7843
8074
  if (this.dragging) {
7844
8075
  event.preventDefault();
7845
8076
  event.stopPropagation();
@@ -7849,8 +8080,15 @@ class DiagramCanvas {
7849
8080
  const diagramEvent = new DiagramSecondaryClickEvent(event, d);
7850
8081
  this.diagramEvent$.next(diagramEvent);
7851
8082
  if (!diagramEvent.defaultPrevented && this.canUserPerformAction(exports.DiagramActions.ContextMenu)) {
7852
- event.preventDefault();
7853
- this.contextMenu.open(event);
8083
+ if (d.rootElement) {
8084
+ event.preventDefault();
8085
+ const elementToSelect = getRelatedNodeOrItself(d.rootElement);
8086
+ this.userHighlight.focusOn(elementToSelect);
8087
+ this.diagramEvent$.next(new DiagramHighlightedEvent(elementToSelect));
8088
+ this.userSelection.add(elementToSelect);
8089
+ this.diagramEvent$.next(new DiagramSelectionEvent([elementToSelect], true));
8090
+ this.contextMenu.open(event);
8091
+ }
7854
8092
  }
7855
8093
  }).on(exports.Events.DoubleClick, (event, d) => {
7856
8094
  const diagramEvent = new DiagramDoubleClickEvent(event, d);
@@ -7911,7 +8149,7 @@ class DiagramCanvas {
7911
8149
  }
7912
8150
  updateConnectionLabelsInView(connection) {
7913
8151
  var _a, _b, _c;
7914
- const connectionSelection = this.selectCanvasView().select(`g.diagram-connection#${connection.id}`);
8152
+ const connectionSelection = this.selectCanvasView().select(`[id='${escapeSelector(connection.id)}']`);
7915
8153
  const pathSelection = connectionSelection.select('path');
7916
8154
  const pathNode = pathSelection.node();
7917
8155
  const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), connection.type.label);
@@ -7953,7 +8191,7 @@ class DiagramCanvas {
7953
8191
  }
7954
8192
  }
7955
8193
  updateConnectionMarkersInView(connection) {
7956
- const connectionSelection = this.selectCanvasView().select(`g.diagram-connection#${connection.id}`);
8194
+ const connectionSelection = this.selectCanvasView().select(`[id='${escapeSelector(connection.id)}']`);
7957
8195
  const startMarkerSelection = connectionSelection.select('marker.diagram-connection-start-marker');
7958
8196
  const endMarkerSelection = connectionSelection.select('marker.diagram-connection-end-marker');
7959
8197
  if (connection.startMarkerLook !== null) {
@@ -7967,13 +8205,27 @@ class DiagramCanvas {
7967
8205
  endMarkerSelection.attr('orient', 'auto-start-reverse').attr('markerWidth', 0).attr('markerHeight', 0);
7968
8206
  }
7969
8207
  }
7970
- fitFieldRootInView(id) {
8208
+ fieldRootFitsInView(id) {
8209
+ var _a, _b, _c, _d;
8210
+ const field = this.model.fields.get(id);
8211
+ if (!field) {
8212
+ return false;
8213
+ }
8214
+ if (field.rootElement instanceof DiagramNode || field.rootElement instanceof DiagramSection) {
8215
+ const fieldDimensions = this.minimumSizeOfField(field);
8216
+ const stretchX = fieldDimensions[0] + getLeftMargin((_a = field.rootElement.type) === null || _a === undefined ? undefined : _a.label) + getRightMargin((_b = field.rootElement.type) === null || _b === undefined ? undefined : _b.label) - field.rootElement.width;
8217
+ const stretchY = fieldDimensions[1] + getTopMargin((_c = field.rootElement.type) === null || _c === undefined ? undefined : _c.label) + getBottomMargin((_d = field.rootElement.type) === null || _d === undefined ? undefined : _d.label) - field.rootElement.height;
8218
+ return stretchX <= 0 && stretchY <= 0;
8219
+ }
8220
+ return true;
8221
+ }
8222
+ fitFieldRootInView(id, shrink) {
7971
8223
  var _a, _b, _c;
7972
8224
  const field = this.model.fields.get(id);
7973
8225
  if (!field) {
7974
8226
  return;
7975
8227
  }
7976
- if (field.rootElement instanceof DiagramNode && field.fit) {
8228
+ if (field.rootElement instanceof DiagramNode) {
7977
8229
  const fieldDimensions = this.minimumSizeOfField(field);
7978
8230
  let stretchX = fieldDimensions[0] + getLeftMargin(field.rootElement.type.label) + getRightMargin(field.rootElement.type.label) - field.rootElement.width;
7979
8231
  let stretchY = fieldDimensions[1] + getTopMargin(field.rootElement.type.label) + getBottomMargin(field.rootElement.type.label) - field.rootElement.height;
@@ -7988,10 +8240,14 @@ class DiagramCanvas {
7988
8240
  if (field.rootElement.height + stretchY < field.rootElement.type.minHeight) {
7989
8241
  stretchY = field.rootElement.type.minHeight - field.rootElement.height;
7990
8242
  }
7991
- field.rootElement.stretch(exports.Side.Right, stretchX);
7992
- field.rootElement.stretch(exports.Side.Bottom, stretchY);
8243
+ if (shrink !== false || stretchX > 0) {
8244
+ field.rootElement.stretch(exports.Side.Right, stretchX);
8245
+ }
8246
+ if (shrink !== false || stretchY > 0) {
8247
+ field.rootElement.stretch(exports.Side.Bottom, stretchY);
8248
+ }
7993
8249
  }
7994
- if (field.rootElement instanceof DiagramSection && field.fit) {
8250
+ if (field.rootElement instanceof DiagramSection) {
7995
8251
  const fieldDimensions = this.minimumSizeOfField(field);
7996
8252
  let minimumFieldWidth = fieldDimensions[0];
7997
8253
  let minimumFieldHeight = fieldDimensions[1];
@@ -8024,8 +8280,12 @@ class DiagramCanvas {
8024
8280
  if (field.rootElement.height + stretchY < (field.rootElement.getMinHeight() || 0)) {
8025
8281
  stretchY = (field.rootElement.getMinHeight() || 0) - field.rootElement.height;
8026
8282
  }
8027
- (_b = field.rootElement.node) === null || _b === undefined ? undefined : _b.stretchSections(exports.Side.Right, stretchX, field.rootElement.indexXInNode, field.rootElement.indexYInNode);
8028
- (_c = field.rootElement.node) === null || _c === undefined ? undefined : _c.stretchSections(exports.Side.Bottom, stretchY, field.rootElement.indexXInNode, field.rootElement.indexYInNode);
8283
+ if (shrink !== false || stretchX > 0) {
8284
+ (_b = field.rootElement.node) === null || _b === undefined ? undefined : _b.stretchSections(exports.Side.Right, stretchX, field.rootElement.indexXInNode, field.rootElement.indexYInNode);
8285
+ }
8286
+ if (shrink !== false || stretchY > 0) {
8287
+ (_c = field.rootElement.node) === null || _c === undefined ? undefined : _c.stretchSections(exports.Side.Bottom, stretchY, field.rootElement.indexXInNode, field.rootElement.indexYInNode);
8288
+ }
8029
8289
  }
8030
8290
  }
8031
8291
  fitNodeInView(id) {
@@ -8324,18 +8584,18 @@ class DiagramCanvas {
8324
8584
  }
8325
8585
  startMultipleSelection(event) {
8326
8586
  this.draggingFrom = this.getPointerLocationRelativeToCanvas(event);
8327
- /* TODO: would be a good idea to build the multipleSelectionContainer
8328
- * from selectRoot() instead of selectCanvasElements()
8329
- * to avoid having the thickness of the rectangle be affected by zoom
8330
- */
8331
- this.multipleSelectionContainer = this.selectCanvasElements().append('rect').attr('stroke', '#0E74B6').attr('fill', 'rgba(14, 116, 182, 0.06)');
8587
+ // we put the multiple selection rectangle in the diagram svg element
8588
+ // so it's not affected by the zoom level in the diagram elements
8589
+ this.multipleSelectionContainer = this.selectSVGElement().append('rect').attr('stroke', '#0E74B6').attr('fill', 'rgba(14, 116, 182, 0.06)');
8332
8590
  }
8333
8591
  continueMultipleSelection(event) {
8334
8592
  var _a, _b, _c, _d;
8335
8593
  const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
8336
8594
  if (this.draggingFrom[0] !== pointerCoords[0] || this.draggingFrom[1] !== pointerCoords[1]) {
8337
8595
  setCursorStyle(exports.CursorStyle.Crosshair);
8338
- (_d = (_c = (_b = (_a = this.multipleSelectionContainer) === null || _a === undefined ? undefined : _a.attr('x', Math.min(this.draggingFrom[0], pointerCoords[0]))) === null || _b === undefined ? undefined : _b.attr('y', Math.min(this.draggingFrom[1], pointerCoords[1]))) === null || _c === undefined ? undefined : _c.attr('width', Math.abs(this.draggingFrom[0] - pointerCoords[0]))) === null || _d === undefined ? undefined : _d.attr('height', Math.abs(this.draggingFrom[1] - pointerCoords[1]));
8596
+ // since the multiple selection rectangle is not affected by zoom,
8597
+ // we compensate its coordinates based in the zoom transform to draw it
8598
+ (_d = (_c = (_b = (_a = this.multipleSelectionContainer) === null || _a === undefined ? undefined : _a.attr('x', Math.min(this.draggingFrom[0], pointerCoords[0]) * this.zoomTransform.k + this.zoomTransform.x)) === null || _b === undefined ? undefined : _b.attr('y', Math.min(this.draggingFrom[1], pointerCoords[1]) * this.zoomTransform.k + this.zoomTransform.y)) === null || _c === undefined ? undefined : _c.attr('width', Math.abs(this.draggingFrom[0] - pointerCoords[0]) * this.zoomTransform.k)) === null || _d === undefined ? undefined : _d.attr('height', Math.abs(this.draggingFrom[1] - pointerCoords[1]) * this.zoomTransform.k);
8339
8599
  this.dragging = true;
8340
8600
  }
8341
8601
  }
@@ -8714,6 +8974,9 @@ class Grid {
8714
8974
  * @public
8715
8975
  */
8716
8976
  class AdjacencyLayout {
8977
+ constructor(gapSize) {
8978
+ this.gapSize = gapSize;
8979
+ }
8717
8980
  apply(model) {
8718
8981
  var _a;
8719
8982
  if (model.nodes.length === 0) {
@@ -8729,7 +8992,7 @@ class AdjacencyLayout {
8729
8992
  // place nodes according to arrangement
8730
8993
  const maximumWidth = Math.max(...model.nodes.map(n => n.width));
8731
8994
  const maximumHeight = Math.max(...model.nodes.map(n => n.height));
8732
- const gapSize = (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
8995
+ const gapSize = this.gapSize !== undefined ? this.gapSize : (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
8733
8996
  for (let y = nodeArrangement.minY(); y <= nodeArrangement.maxY(); ++y) {
8734
8997
  for (let x = nodeArrangement.minX(); x <= nodeArrangement.maxX(); ++x) {
8735
8998
  const node = nodeArrangement.get([x, y]);
@@ -8757,6 +9020,9 @@ const arrangeNode = (node, nodeArrangement, coords, nodesToBeArranged) => {
8757
9020
  * @public
8758
9021
  */
8759
9022
  class BreadthAdjacencyLayout {
9023
+ constructor(gapSize) {
9024
+ this.gapSize = gapSize;
9025
+ }
8760
9026
  apply(model) {
8761
9027
  var _a;
8762
9028
  if (model.nodes.length === 0) {
@@ -8794,7 +9060,7 @@ class BreadthAdjacencyLayout {
8794
9060
  // place nodes according to arrangement
8795
9061
  const maximumWidth = Math.max(...model.nodes.map(n => n.width));
8796
9062
  const maximumHeight = Math.max(...model.nodes.map(n => n.height));
8797
- const gapSize = (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9063
+ const gapSize = this.gapSize !== undefined ? this.gapSize : (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
8798
9064
  for (let y = nodeArrangement.minY(); y <= nodeArrangement.maxY(); ++y) {
8799
9065
  for (let x = nodeArrangement.minX(); x <= nodeArrangement.maxX(); ++x) {
8800
9066
  const node = nodeArrangement.get([x, y]);
@@ -8812,13 +9078,16 @@ class BreadthAdjacencyLayout {
8812
9078
  * @public
8813
9079
  */
8814
9080
  class BreadthLayout {
9081
+ constructor(gapSize) {
9082
+ this.gapSize = gapSize;
9083
+ }
8815
9084
  apply(model) {
8816
9085
  var _a;
8817
9086
  if (model.nodes.length === 0) {
8818
9087
  // nothing to arrange...
8819
9088
  return model;
8820
9089
  }
8821
- const gapSize = (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9090
+ const gapSize = this.gapSize !== undefined ? this.gapSize : (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
8822
9091
  let nodesToBeArranged = model.nodes.filter(n => !n.parent);
8823
9092
  // Arrange nodes by a breadth first search
8824
9093
  const firstNode = nodesToBeArranged[0];
@@ -8874,6 +9143,9 @@ class BreadthLayout {
8874
9143
  * @public
8875
9144
  */
8876
9145
  class ForceLayout {
9146
+ constructor(gapSize) {
9147
+ this.gapSize = gapSize;
9148
+ }
8877
9149
  apply(model) {
8878
9150
  var _a;
8879
9151
  if (model.nodes.length === 0) {
@@ -8882,7 +9154,7 @@ class ForceLayout {
8882
9154
  }
8883
9155
  // as a starting point, we apply a simple layout
8884
9156
  new BreadthLayout().apply(model);
8885
- const gapSize = (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9157
+ const gapSize = this.gapSize !== undefined ? this.gapSize : (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
8886
9158
  const coolingFactor = 0.99;
8887
9159
  const minimumTemperature = 1;
8888
9160
  const attractionFactor = 0.1;
@@ -8969,13 +9241,16 @@ class ForceLayout {
8969
9241
  * @public
8970
9242
  */
8971
9243
  class HorizontalLayout {
9244
+ constructor(gapSize) {
9245
+ this.gapSize = gapSize;
9246
+ }
8972
9247
  apply(model) {
8973
9248
  var _a;
8974
9249
  if (model.nodes.length === 0) {
8975
9250
  // nothing to arrange...
8976
9251
  return model;
8977
9252
  }
8978
- const gapSize = (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9253
+ const gapSize = this.gapSize !== undefined ? this.gapSize : (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
8979
9254
  const nodesToBeArranged = model.nodes.filter(n => !n.parent);
8980
9255
  nodesToBeArranged.sort((a, b) => b.type.priority - a.type.priority);
8981
9256
  let widthAccumulator = 0;
@@ -8992,6 +9267,9 @@ class HorizontalLayout {
8992
9267
  * @public
8993
9268
  */
8994
9269
  class PriorityLayout {
9270
+ constructor(gapSize) {
9271
+ this.gapSize = gapSize;
9272
+ }
8995
9273
  apply(model) {
8996
9274
  var _a;
8997
9275
  if (model.nodes.length === 0) {
@@ -9005,7 +9283,7 @@ class PriorityLayout {
9005
9283
  new BreadthLayout().apply(model);
9006
9284
  return model;
9007
9285
  }
9008
- const gapSize = (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9286
+ const gapSize = this.gapSize !== undefined ? this.gapSize : (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9009
9287
  const nodesToBeArranged = model.nodes.filter(n => !n.parent);
9010
9288
  const nodeArrangement = [];
9011
9289
  const nodesWithMaximumPriorityToBeArranged = model.nodes.filter(n => !n.parent).filter(n => n.getPriority() >= maximumPriority);
@@ -9099,6 +9377,9 @@ class PriorityLayout {
9099
9377
  * @public
9100
9378
  */
9101
9379
  class TreeLayout {
9380
+ constructor(gapSize) {
9381
+ this.gapSize = gapSize;
9382
+ }
9102
9383
  apply(model) {
9103
9384
  var _a;
9104
9385
  if (model.nodes.length === 0) {
@@ -9112,7 +9393,7 @@ class TreeLayout {
9112
9393
  new BreadthLayout().apply(model);
9113
9394
  return model;
9114
9395
  }
9115
- const gapSize = (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9396
+ const gapSize = this.gapSize !== undefined ? this.gapSize : (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9116
9397
  const nodesToBeArranged = model.nodes.filter(n => !n.parent).sort((n1, n2) => n2.getPriority() - n1.getPriority());
9117
9398
  const branches = [];
9118
9399
  while (nodesToBeArranged.length > 0) {
@@ -9197,13 +9478,16 @@ class Branch {
9197
9478
  * @public
9198
9479
  */
9199
9480
  class VerticalLayout {
9481
+ constructor(gapSize) {
9482
+ this.gapSize = gapSize;
9483
+ }
9200
9484
  apply(model) {
9201
9485
  var _a;
9202
9486
  if (model.nodes.length === 0) {
9203
9487
  // nothing to arrange...
9204
9488
  return model;
9205
9489
  }
9206
- const gapSize = (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9490
+ const gapSize = this.gapSize !== undefined ? this.gapSize : (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9207
9491
  const nodesToBeArranged = model.nodes.filter(n => !n.parent);
9208
9492
  nodesToBeArranged.sort((a, b) => b.type.priority - a.type.priority);
9209
9493
  let heightAccumulator = 0;