@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.esm.js CHANGED
@@ -1146,24 +1146,6 @@ class DiagramElementSet extends DiagramEntitySet {
1146
1146
  }
1147
1147
  }
1148
1148
 
1149
- /**
1150
- * Returns whether the incoming timestamp wins over the existing timestamp.
1151
- *
1152
- * In the DiagramModel, timestamps that have never been set are left null;
1153
- * `timestampWins` treats that as an "initial timestamp" that loses to all LogicalTimestamps.
1154
- */
1155
- function timestampWins(incoming, existing) {
1156
- if (!existing) return true;
1157
- if (incoming[0] > existing[0]) return true;
1158
- if (incoming[0] === existing[0]) {
1159
- // In case of equality, declare the incoming timestamp the "winner".
1160
- // This occurs if a client reuses a timestamp for multiple actions in a row,
1161
- // in which case the last created should win.
1162
- return incoming[1] >= existing[1];
1163
- }
1164
- return false;
1165
- }
1166
-
1167
1149
  /**
1168
1150
  * A property which is part of a property set and defines what values a value in a value set can take.
1169
1151
  * @public
@@ -1280,6 +1262,121 @@ class PropertySet {
1280
1262
  return this.propertyList.length > 0;
1281
1263
  }
1282
1264
  }
1265
+
1266
+ /**
1267
+ * Returns whether the incoming timestamp wins over the existing timestamp.
1268
+ *
1269
+ * In the DiagramModel, timestamps that have never been set are left null;
1270
+ * `timestampWins` treats that as an "initial timestamp" that loses to all LogicalTimestamps.
1271
+ */
1272
+ function timestampWins(incoming, existing) {
1273
+ if (!existing) return true;
1274
+ if (incoming[0] > existing[0]) return true;
1275
+ if (incoming[0] === existing[0]) {
1276
+ // In case of equality, declare the incoming timestamp the "winner".
1277
+ // This occurs if a client reuses a timestamp for multiple actions in a row,
1278
+ // in which case the last created should win.
1279
+ return incoming[1] >= existing[1];
1280
+ }
1281
+ return false;
1282
+ }
1283
+
1284
+ /**
1285
+ * Checks if the given value is not empty.
1286
+ * @private
1287
+ * @param a A value.
1288
+ * @returns `true` if the given value is not `undefined`, `null`, `''`, `[]` or `{}`; `false` otherwise.
1289
+ */
1290
+ const empty = a => {
1291
+ return a === undefined || a === null || a === '' || a instanceof Array && a.length === 0 || a instanceof Object && Object.keys(a).length === 0;
1292
+ };
1293
+ /**
1294
+ * Checks whether the given values are equal.
1295
+ * @public
1296
+ * @param a A value.
1297
+ * @param b A value.
1298
+ * @returns `true` if the given values are equal, `false` otherwise.
1299
+ */
1300
+ const equals = (a, b) => {
1301
+ return a === b || JSON.stringify(a) === JSON.stringify(b);
1302
+ };
1303
+ /**
1304
+ * Calculates the differences between the two given objects and returns two objects containing the differences in each relative to the other.
1305
+ *
1306
+ * 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.
1307
+ *
1308
+ * This function is recursive, that is, if the value under the key is an object, the function will be applied to that value recursively.
1309
+ *
1310
+ * @public
1311
+ * @param a An object.
1312
+ * @param b An object.
1313
+ * @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.
1314
+ */
1315
+ const diff = (a, b) => {
1316
+ const aDiff = {};
1317
+ const bDiff = {};
1318
+ const allKeys = [];
1319
+ for (const key in a) {
1320
+ allKeys.push(key);
1321
+ }
1322
+ for (const key in b) {
1323
+ if (!(key in a)) {
1324
+ allKeys.push(key);
1325
+ }
1326
+ }
1327
+ for (const key of allKeys) {
1328
+ if (isObject(a[key]) && isObject(b[key])) {
1329
+ const diffAB = diff(a[key], b[key]);
1330
+ // only add the key if differences are detected
1331
+ if (Object.keys(diffAB[0]).length > 0 && Object.keys(diffAB[1]).length > 0) {
1332
+ aDiff[key] = diffAB[0];
1333
+ bDiff[key] = diffAB[1];
1334
+ }
1335
+ } else {
1336
+ if (!equals(a[key], b[key])) {
1337
+ aDiff[key] = a[key];
1338
+ bDiff[key] = b[key];
1339
+ }
1340
+ }
1341
+ }
1342
+ return [aDiff, bDiff];
1343
+ };
1344
+ /**
1345
+ * Calculates the differences between the two given values of a valueset and returns two objects containing the differences in each relative to the other.
1346
+ *
1347
+ * @param a An object.
1348
+ * @param b An object.
1349
+ * @param valueSet A ValueSet to use as reference for the keys and types of each property.
1350
+ * @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.
1351
+ */
1352
+ const diffProperties = (a, b, valueSet) => {
1353
+ const aDiff = {};
1354
+ const bDiff = {};
1355
+ for (const key in valueSet.propertySet.propertyMap) {
1356
+ if (valueSet.propertySet.propertyMap[key].type === Type.Object) {
1357
+ const diffAB = diffProperties(a[key], b[key], valueSet.getSubValueSet(key));
1358
+ // only add the key if differences are detected
1359
+ if (Object.keys(diffAB[0]).length > 0 && Object.keys(diffAB[1]).length > 0) {
1360
+ aDiff[key] = diffAB[0];
1361
+ bDiff[key] = diffAB[1];
1362
+ }
1363
+ } else {
1364
+ if (!equals(a[key], b[key])) {
1365
+ aDiff[key] = a[key];
1366
+ bDiff[key] = b[key];
1367
+ }
1368
+ }
1369
+ }
1370
+ return [aDiff, bDiff];
1371
+ };
1372
+ /**
1373
+ * Checks if the given value is an object.
1374
+ * @public
1375
+ * @param x A value.
1376
+ * @returns `true` if the given value is an object, `false` otherwise.
1377
+ */
1378
+ const isObject = x => x !== undefined && x !== null && x.constructor === Object;
1379
+
1283
1380
  /**
1284
1381
  * A set of values corresponding to a set of properties.
1285
1382
  * @public
@@ -1573,10 +1670,8 @@ class ValueSet {
1573
1670
  this.values[key] = structuredClone(property.defaultValue);
1574
1671
  }
1575
1672
  if (rootAttribute !== undefined && rootAttribute !== null) {
1576
- if (property.defaultValue !== undefined && !equals(this.values[key], property.defaultValue)) {
1673
+ if (property.defaultValue !== undefined && !equals(this.getRootElementValue(rootAttribute), property.defaultValue)) {
1577
1674
  this.setRootElementValue(rootAttribute, this.values[key]);
1578
- } else {
1579
- this.values[key] = this.getRootElementValue(rootAttribute);
1580
1675
  }
1581
1676
  }
1582
1677
  if (property.basic) {
@@ -1631,101 +1726,6 @@ class ValueSet {
1631
1726
  }
1632
1727
  }
1633
1728
  }
1634
- /**
1635
- * Checks if the given value is not empty.
1636
- * @private
1637
- * @param a A value.
1638
- * @returns `true` if the given value is not `undefined`, `null`, `''`, `[]` or `{}`; `false` otherwise.
1639
- */
1640
- const empty = a => {
1641
- return a === undefined || a === null || a === '' || a instanceof Array && a.length === 0 || a instanceof Object && Object.keys(a).length === 0;
1642
- };
1643
- /**
1644
- * Checks whether the given values are equal.
1645
- * @public
1646
- * @param a A value.
1647
- * @param b A value.
1648
- * @returns `true` if the given values are equal, `false` otherwise.
1649
- */
1650
- const equals = (a, b) => {
1651
- return a === b || JSON.stringify(a) === JSON.stringify(b);
1652
- };
1653
- /**
1654
- * Calculates the differences between the two given objects and returns two objects containing the differences in each relative to the other.
1655
- *
1656
- * 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.
1657
- *
1658
- * This function is recursive, that is, if the value under the key is an object, the function will be applied to that value recursively.
1659
- *
1660
- * @public
1661
- * @param a An object.
1662
- * @param b An object.
1663
- * @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.
1664
- */
1665
- const diff = (a, b) => {
1666
- const aDiff = {};
1667
- const bDiff = {};
1668
- const allKeys = [];
1669
- for (const key in a) {
1670
- allKeys.push(key);
1671
- }
1672
- for (const key in b) {
1673
- if (!(key in a)) {
1674
- allKeys.push(key);
1675
- }
1676
- }
1677
- for (const key of allKeys) {
1678
- if (isObject(a[key]) && isObject(b[key])) {
1679
- const diffAB = diff(a[key], b[key]);
1680
- // only add the key if differences are detected
1681
- if (Object.keys(diffAB[0]).length > 0 && Object.keys(diffAB[1]).length > 0) {
1682
- aDiff[key] = diffAB[0];
1683
- bDiff[key] = diffAB[1];
1684
- }
1685
- } else {
1686
- if (!equals(a[key], b[key])) {
1687
- aDiff[key] = a[key];
1688
- bDiff[key] = b[key];
1689
- }
1690
- }
1691
- }
1692
- return [aDiff, bDiff];
1693
- };
1694
- /**
1695
- * Calculates the differences between the two given values of a valueset and returns two objects containing the differences in each relative to the other.
1696
- *
1697
- * @param a An object.
1698
- * @param b An object.
1699
- * @param valueSet A ValueSet to use as reference for the keys and types of each property.
1700
- * @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.
1701
- */
1702
- const diffProperties = (a, b, valueSet) => {
1703
- const aDiff = {};
1704
- const bDiff = {};
1705
- for (const key in valueSet.propertySet.propertyMap) {
1706
- if (valueSet.propertySet.propertyMap[key].type === Type.Object) {
1707
- const diffAB = diffProperties(a[key], b[key], valueSet.getSubValueSet(key));
1708
- // only add the key if differences are detected
1709
- if (Object.keys(diffAB[0]).length > 0 && Object.keys(diffAB[1]).length > 0) {
1710
- aDiff[key] = diffAB[0];
1711
- bDiff[key] = diffAB[1];
1712
- }
1713
- } else {
1714
- if (!equals(a[key], b[key])) {
1715
- aDiff[key] = a[key];
1716
- bDiff[key] = b[key];
1717
- }
1718
- }
1719
- }
1720
- return [aDiff, bDiff];
1721
- };
1722
- /**
1723
- * Checks if the given value is an object.
1724
- * @public
1725
- * @param x A value.
1726
- * @returns `true` if the given value is an object, `false` otherwise.
1727
- */
1728
- const isObject = x => x !== undefined && x !== null && x.constructor === Object;
1729
1729
 
1730
1730
  /**
1731
1731
  * Default values of the parameters of a diagram connection.
@@ -2962,6 +2962,7 @@ const DIAGRAM_NODE_TYPE_DEFAULTS = {
2962
2962
  padding: 0,
2963
2963
  label: null,
2964
2964
  ports: [],
2965
+ decorators: [],
2965
2966
  sectionGrid: null,
2966
2967
  look: DIAGRAM_NODE_LOOK_DEFAULTS,
2967
2968
  isUnique: false,
@@ -2992,6 +2993,7 @@ class DiagramNodeType {
2992
2993
  this.topPadding = getTopPadding(values);
2993
2994
  this.label = values.label;
2994
2995
  this.ports = values.ports;
2996
+ this.decorators = values.decorators;
2995
2997
  this.sectionGrid = values.sectionGrid ? new DiagramSectionGrid(values.sectionGrid) : null;
2996
2998
  const looks = extractLooksFromConfig(values.look);
2997
2999
  this.defaultLook = looks.defaultLook;
@@ -3135,15 +3137,15 @@ class DiagramNode extends DiagramElement {
3135
3137
  raise() {
3136
3138
  var _a;
3137
3139
  (_a = this.select()) === null || _a === undefined ? undefined : _a.raise();
3140
+ for (const section of this.sections) {
3141
+ section.raise();
3142
+ }
3138
3143
  if (this.label) {
3139
3144
  this.label.raise();
3140
3145
  }
3141
3146
  for (const port of this.ports) {
3142
3147
  port.raise();
3143
3148
  }
3144
- for (const section of this.sections) {
3145
- section.raise();
3146
- }
3147
3149
  for (const decorator of this.decorators) {
3148
3150
  decorator.raise();
3149
3151
  }
@@ -3577,6 +3579,106 @@ class DiagramNode extends DiagramElement {
3577
3579
  this.getConnections().forEach(c => c.tighten());
3578
3580
  this.updateInView();
3579
3581
  }
3582
+ /**
3583
+ * Removes all sections with the given index along the x axis.
3584
+ * @public
3585
+ */
3586
+ removeSectionColumn(columnIndex) {
3587
+ var _a;
3588
+ const margin = ((_a = this.type.sectionGrid) === null || _a === undefined ? undefined : _a.margin) || 0;
3589
+ let columnWidth = 0;
3590
+ const sections = [...this.sections];
3591
+ for (const section of sections) {
3592
+ if (section.indexYInNode === columnIndex) {
3593
+ columnWidth = Math.max(columnWidth, section.width);
3594
+ this.model.sections.remove(section.id);
3595
+ }
3596
+ }
3597
+ for (const section of sections) {
3598
+ if (section.indexYInNode > columnIndex) {
3599
+ --section.indexYInNode;
3600
+ section.move([section.coords[0] - columnWidth - margin, section.coords[1]]);
3601
+ }
3602
+ }
3603
+ this.stretch(Side.Right, -margin - columnWidth);
3604
+ }
3605
+ /**
3606
+ * Removes all sections with the given index along the y axis.
3607
+ * @public
3608
+ */
3609
+ removeSectionRow(rowIndex) {
3610
+ var _a;
3611
+ const margin = ((_a = this.type.sectionGrid) === null || _a === undefined ? undefined : _a.margin) || 0;
3612
+ let rowHeight = 0;
3613
+ const sections = [...this.sections];
3614
+ for (const section of sections) {
3615
+ if (section.indexXInNode === rowIndex) {
3616
+ rowHeight = Math.max(rowHeight, section.height);
3617
+ this.model.sections.remove(section.id);
3618
+ }
3619
+ }
3620
+ for (const section of sections) {
3621
+ if (section.indexYInNode > rowIndex) {
3622
+ --section.indexXInNode;
3623
+ section.move([section.coords[0], section.coords[1] - rowHeight - margin]);
3624
+ }
3625
+ }
3626
+ this.stretch(Side.Bottom, -margin - rowHeight);
3627
+ }
3628
+ /**
3629
+ * Creates a copy of all sections with the given index along the x axis.
3630
+ * @public
3631
+ */
3632
+ copySectionColumn(columnIndex) {
3633
+ var _a;
3634
+ const margin = ((_a = this.type.sectionGrid) === null || _a === undefined ? undefined : _a.margin) || 0;
3635
+ let columnWidth = 0;
3636
+ const sections = [...this.sections];
3637
+ for (const section of sections) {
3638
+ if (section.indexXInNode === columnIndex) {
3639
+ columnWidth = Math.max(columnWidth, section.width);
3640
+ let newSectionIdIndexX = section.indexXInNode + 1;
3641
+ while (this.model.sections.get(`${section.id}_copy_${newSectionIdIndexX}_${section.indexYInNode}`, true) !== undefined) {
3642
+ ++newSectionIdIndexX;
3643
+ }
3644
+ 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}`);
3645
+ }
3646
+ }
3647
+ for (const section of sections) {
3648
+ if (section.indexXInNode > columnIndex) {
3649
+ ++section.indexXInNode;
3650
+ section.move([section.coords[0] + columnWidth + margin, section.coords[1]]);
3651
+ }
3652
+ }
3653
+ this.stretch(Side.Right, margin + columnWidth);
3654
+ }
3655
+ /**
3656
+ * Creates a copy of all sections with the given index along the y axis.
3657
+ * @public
3658
+ */
3659
+ copySectionRow(rowIndex) {
3660
+ var _a;
3661
+ const margin = ((_a = this.type.sectionGrid) === null || _a === undefined ? undefined : _a.margin) || 0;
3662
+ let rowHeight = 0;
3663
+ const sections = [...this.sections];
3664
+ for (const section of sections) {
3665
+ if (section.indexYInNode === rowIndex) {
3666
+ rowHeight = Math.max(rowHeight, section.height);
3667
+ let newSectionIdIndexY = section.indexYInNode + 1;
3668
+ while (this.model.sections.get(`${section.id}_copy_${section.indexXInNode}_${newSectionIdIndexY}`, true) !== undefined) {
3669
+ ++newSectionIdIndexY;
3670
+ }
3671
+ 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}`);
3672
+ }
3673
+ }
3674
+ for (const section of sections) {
3675
+ if (section.indexYInNode > rowIndex) {
3676
+ ++section.indexYInNode;
3677
+ section.move([section.coords[0], section.coords[1] + rowHeight + margin]);
3678
+ }
3679
+ }
3680
+ this.stretch(Side.Bottom, margin + rowHeight);
3681
+ }
3580
3682
  }
3581
3683
  class DiagramNodeSet extends DiagramElementSet {
3582
3684
  /**
@@ -3633,7 +3735,7 @@ class DiagramNodeSet extends DiagramElementSet {
3633
3735
  for (let i = 0; i < nodeType.ports.length; ++i) {
3634
3736
  const portConfig = nodeType.ports[i];
3635
3737
  const portType = portConfig.type !== undefined ? this.model.ports.types.get(portConfig.type) : undefined;
3636
- 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}`);
3738
+ 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}`);
3637
3739
  if ((_e = port.type) === null || _e === undefined ? undefined : _e.label) {
3638
3740
  const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), (_f = port.type) === null || _f === undefined ? undefined : _f.label);
3639
3741
  const labelWidth = 6 * labelConfiguration.fontSize + getLeftPadding$1(labelConfiguration) + getRightPadding$1(labelConfiguration);
@@ -3660,6 +3762,13 @@ class DiagramNodeSet extends DiagramElementSet {
3660
3762
  const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), nodeType.label);
3661
3763
  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);
3662
3764
  }
3765
+ // add node decorators
3766
+ if (nodeType.decorators.length > 0) {
3767
+ for (let i = 0; i < nodeType.decorators.length; ++i) {
3768
+ const decoratorConfig = nodeType.decorators[i];
3769
+ 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}`);
3770
+ }
3771
+ }
3663
3772
  node.valueSet.resetValues();
3664
3773
  (_g = node.model.canvas) === null || _g === undefined ? undefined : _g.fitNodeInView(node.id);
3665
3774
  return node;
@@ -4188,6 +4297,13 @@ class DagaImporter {
4188
4297
  newNode.width = node.width;
4189
4298
  newNode.height = node.height;
4190
4299
  if (node.label) {
4300
+ // add node decorators
4301
+ if (newNodeType.decorators) {
4302
+ for (let i = 0; i < newNodeType.decorators.length; ++i) {
4303
+ const decoratorConfig = newNodeType.decorators[i];
4304
+ 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}`);
4305
+ }
4306
+ }
4191
4307
  // add node label
4192
4308
  if (newNodeType.label) {
4193
4309
  const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), newNodeType.label);
@@ -4400,6 +4516,54 @@ class AddNodeCollabAction {
4400
4516
  return new AddNodeCollabAction(canvas, serialized.id, serialized.typeId, serialized.coords, serialized.parentId, serialized.label, serialized.values);
4401
4517
  }
4402
4518
  }
4519
+ /**
4520
+ * Collaborative action which consists of adding or removing sections in a node.
4521
+ * @private
4522
+ * @see AddNodeAction
4523
+ */
4524
+ class AddSectionCollabAction {
4525
+ constructor(canvas, nodeId, copyColumnIndex, copyRowIndex, removeColumnIndex, removeRowIndex, timestamp) {
4526
+ this.canvas = canvas;
4527
+ this.nodeId = nodeId;
4528
+ this.copyColumnIndex = copyColumnIndex;
4529
+ this.copyRowIndex = copyRowIndex;
4530
+ this.removeColumnIndex = removeColumnIndex;
4531
+ this.removeRowIndex = removeRowIndex;
4532
+ this.timestamp = timestamp;
4533
+ }
4534
+ do() {
4535
+ const node = this.canvas.model.nodes.get(this.nodeId);
4536
+ if (node && timestampWins(this.timestamp, node.geometryTimestamp)) {
4537
+ if (this.copyColumnIndex !== undefined) {
4538
+ node.copySectionColumn(this.copyColumnIndex);
4539
+ }
4540
+ if (this.copyRowIndex !== undefined) {
4541
+ node.copySectionRow(this.copyRowIndex);
4542
+ }
4543
+ if (this.removeColumnIndex !== undefined) {
4544
+ node.removeSectionColumn(this.removeColumnIndex);
4545
+ }
4546
+ if (this.removeRowIndex !== undefined) {
4547
+ node.removeSectionRow(this.removeRowIndex);
4548
+ }
4549
+ node.geometryTimestamp = this.timestamp;
4550
+ }
4551
+ }
4552
+ serialize() {
4553
+ return {
4554
+ type: 'addSection',
4555
+ nodeId: this.nodeId,
4556
+ copyColumnIndex: this.copyColumnIndex,
4557
+ copyRowIndex: this.copyRowIndex,
4558
+ removeColumnIndex: this.removeColumnIndex,
4559
+ removeRowIndex: this.removeRowIndex,
4560
+ timestamp: this.timestamp
4561
+ };
4562
+ }
4563
+ static deserialize(canvas, serialized) {
4564
+ return new AddSectionCollabAction(canvas, serialized.nodeId, serialized.copyColumnIndex, serialized.copyRowIndex, serialized.removeColumnIndex, serialized.removeRowIndex, serialized.timestamp);
4565
+ }
4566
+ }
4403
4567
  /**
4404
4568
  * Collaborative which consists of applying a layout to the diagram which can change the location of several nodes.
4405
4569
  * @private
@@ -4816,6 +4980,12 @@ class CollabEngine {
4816
4980
  action.do();
4817
4981
  break;
4818
4982
  }
4983
+ case 'addSection':
4984
+ {
4985
+ const action = AddSectionCollabAction.deserialize(this.canvas, message);
4986
+ action.do();
4987
+ break;
4988
+ }
4819
4989
  case 'applyLayout':
4820
4990
  {
4821
4991
  const action = ApplyLayoutCollabAction.deserialize(this.canvas, message);
@@ -4978,6 +5148,12 @@ var DiagramActions;
4978
5148
  * @see AddNodeAction
4979
5149
  */
4980
5150
  DiagramActions["AddNode"] = "add-node";
5151
+ /**
5152
+ * Action that corresponds to the addition or removal of sections in a node.
5153
+ * @public
5154
+ * @see AddSectionAction
5155
+ */
5156
+ DiagramActions["AddSectionAction"] = "add-section";
4981
5157
  /**
4982
5158
  * Action that corresponds to applying a layout which changes the location of several nodes.
4983
5159
  * @public
@@ -5909,6 +6085,32 @@ const updateLook = selection => {
5909
6085
  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);
5910
6086
  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);
5911
6087
  };
6088
+ const GRID_DEFAULTS = {
6089
+ enabled: true,
6090
+ style: 'dots',
6091
+ color: 'rgba(0, 0, 0, 0.1)',
6092
+ snap: false,
6093
+ spacing: 10,
6094
+ thickness: 0.05
6095
+ };
6096
+ const initializeGrid = (canvas, canvasView, backgroundPatternId) => {
6097
+ const canvasDefs = canvasView.append('defs');
6098
+ if (canvas.gridSize > 0 && isFinite(canvas.gridSize)) {
6099
+ 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');
6100
+ canvasBackgroundPattern.append('rect').attr('x', 0).attr('y', 0).attr('width', canvas.gridSize).attr('height', canvas.gridSize).attr('fill', canvas.backgroundColor);
6101
+ switch (canvas.gridStyle) {
6102
+ case 'dots':
6103
+ canvasBackgroundPattern.append('circle').attr('cx', canvas.gridSize / 2).attr('cy', canvas.gridSize / 2).attr('r', canvas.gridSize * canvas.gridThickness).attr('fill', canvas.gridColor);
6104
+ break;
6105
+ case 'lines':
6106
+ 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);
6107
+ 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);
6108
+ 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);
6109
+ break;
6110
+ }
6111
+ canvasView.select('rect').attr('fill', `url(#${backgroundPatternId})`);
6112
+ }
6113
+ };
5912
6114
 
5913
6115
  const CONTEXT_MENU_MENU_RADIUS = 96;
5914
6116
  const CONTEXT_MENU_BUTTON_RADIUS = 32;
@@ -6078,7 +6280,7 @@ class DiagramUserHighlight extends DiagramElementSet {
6078
6280
  focusOn(element) {
6079
6281
  this.clear();
6080
6282
  this.focus = element;
6081
- if (element instanceof DiagramField && element.rootElement) {
6283
+ if ((element instanceof DiagramField || element instanceof DiagramDecorator) && element.rootElement) {
6082
6284
  this.focusOn(element.rootElement);
6083
6285
  } else {
6084
6286
  this.add(element);
@@ -6566,7 +6768,7 @@ class DiagramCanvas {
6566
6768
  * @param config The configuration object used to set the parameters of this canvas.
6567
6769
  */
6568
6770
  constructor(parentComponent, config) {
6569
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
6771
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
6570
6772
  this.backgroundPatternId = `daga-background-pattern-id-${DiagramCanvas.canvasCount++}`;
6571
6773
  this.zoomTransform = d3.zoomIdentity;
6572
6774
  // used to distinguish drags from clicks when dragging elements and during multiple selection
@@ -6585,15 +6787,16 @@ class DiagramCanvas {
6585
6787
  this.userHighlight = new DiagramUserHighlight(this);
6586
6788
  this.contextMenu = new DiagramContextMenu(this, (_a = config.canvas) === null || _a === undefined ? undefined : _a.contextMenu);
6587
6789
  this.backgroundColor = ((_b = config.canvas) === null || _b === undefined ? undefined : _b.backgroundColor) || '#FFFFFF';
6588
- 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);
6589
- this.gridThickness = Math.abs(((_j = (_h = config.canvas) === null || _h === undefined ? undefined : _h.grid) === null || _j === undefined ? undefined : _j.thickness) || 0.05);
6590
- this.gridColor = ((_l = (_k = config.canvas) === null || _k === undefined ? undefined : _k.grid) === null || _l === undefined ? undefined : _l.color) || 'rgba(0, 0, 0, 0.1)';
6591
- 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;
6592
- this.zoomFactor = ((_s = config.canvas) === null || _s === undefined ? undefined : _s.zoomFactor) || 2;
6593
- this.panRate = ((_t = config.canvas) === null || _t === undefined ? undefined : _t.panRate) || 100;
6790
+ 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;
6791
+ 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);
6792
+ this.gridThickness = Math.abs(((_m = (_l = config.canvas) === null || _l === undefined ? undefined : _l.grid) === null || _m === undefined ? undefined : _m.thickness) || GRID_DEFAULTS.thickness);
6793
+ this.gridColor = ((_p = (_o = config.canvas) === null || _o === undefined ? undefined : _o.grid) === null || _p === undefined ? undefined : _p.color) || GRID_DEFAULTS.color;
6794
+ 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;
6795
+ this.zoomFactor = ((_v = config.canvas) === null || _v === undefined ? undefined : _v.zoomFactor) || 2;
6796
+ this.panRate = ((_w = config.canvas) === null || _w === undefined ? undefined : _w.panRate) || 100;
6594
6797
  this.inferConnectionType = config.inferConnectionType || false;
6595
6798
  this.multipleSelectionOn = false;
6596
- this.priorityThresholds = ((_u = config.canvas) === null || _u === undefined ? undefined : _u.priorityThresholds) || [];
6799
+ this.priorityThresholds = ((_x = config.canvas) === null || _x === undefined ? undefined : _x.priorityThresholds) || [];
6597
6800
  this.priorityThreshold = this.priorityThresholds ? this.priorityThresholds[0] : undefined;
6598
6801
  this.layoutFormat = config.layoutFormat;
6599
6802
  this.userActions = config.userActions || {};
@@ -6720,23 +6923,29 @@ class DiagramCanvas {
6720
6923
  }
6721
6924
  }
6722
6925
  if (event.ctrlKey && event.key === 'c') {
6723
- event.preventDefault();
6724
- // copy
6725
- this.userSelection.copyToClipboard();
6726
- this.cancelAllUserActions();
6926
+ if (this.canUserPerformAction(DiagramActions.Clipboard)) {
6927
+ event.preventDefault();
6928
+ // copy
6929
+ this.userSelection.copyToClipboard();
6930
+ this.cancelAllUserActions();
6931
+ }
6727
6932
  }
6728
6933
  if (event.ctrlKey && event.key === 'x') {
6729
- event.preventDefault();
6730
- // cut
6731
- this.userSelection.cutToClipboard();
6732
- this.cancelAllUserActions();
6934
+ if (this.canUserPerformAction(DiagramActions.Clipboard) && this.canUserPerformAction(DiagramActions.Remove)) {
6935
+ event.preventDefault();
6936
+ // cut
6937
+ this.userSelection.cutToClipboard();
6938
+ this.cancelAllUserActions();
6939
+ }
6733
6940
  }
6734
6941
  if (event.ctrlKey && event.key === 'v') {
6735
- event.preventDefault();
6736
- // paste
6737
- const coordinateRange = this.getCoordinatesOnScreen();
6738
- this.userSelection.pasteFromClipboard(this.getClosestGridPoint([(coordinateRange[0][0] + coordinateRange[1][0]) / 2, (coordinateRange[0][1] + coordinateRange[1][1]) / 2]));
6739
- this.cancelAllUserActions();
6942
+ if (this.canUserPerformAction(DiagramActions.Paste)) {
6943
+ event.preventDefault();
6944
+ // paste
6945
+ const coordinateRange = this.getCoordinatesOnScreen();
6946
+ this.userSelection.pasteFromClipboard(this.getClosestGridPoint([(coordinateRange[0][0] + coordinateRange[1][0]) / 2, (coordinateRange[0][1] + coordinateRange[1][1]) / 2]));
6947
+ this.cancelAllUserActions();
6948
+ }
6740
6949
  }
6741
6950
  if (event.ctrlKey && event.key === 'y') {
6742
6951
  event.preventDefault();
@@ -6749,38 +6958,50 @@ class DiagramCanvas {
6749
6958
  this.actionStack.undo();
6750
6959
  }
6751
6960
  if (event.key === '+') {
6752
- event.preventDefault();
6753
- // zoom in
6754
- this.zoomBy(this.zoomFactor);
6961
+ if (this.canUserPerformAction(DiagramActions.Zoom)) {
6962
+ event.preventDefault();
6963
+ // zoom in
6964
+ this.zoomBy(this.zoomFactor);
6965
+ }
6755
6966
  }
6756
6967
  if (event.key === '-') {
6757
- event.preventDefault();
6758
- // zoom out
6759
- this.zoomBy(1 / this.zoomFactor);
6968
+ if (this.canUserPerformAction(DiagramActions.Zoom)) {
6969
+ event.preventDefault();
6970
+ // zoom out
6971
+ this.zoomBy(1 / this.zoomFactor);
6972
+ }
6760
6973
  }
6761
6974
  if (event.key === Keys.ArrowLeft) {
6762
- event.preventDefault();
6763
- // move left, faster if we're zoomed out and slower if we're zoomed in
6764
- this.translateBy(this.panRate / this.zoomTransform.k, 0);
6975
+ if (this.canUserPerformAction(DiagramActions.Zoom)) {
6976
+ event.preventDefault();
6977
+ // move left, faster if we're zoomed out and slower if we're zoomed in
6978
+ this.translateBy(this.panRate / this.zoomTransform.k, 0);
6979
+ }
6765
6980
  }
6766
6981
  if (event.key === Keys.ArrowRight) {
6767
- event.preventDefault();
6768
- // move right, faster if we're zoomed out and slower if we're zoomed in
6769
- this.translateBy(-this.panRate / this.zoomTransform.k, 0);
6982
+ if (this.canUserPerformAction(DiagramActions.Zoom)) {
6983
+ event.preventDefault();
6984
+ // move right, faster if we're zoomed out and slower if we're zoomed in
6985
+ this.translateBy(-this.panRate / this.zoomTransform.k, 0);
6986
+ }
6770
6987
  }
6771
6988
  if (event.key === Keys.ArrowDown) {
6772
- event.preventDefault();
6773
- // move down, faster if we're zoomed out and slower if we're zoomed in
6774
- this.translateBy(0, -this.panRate / this.zoomTransform.k);
6989
+ if (this.canUserPerformAction(DiagramActions.Zoom)) {
6990
+ event.preventDefault();
6991
+ // move down, faster if we're zoomed out and slower if we're zoomed in
6992
+ this.translateBy(0, -this.panRate / this.zoomTransform.k);
6993
+ }
6775
6994
  }
6776
6995
  if (event.key === Keys.ArrowUp) {
6777
- event.preventDefault();
6778
- // move up, faster if we're zoomed out and slower if we're zoomed in
6779
- this.translateBy(0, this.panRate / this.zoomTransform.k);
6996
+ if (this.canUserPerformAction(DiagramActions.Zoom)) {
6997
+ event.preventDefault();
6998
+ // move up, faster if we're zoomed out and slower if we're zoomed in
6999
+ this.translateBy(0, this.panRate / this.zoomTransform.k);
7000
+ }
6780
7001
  }
6781
7002
  });
6782
7003
  const canvasView = this.selectSVGElement().append('g').attr('class', 'daga-canvas-view').attr('width', `100%`).attr('height', `100%`);
6783
- 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(Events.MouseMove, event => {
7004
+ canvasView.append('rect').attr('x', 0).attr('y', 0).attr('width', `100%`).attr('height', `100%`).attr('fill', this.backgroundColor).attr('stroke-width', '0').on(Events.MouseMove, event => {
6784
7005
  if (this.unfinishedConnection !== undefined) {
6785
7006
  const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
6786
7007
  this.unfinishedConnection.endCoords = pointerCoords;
@@ -6836,13 +7057,7 @@ class DiagramCanvas {
6836
7057
  }).on(ZoomEvents.End, () => {
6837
7058
  setCursorStyle();
6838
7059
  }));
6839
- const canvasDefs = canvasView.append('defs');
6840
- if (this.gridSize > 0 && isFinite(this.gridSize)) {
6841
- 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');
6842
- canvasBackgroundPattern.append('rect').attr('x', 0).attr('y', 0).attr('width', this.gridSize).attr('height', this.gridSize).attr('fill', this.backgroundColor);
6843
- canvasBackgroundPattern.append('circle').attr('cx', this.gridSize / 2).attr('cy', this.gridSize / 2).attr('r', this.gridSize * this.gridThickness).attr('fill', this.gridColor);
6844
- canvasBackground.attr('fill', `url(#${this.backgroundPatternId})`);
6845
- }
7060
+ initializeGrid(this, canvasView, this.backgroundPatternId);
6846
7061
  canvasView.append('g').attr('class', 'daga-canvas-elements');
6847
7062
  }
6848
7063
  zoomBy(factor) {
@@ -7818,7 +8033,23 @@ class DiagramCanvas {
7818
8033
  const mergeSelection = enterSelection.merge(updateSelection);
7819
8034
  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);
7820
8035
  exitSelection.remove();
7821
- enterSelection.on(Events.ContextMenu, (event, d) => {
8036
+ enterSelection.on(Events.MouseOver, (_event, d) => {
8037
+ if (!this.dragging) {
8038
+ this.userHighlight.focusOn(d);
8039
+ this.diagramEvent$.next(new DiagramHighlightedEvent(d));
8040
+ }
8041
+ }).on(Events.Click, (event, d) => {
8042
+ if (!event.ctrlKey && !event.shiftKey) {
8043
+ const deselectedElements = this.userSelection.all();
8044
+ this.userSelection.clear();
8045
+ this.diagramEvent$.next(new DiagramSelectionEvent(deselectedElements, false));
8046
+ }
8047
+ if (d.rootElement) {
8048
+ const elementToBeToggled = getRelatedNodeOrItself(d.rootElement);
8049
+ this.userSelection.toggle(elementToBeToggled);
8050
+ this.diagramEvent$.next(new DiagramSelectionEvent([elementToBeToggled], elementToBeToggled.selected));
8051
+ }
8052
+ }).on(Events.ContextMenu, (event, d) => {
7822
8053
  if (this.dragging) {
7823
8054
  event.preventDefault();
7824
8055
  event.stopPropagation();
@@ -7828,8 +8059,15 @@ class DiagramCanvas {
7828
8059
  const diagramEvent = new DiagramSecondaryClickEvent(event, d);
7829
8060
  this.diagramEvent$.next(diagramEvent);
7830
8061
  if (!diagramEvent.defaultPrevented && this.canUserPerformAction(DiagramActions.ContextMenu)) {
7831
- event.preventDefault();
7832
- this.contextMenu.open(event);
8062
+ if (d.rootElement) {
8063
+ event.preventDefault();
8064
+ const elementToSelect = getRelatedNodeOrItself(d.rootElement);
8065
+ this.userHighlight.focusOn(elementToSelect);
8066
+ this.diagramEvent$.next(new DiagramHighlightedEvent(elementToSelect));
8067
+ this.userSelection.add(elementToSelect);
8068
+ this.diagramEvent$.next(new DiagramSelectionEvent([elementToSelect], true));
8069
+ this.contextMenu.open(event);
8070
+ }
7833
8071
  }
7834
8072
  }).on(Events.DoubleClick, (event, d) => {
7835
8073
  const diagramEvent = new DiagramDoubleClickEvent(event, d);
@@ -7890,7 +8128,7 @@ class DiagramCanvas {
7890
8128
  }
7891
8129
  updateConnectionLabelsInView(connection) {
7892
8130
  var _a, _b, _c;
7893
- const connectionSelection = this.selectCanvasView().select(`g.diagram-connection#${connection.id}`);
8131
+ const connectionSelection = this.selectCanvasView().select(`[id='${escapeSelector(connection.id)}']`);
7894
8132
  const pathSelection = connectionSelection.select('path');
7895
8133
  const pathNode = pathSelection.node();
7896
8134
  const labelConfiguration = Object.assign(Object.assign({}, DIAGRAM_FIELD_DEFAULTS), connection.type.label);
@@ -7932,7 +8170,7 @@ class DiagramCanvas {
7932
8170
  }
7933
8171
  }
7934
8172
  updateConnectionMarkersInView(connection) {
7935
- const connectionSelection = this.selectCanvasView().select(`g.diagram-connection#${connection.id}`);
8173
+ const connectionSelection = this.selectCanvasView().select(`[id='${escapeSelector(connection.id)}']`);
7936
8174
  const startMarkerSelection = connectionSelection.select('marker.diagram-connection-start-marker');
7937
8175
  const endMarkerSelection = connectionSelection.select('marker.diagram-connection-end-marker');
7938
8176
  if (connection.startMarkerLook !== null) {
@@ -7946,13 +8184,27 @@ class DiagramCanvas {
7946
8184
  endMarkerSelection.attr('orient', 'auto-start-reverse').attr('markerWidth', 0).attr('markerHeight', 0);
7947
8185
  }
7948
8186
  }
7949
- fitFieldRootInView(id) {
8187
+ fieldRootFitsInView(id) {
8188
+ var _a, _b, _c, _d;
8189
+ const field = this.model.fields.get(id);
8190
+ if (!field) {
8191
+ return false;
8192
+ }
8193
+ if (field.rootElement instanceof DiagramNode || field.rootElement instanceof DiagramSection) {
8194
+ const fieldDimensions = this.minimumSizeOfField(field);
8195
+ 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;
8196
+ 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;
8197
+ return stretchX <= 0 && stretchY <= 0;
8198
+ }
8199
+ return true;
8200
+ }
8201
+ fitFieldRootInView(id, shrink) {
7950
8202
  var _a, _b, _c;
7951
8203
  const field = this.model.fields.get(id);
7952
8204
  if (!field) {
7953
8205
  return;
7954
8206
  }
7955
- if (field.rootElement instanceof DiagramNode && field.fit) {
8207
+ if (field.rootElement instanceof DiagramNode) {
7956
8208
  const fieldDimensions = this.minimumSizeOfField(field);
7957
8209
  let stretchX = fieldDimensions[0] + getLeftMargin(field.rootElement.type.label) + getRightMargin(field.rootElement.type.label) - field.rootElement.width;
7958
8210
  let stretchY = fieldDimensions[1] + getTopMargin(field.rootElement.type.label) + getBottomMargin(field.rootElement.type.label) - field.rootElement.height;
@@ -7967,10 +8219,14 @@ class DiagramCanvas {
7967
8219
  if (field.rootElement.height + stretchY < field.rootElement.type.minHeight) {
7968
8220
  stretchY = field.rootElement.type.minHeight - field.rootElement.height;
7969
8221
  }
7970
- field.rootElement.stretch(Side.Right, stretchX);
7971
- field.rootElement.stretch(Side.Bottom, stretchY);
8222
+ if (shrink !== false || stretchX > 0) {
8223
+ field.rootElement.stretch(Side.Right, stretchX);
8224
+ }
8225
+ if (shrink !== false || stretchY > 0) {
8226
+ field.rootElement.stretch(Side.Bottom, stretchY);
8227
+ }
7972
8228
  }
7973
- if (field.rootElement instanceof DiagramSection && field.fit) {
8229
+ if (field.rootElement instanceof DiagramSection) {
7974
8230
  const fieldDimensions = this.minimumSizeOfField(field);
7975
8231
  let minimumFieldWidth = fieldDimensions[0];
7976
8232
  let minimumFieldHeight = fieldDimensions[1];
@@ -8003,8 +8259,12 @@ class DiagramCanvas {
8003
8259
  if (field.rootElement.height + stretchY < (field.rootElement.getMinHeight() || 0)) {
8004
8260
  stretchY = (field.rootElement.getMinHeight() || 0) - field.rootElement.height;
8005
8261
  }
8006
- (_b = field.rootElement.node) === null || _b === undefined ? undefined : _b.stretchSections(Side.Right, stretchX, field.rootElement.indexXInNode, field.rootElement.indexYInNode);
8007
- (_c = field.rootElement.node) === null || _c === undefined ? undefined : _c.stretchSections(Side.Bottom, stretchY, field.rootElement.indexXInNode, field.rootElement.indexYInNode);
8262
+ if (shrink !== false || stretchX > 0) {
8263
+ (_b = field.rootElement.node) === null || _b === undefined ? undefined : _b.stretchSections(Side.Right, stretchX, field.rootElement.indexXInNode, field.rootElement.indexYInNode);
8264
+ }
8265
+ if (shrink !== false || stretchY > 0) {
8266
+ (_c = field.rootElement.node) === null || _c === undefined ? undefined : _c.stretchSections(Side.Bottom, stretchY, field.rootElement.indexXInNode, field.rootElement.indexYInNode);
8267
+ }
8008
8268
  }
8009
8269
  }
8010
8270
  fitNodeInView(id) {
@@ -8303,18 +8563,18 @@ class DiagramCanvas {
8303
8563
  }
8304
8564
  startMultipleSelection(event) {
8305
8565
  this.draggingFrom = this.getPointerLocationRelativeToCanvas(event);
8306
- /* TODO: would be a good idea to build the multipleSelectionContainer
8307
- * from selectRoot() instead of selectCanvasElements()
8308
- * to avoid having the thickness of the rectangle be affected by zoom
8309
- */
8310
- this.multipleSelectionContainer = this.selectCanvasElements().append('rect').attr('stroke', '#0E74B6').attr('fill', 'rgba(14, 116, 182, 0.06)');
8566
+ // we put the multiple selection rectangle in the diagram svg element
8567
+ // so it's not affected by the zoom level in the diagram elements
8568
+ this.multipleSelectionContainer = this.selectSVGElement().append('rect').attr('stroke', '#0E74B6').attr('fill', 'rgba(14, 116, 182, 0.06)');
8311
8569
  }
8312
8570
  continueMultipleSelection(event) {
8313
8571
  var _a, _b, _c, _d;
8314
8572
  const pointerCoords = this.getPointerLocationRelativeToCanvas(event);
8315
8573
  if (this.draggingFrom[0] !== pointerCoords[0] || this.draggingFrom[1] !== pointerCoords[1]) {
8316
8574
  setCursorStyle(CursorStyle.Crosshair);
8317
- (_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]));
8575
+ // since the multiple selection rectangle is not affected by zoom,
8576
+ // we compensate its coordinates based in the zoom transform to draw it
8577
+ (_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);
8318
8578
  this.dragging = true;
8319
8579
  }
8320
8580
  }
@@ -8693,6 +8953,9 @@ class Grid {
8693
8953
  * @public
8694
8954
  */
8695
8955
  class AdjacencyLayout {
8956
+ constructor(gapSize) {
8957
+ this.gapSize = gapSize;
8958
+ }
8696
8959
  apply(model) {
8697
8960
  var _a;
8698
8961
  if (model.nodes.length === 0) {
@@ -8708,7 +8971,7 @@ class AdjacencyLayout {
8708
8971
  // place nodes according to arrangement
8709
8972
  const maximumWidth = Math.max(...model.nodes.map(n => n.width));
8710
8973
  const maximumHeight = Math.max(...model.nodes.map(n => n.height));
8711
- const gapSize = (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
8974
+ const gapSize = this.gapSize !== undefined ? this.gapSize : (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
8712
8975
  for (let y = nodeArrangement.minY(); y <= nodeArrangement.maxY(); ++y) {
8713
8976
  for (let x = nodeArrangement.minX(); x <= nodeArrangement.maxX(); ++x) {
8714
8977
  const node = nodeArrangement.get([x, y]);
@@ -8736,6 +8999,9 @@ const arrangeNode = (node, nodeArrangement, coords, nodesToBeArranged) => {
8736
8999
  * @public
8737
9000
  */
8738
9001
  class BreadthAdjacencyLayout {
9002
+ constructor(gapSize) {
9003
+ this.gapSize = gapSize;
9004
+ }
8739
9005
  apply(model) {
8740
9006
  var _a;
8741
9007
  if (model.nodes.length === 0) {
@@ -8773,7 +9039,7 @@ class BreadthAdjacencyLayout {
8773
9039
  // place nodes according to arrangement
8774
9040
  const maximumWidth = Math.max(...model.nodes.map(n => n.width));
8775
9041
  const maximumHeight = Math.max(...model.nodes.map(n => n.height));
8776
- const gapSize = (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9042
+ const gapSize = this.gapSize !== undefined ? this.gapSize : (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
8777
9043
  for (let y = nodeArrangement.minY(); y <= nodeArrangement.maxY(); ++y) {
8778
9044
  for (let x = nodeArrangement.minX(); x <= nodeArrangement.maxX(); ++x) {
8779
9045
  const node = nodeArrangement.get([x, y]);
@@ -8791,13 +9057,16 @@ class BreadthAdjacencyLayout {
8791
9057
  * @public
8792
9058
  */
8793
9059
  class BreadthLayout {
9060
+ constructor(gapSize) {
9061
+ this.gapSize = gapSize;
9062
+ }
8794
9063
  apply(model) {
8795
9064
  var _a;
8796
9065
  if (model.nodes.length === 0) {
8797
9066
  // nothing to arrange...
8798
9067
  return model;
8799
9068
  }
8800
- const gapSize = (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9069
+ const gapSize = this.gapSize !== undefined ? this.gapSize : (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
8801
9070
  let nodesToBeArranged = model.nodes.filter(n => !n.parent);
8802
9071
  // Arrange nodes by a breadth first search
8803
9072
  const firstNode = nodesToBeArranged[0];
@@ -8853,6 +9122,9 @@ class BreadthLayout {
8853
9122
  * @public
8854
9123
  */
8855
9124
  class ForceLayout {
9125
+ constructor(gapSize) {
9126
+ this.gapSize = gapSize;
9127
+ }
8856
9128
  apply(model) {
8857
9129
  var _a;
8858
9130
  if (model.nodes.length === 0) {
@@ -8861,7 +9133,7 @@ class ForceLayout {
8861
9133
  }
8862
9134
  // as a starting point, we apply a simple layout
8863
9135
  new BreadthLayout().apply(model);
8864
- const gapSize = (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9136
+ const gapSize = this.gapSize !== undefined ? this.gapSize : (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
8865
9137
  const coolingFactor = 0.99;
8866
9138
  const minimumTemperature = 1;
8867
9139
  const attractionFactor = 0.1;
@@ -8948,13 +9220,16 @@ class ForceLayout {
8948
9220
  * @public
8949
9221
  */
8950
9222
  class HorizontalLayout {
9223
+ constructor(gapSize) {
9224
+ this.gapSize = gapSize;
9225
+ }
8951
9226
  apply(model) {
8952
9227
  var _a;
8953
9228
  if (model.nodes.length === 0) {
8954
9229
  // nothing to arrange...
8955
9230
  return model;
8956
9231
  }
8957
- const gapSize = (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9232
+ const gapSize = this.gapSize !== undefined ? this.gapSize : (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
8958
9233
  const nodesToBeArranged = model.nodes.filter(n => !n.parent);
8959
9234
  nodesToBeArranged.sort((a, b) => b.type.priority - a.type.priority);
8960
9235
  let widthAccumulator = 0;
@@ -8971,6 +9246,9 @@ class HorizontalLayout {
8971
9246
  * @public
8972
9247
  */
8973
9248
  class PriorityLayout {
9249
+ constructor(gapSize) {
9250
+ this.gapSize = gapSize;
9251
+ }
8974
9252
  apply(model) {
8975
9253
  var _a;
8976
9254
  if (model.nodes.length === 0) {
@@ -8984,7 +9262,7 @@ class PriorityLayout {
8984
9262
  new BreadthLayout().apply(model);
8985
9263
  return model;
8986
9264
  }
8987
- const gapSize = (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9265
+ const gapSize = this.gapSize !== undefined ? this.gapSize : (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
8988
9266
  const nodesToBeArranged = model.nodes.filter(n => !n.parent);
8989
9267
  const nodeArrangement = [];
8990
9268
  const nodesWithMaximumPriorityToBeArranged = model.nodes.filter(n => !n.parent).filter(n => n.getPriority() >= maximumPriority);
@@ -9078,6 +9356,9 @@ class PriorityLayout {
9078
9356
  * @public
9079
9357
  */
9080
9358
  class TreeLayout {
9359
+ constructor(gapSize) {
9360
+ this.gapSize = gapSize;
9361
+ }
9081
9362
  apply(model) {
9082
9363
  var _a;
9083
9364
  if (model.nodes.length === 0) {
@@ -9091,7 +9372,7 @@ class TreeLayout {
9091
9372
  new BreadthLayout().apply(model);
9092
9373
  return model;
9093
9374
  }
9094
- const gapSize = (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9375
+ const gapSize = this.gapSize !== undefined ? this.gapSize : (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9095
9376
  const nodesToBeArranged = model.nodes.filter(n => !n.parent).sort((n1, n2) => n2.getPriority() - n1.getPriority());
9096
9377
  const branches = [];
9097
9378
  while (nodesToBeArranged.length > 0) {
@@ -9176,13 +9457,16 @@ class Branch {
9176
9457
  * @public
9177
9458
  */
9178
9459
  class VerticalLayout {
9460
+ constructor(gapSize) {
9461
+ this.gapSize = gapSize;
9462
+ }
9179
9463
  apply(model) {
9180
9464
  var _a;
9181
9465
  if (model.nodes.length === 0) {
9182
9466
  // nothing to arrange...
9183
9467
  return model;
9184
9468
  }
9185
- const gapSize = (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9469
+ const gapSize = this.gapSize !== undefined ? this.gapSize : (((_a = model.canvas) === null || _a === undefined ? undefined : _a.gridSize) || 0) * 2;
9186
9470
  const nodesToBeArranged = model.nodes.filter(n => !n.parent);
9187
9471
  nodesToBeArranged.sort((a, b) => b.type.priority - a.type.priority);
9188
9472
  let heightAccumulator = 0;