@metadev/daga 1.0.0 → 1.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.
@@ -223,8 +223,8 @@ class AdjacencyLayout {
223
223
  arrangeNode(nodesToBeArranged[0], nodeArrangement, [0, 0], nodesToBeArranged);
224
224
  }
225
225
  // place nodes according to arrangement
226
- const maximumWidth = Math.max(...model.nodes.map((n) => n.width));
227
- const maximumHeight = Math.max(...model.nodes.map((n) => n.height));
226
+ const maximumWidth = Math.max(...model.nodes.all().map((n) => n.width));
227
+ const maximumHeight = Math.max(...model.nodes.all().map((n) => n.height));
228
228
  const gapSize = (model.canvas?.gridSize || 0) * 2;
229
229
  for (let y = nodeArrangement.minY(); y <= nodeArrangement.maxY(); ++y) {
230
230
  for (let x = nodeArrangement.minX(); x <= nodeArrangement.maxX(); ++x) {
@@ -294,8 +294,8 @@ class BreadthAdjacencyLayout {
294
294
  }
295
295
  }
296
296
  // place nodes according to arrangement
297
- const maximumWidth = Math.max(...model.nodes.map((n) => n.width));
298
- const maximumHeight = Math.max(...model.nodes.map((n) => n.height));
297
+ const maximumWidth = Math.max(...model.nodes.all().map((n) => n.width));
298
+ const maximumHeight = Math.max(...model.nodes.all().map((n) => n.height));
299
299
  const gapSize = (model.canvas?.gridSize || 0) * 2;
300
300
  for (let y = nodeArrangement.minY(); y <= nodeArrangement.maxY(); ++y) {
301
301
  for (let x = nodeArrangement.minX(); x <= nodeArrangement.maxX(); ++x) {
@@ -634,7 +634,7 @@ class HorizontalLayout {
634
634
  return model;
635
635
  }
636
636
  const gapSize = (model.canvas?.gridSize || 0) * 2;
637
- const nodesToBeArranged = model.nodes;
637
+ const nodesToBeArranged = model.nodes.all();
638
638
  nodesToBeArranged.sort((a, b) => b.type.priority - a.type.priority);
639
639
  let widthAccumulator = 0;
640
640
  for (const node of nodesToBeArranged) {
@@ -654,8 +654,8 @@ class PriorityLayout {
654
654
  // nothing to arrange...
655
655
  return model;
656
656
  }
657
- const maximumPriority = Math.max(...model.nodeTypes.map((n) => n.priority));
658
- const minimumPriority = Math.min(...model.nodeTypes.map((n) => n.priority));
657
+ const maximumPriority = Math.max(...model.nodes.types.all().map((n) => n.priority));
658
+ const minimumPriority = Math.min(...model.nodes.types.all().map((n) => n.priority));
659
659
  if (maximumPriority === minimumPriority) {
660
660
  // if there's no disparity in priorities, just use breadth layout
661
661
  new BreadthLayout().apply(model);
@@ -664,7 +664,7 @@ class PriorityLayout {
664
664
  const gapSize = (model.canvas?.gridSize || 0) * 2;
665
665
  const nodesToBeArranged = [...model.nodes];
666
666
  const nodeArrangement = [];
667
- const nodesWithMaximumPriorityToBeArranged = model.getNodes(maximumPriority);
667
+ const nodesWithMaximumPriorityToBeArranged = model.nodes.filter(undefined, maximumPriority);
668
668
  const nodesWithMaximumPriority = [];
669
669
  if (nodesWithMaximumPriorityToBeArranged.length > 1) {
670
670
  // use bfs to sort nodes by distance to the first node
@@ -762,7 +762,7 @@ class VerticalLayout {
762
762
  return model;
763
763
  }
764
764
  const gapSize = (model.canvas?.gridSize || 0) * 2;
765
- const nodesToBeArranged = model.nodes;
765
+ const nodesToBeArranged = model.nodes.all();
766
766
  nodesToBeArranged.sort((a, b) => b.type.priority - a.type.priority);
767
767
  let heightAccumulator = 0;
768
768
  for (const node of nodesToBeArranged) {
@@ -1336,14 +1336,11 @@ class AddNodeAction {
1336
1336
  }
1337
1337
  undo() {
1338
1338
  if (this.id) {
1339
- const node = this.canvas.model.getNode(this.id);
1340
- if (node) {
1341
- this.canvas.model.deleteNode(node);
1342
- }
1339
+ this.canvas.model.nodes.remove(this.id);
1343
1340
  }
1344
1341
  }
1345
1342
  redo() {
1346
- const node = this.canvas.model.addNode(this.type, this.coords, this.id, this.sectionIds, this.sectionPortIds, this.sectionPortLabelIds, this.portIds, this.portLabelIds, this.labelId);
1343
+ const node = this.canvas.model.nodes.new(this.type, this.coords, this.id, this.sectionIds, this.sectionPortIds, this.sectionPortLabelIds, this.portIds, this.portLabelIds, this.labelId);
1347
1344
  if (this.values !== undefined) {
1348
1345
  node.valueSet.setValues(structuredClone({
1349
1346
  ...node.valueSet.getValues(),
@@ -1372,16 +1369,10 @@ class MoveNodeAction {
1372
1369
  this.to = to;
1373
1370
  }
1374
1371
  undo() {
1375
- const node = this.canvas.model.getNode(this.nodeId);
1376
- if (node) {
1377
- node.move(this.from);
1378
- }
1372
+ this.canvas.model.nodes.get(this.nodeId)?.move(this.from);
1379
1373
  }
1380
1374
  redo() {
1381
- const node = this.canvas.model.getNode(this.nodeId);
1382
- if (node) {
1383
- node.move(this.to);
1384
- }
1375
+ this.canvas.model.nodes.get(this.nodeId)?.move(this.to);
1385
1376
  }
1386
1377
  }
1387
1378
  class StretchNodeAction {
@@ -1393,16 +1384,14 @@ class StretchNodeAction {
1393
1384
  this.to = to;
1394
1385
  }
1395
1386
  undo() {
1396
- const node = this.canvas.model.getNode(this.nodeId);
1397
- if (node) {
1398
- node.stretch(this.direction, this.from - this.to);
1399
- }
1387
+ this.canvas.model.nodes
1388
+ .get(this.nodeId)
1389
+ ?.stretch(this.direction, this.from - this.to);
1400
1390
  }
1401
1391
  redo() {
1402
- const node = this.canvas.model.getNode(this.nodeId);
1403
- if (node) {
1404
- node.stretch(this.direction, this.to - this.from);
1405
- }
1392
+ this.canvas.model.nodes
1393
+ .get(this.nodeId)
1394
+ ?.stretch(this.direction, this.to - this.from);
1406
1395
  }
1407
1396
  }
1408
1397
  class StretchSectionAction {
@@ -1414,14 +1403,14 @@ class StretchSectionAction {
1414
1403
  this.to = to;
1415
1404
  }
1416
1405
  undo() {
1417
- const section = this.canvas.model.getSection(this.sectionId);
1406
+ const section = this.canvas.model.sections.get(this.sectionId);
1418
1407
  const node = section?.node;
1419
1408
  if (node) {
1420
1409
  node.stretchSections(this.direction, this.from - this.to, section.coords);
1421
1410
  }
1422
1411
  }
1423
1412
  redo() {
1424
- const section = this.canvas.model.getSection(this.sectionId);
1413
+ const section = this.canvas.model.sections.get(this.sectionId);
1425
1414
  const node = section?.node;
1426
1415
  if (node) {
1427
1416
  node.stretchSections(this.direction, this.to - this.from, section.coords);
@@ -1438,17 +1427,14 @@ class AddConnectionAction {
1438
1427
  }
1439
1428
  undo() {
1440
1429
  if (this.id) {
1441
- const connection = this.canvas.model.getConnection(this.id);
1442
- if (connection) {
1443
- this.canvas.model.deleteConnection(connection);
1444
- }
1430
+ this.canvas.model.connections.remove(this.id);
1445
1431
  }
1446
1432
  }
1447
1433
  redo() {
1448
- const start = this.canvas.model.getPort(this.startId);
1449
- const end = this.canvas.model.getPort(this.endId);
1434
+ const start = this.canvas.model.ports.get(this.startId);
1435
+ const end = this.canvas.model.ports.get(this.endId);
1450
1436
  if (start && end) {
1451
- const connection = this.canvas.model.addConnection(this.type, start, end, this.id);
1437
+ const connection = this.canvas.model.connections.new(this.type, start, end, this.id);
1452
1438
  // reset our id in case it was automatically generated
1453
1439
  this.id = connection.id;
1454
1440
  }
@@ -1462,14 +1448,14 @@ class EditFieldAction {
1462
1448
  this.to = to;
1463
1449
  }
1464
1450
  undo() {
1465
- const field = this.canvas.model.getField(this.fieldId);
1451
+ const field = this.canvas.model.fields.get(this.fieldId);
1466
1452
  if (field) {
1467
1453
  field.text = this.from;
1468
1454
  this.canvas.updateFieldsInView(this.fieldId);
1469
1455
  }
1470
1456
  }
1471
1457
  redo() {
1472
- const field = this.canvas.model.getField(this.fieldId);
1458
+ const field = this.canvas.model.fields.get(this.fieldId);
1473
1459
  if (field) {
1474
1460
  field.text = this.to;
1475
1461
  this.canvas.updateFieldsInView(this.fieldId);
@@ -1488,7 +1474,7 @@ class UpdateValuesAction {
1488
1474
  return this.model.valueSet;
1489
1475
  }
1490
1476
  else {
1491
- return this.model.getElement(this.id)?.valueSet;
1477
+ return (this.model.nodes.get(this.id) || this.model.connections.get(this.id))?.valueSet;
1492
1478
  }
1493
1479
  }
1494
1480
  undo() {
@@ -1557,30 +1543,30 @@ class RemoveAction {
1557
1543
  }
1558
1544
  undo() {
1559
1545
  for (const node of this.nodes) {
1560
- this.model.nodes.push(node);
1546
+ this.model.nodes.add(node);
1561
1547
  }
1562
1548
  for (const section of this.sections) {
1563
- this.model.sections.push(section);
1549
+ this.model.sections.add(section);
1564
1550
  }
1565
1551
  for (const port of this.ports) {
1566
- this.model.ports.push(port);
1552
+ this.model.ports.add(port);
1567
1553
  }
1568
1554
  for (const connection of this.connections) {
1569
- this.model.connections.push(connection);
1555
+ this.model.connections.add(connection);
1570
1556
  }
1571
1557
  for (const field of this.fields) {
1572
- this.model.fields.push(field);
1558
+ this.model.fields.add(field);
1573
1559
  }
1574
1560
  for (const node of this.nodes) {
1575
1561
  if (node.label) {
1576
- const label = this.model.getField(node.label._id);
1562
+ const label = this.model.fields.get(node.label._id);
1577
1563
  if (label) {
1578
1564
  node.label = label;
1579
1565
  }
1580
1566
  }
1581
1567
  const ports = [];
1582
1568
  for (const nodePort of node.ports) {
1583
- const port = this.model.getPort(nodePort._id);
1569
+ const port = this.model.ports.get(nodePort._id);
1584
1570
  if (port) {
1585
1571
  ports.push(port);
1586
1572
  }
@@ -1588,7 +1574,7 @@ class RemoveAction {
1588
1574
  node.ports = ports;
1589
1575
  const sections = [];
1590
1576
  for (const nodeSection of node.sections) {
1591
- const section = this.model.getSection(nodeSection._id);
1577
+ const section = this.model.sections.get(nodeSection._id);
1592
1578
  if (section) {
1593
1579
  sections.push(section);
1594
1580
  }
@@ -1597,20 +1583,20 @@ class RemoveAction {
1597
1583
  }
1598
1584
  for (const section of this.sections) {
1599
1585
  if (section.node) {
1600
- const node = this.model.getNode(section.node._id);
1586
+ const node = this.model.nodes.get(section.node._id);
1601
1587
  if (node) {
1602
1588
  section.node = node;
1603
1589
  }
1604
1590
  }
1605
1591
  if (section.label) {
1606
- const label = this.model.getField(section.label._id);
1592
+ const label = this.model.fields.get(section.label._id);
1607
1593
  if (label) {
1608
1594
  section.label = label;
1609
1595
  }
1610
1596
  }
1611
1597
  const ports = [];
1612
1598
  for (const sectionPort of section.ports) {
1613
- const port = this.model.getPort(sectionPort._id);
1599
+ const port = this.model.ports.get(sectionPort._id);
1614
1600
  if (port) {
1615
1601
  ports.push(port);
1616
1602
  }
@@ -1619,20 +1605,21 @@ class RemoveAction {
1619
1605
  }
1620
1606
  for (const port of this.ports) {
1621
1607
  if (port.rootElement) {
1622
- const rootElement = this.model.getElement(port.rootElement._id);
1608
+ const rootElement = this.model.nodes.get(port.rootElement._id) ||
1609
+ this.model.sections.get(port.rootElement._id);
1623
1610
  if (rootElement) {
1624
1611
  port.rootElement = rootElement;
1625
1612
  }
1626
1613
  }
1627
1614
  if (port.label) {
1628
- const label = this.model.getField(port.label._id);
1615
+ const label = this.model.fields.get(port.label._id);
1629
1616
  if (label) {
1630
1617
  port.label = label;
1631
1618
  }
1632
1619
  }
1633
1620
  const outgoingConnections = [];
1634
1621
  for (const portOutgoingConnection of port.outgoingConnections) {
1635
- const connection = this.model.getConnection(portOutgoingConnection._id);
1622
+ const connection = this.model.connections.get(portOutgoingConnection._id);
1636
1623
  if (connection) {
1637
1624
  outgoingConnections.push(connection);
1638
1625
  }
@@ -1640,7 +1627,7 @@ class RemoveAction {
1640
1627
  port.outgoingConnections = outgoingConnections;
1641
1628
  const incomingConnections = [];
1642
1629
  for (const portIncomingConnection of port.incomingConnections) {
1643
- const connection = this.model.getConnection(portIncomingConnection._id);
1630
+ const connection = this.model.connections.get(portIncomingConnection._id);
1644
1631
  if (connection) {
1645
1632
  incomingConnections.push(connection);
1646
1633
  }
@@ -1649,13 +1636,13 @@ class RemoveAction {
1649
1636
  }
1650
1637
  for (const connection of this.connections) {
1651
1638
  if (connection.start) {
1652
- const start = this.model.getPort(connection.start._id);
1639
+ const start = this.model.ports.get(connection.start._id);
1653
1640
  if (start) {
1654
1641
  connection.setStart(start);
1655
1642
  }
1656
1643
  }
1657
1644
  if (connection.end) {
1658
- const end = this.model.getPort(connection.end._id);
1645
+ const end = this.model.ports.get(connection.end._id);
1659
1646
  if (end) {
1660
1647
  connection.setEnd(end);
1661
1648
  }
@@ -1663,7 +1650,9 @@ class RemoveAction {
1663
1650
  }
1664
1651
  for (const field of this.fields) {
1665
1652
  if (field.rootElement) {
1666
- const rootElement = this.model.getElement(field.rootElement._id);
1653
+ const rootElement = this.model.nodes.get(field.rootElement._id) ||
1654
+ this.model.sections.get(field.rootElement._id) ||
1655
+ this.model.ports.get(field.rootElement._id);
1667
1656
  if (rootElement) {
1668
1657
  field.rootElement = rootElement;
1669
1658
  }
@@ -1680,7 +1669,7 @@ class RemoveAction {
1680
1669
  this.fields = [];
1681
1670
  // make shallow copies of the elements with their relationships
1682
1671
  for (const nodeId of this.nodeIds) {
1683
- const node = this.model.getNode(nodeId);
1672
+ const node = this.model.nodes.get(nodeId);
1684
1673
  if (node) {
1685
1674
  const nodeCopy = clone(node);
1686
1675
  if (nodeCopy.label) {
@@ -1692,7 +1681,7 @@ class RemoveAction {
1692
1681
  }
1693
1682
  }
1694
1683
  for (const sectionId of this.sectionIds) {
1695
- const section = this.model.getSection(sectionId);
1684
+ const section = this.model.sections.get(sectionId);
1696
1685
  if (section) {
1697
1686
  const sectionCopy = clone(section);
1698
1687
  if (sectionCopy.label) {
@@ -1703,7 +1692,7 @@ class RemoveAction {
1703
1692
  }
1704
1693
  }
1705
1694
  for (const portId of this.portIds) {
1706
- const port = this.model.getPort(portId);
1695
+ const port = this.model.ports.get(portId);
1707
1696
  if (port) {
1708
1697
  const portCopy = clone(port);
1709
1698
  if (portCopy.rootElement) {
@@ -1718,7 +1707,7 @@ class RemoveAction {
1718
1707
  }
1719
1708
  }
1720
1709
  for (const connectionId of this.connectionIds) {
1721
- const connection = this.model.getConnection(connectionId);
1710
+ const connection = this.model.connections.get(connectionId);
1722
1711
  if (connection) {
1723
1712
  const connectionCopy = clone(connection);
1724
1713
  if (connectionCopy.start) {
@@ -1731,7 +1720,7 @@ class RemoveAction {
1731
1720
  }
1732
1721
  }
1733
1722
  for (const fieldId of this.fieldIds) {
1734
- const field = this.model.getField(fieldId);
1723
+ const field = this.model.fields.get(fieldId);
1735
1724
  if (field) {
1736
1725
  const fieldCopy = clone(field);
1737
1726
  if (fieldCopy.rootElement) {
@@ -1742,34 +1731,19 @@ class RemoveAction {
1742
1731
  }
1743
1732
  // delete the elements
1744
1733
  for (const nodeId of this.nodeIds) {
1745
- const node = this.model.getNode(nodeId);
1746
- if (node) {
1747
- this.model.deleteNode(node);
1748
- }
1734
+ this.model.nodes.remove(nodeId);
1749
1735
  }
1750
1736
  for (const sectionId of this.sectionIds) {
1751
- const section = this.model.getSection(sectionId);
1752
- if (section) {
1753
- this.model.deleteSection(section);
1754
- }
1737
+ this.model.sections.remove(sectionId);
1755
1738
  }
1756
1739
  for (const portId of this.portIds) {
1757
- const port = this.model.getPort(portId);
1758
- if (port) {
1759
- this.model.deletePort(port);
1760
- }
1740
+ this.model.ports.remove(portId);
1761
1741
  }
1762
1742
  for (const connectionId of this.connectionIds) {
1763
- const connection = this.model.getConnection(connectionId);
1764
- if (connection) {
1765
- this.model.deleteConnection(connection);
1766
- }
1743
+ this.model.connections.remove(connectionId);
1767
1744
  }
1768
1745
  for (const fieldId of this.fieldIds) {
1769
- const field = this.model.getField(fieldId);
1770
- if (field) {
1771
- this.model.deleteField(field);
1772
- }
1746
+ this.model.fields.remove(fieldId);
1773
1747
  }
1774
1748
  }
1775
1749
  }
@@ -1781,7 +1755,7 @@ const clone = (obj) => {
1781
1755
  };
1782
1756
 
1783
1757
  /**
1784
- * Represents an object which exists as part of a particular diagram model and has a visual representation in a diagram canvas.
1758
+ * Represents an object which exists as part of a specific diagram model and has a visual representation in a diagram canvas.
1785
1759
  * @see DiagramModel
1786
1760
  * @see DiagramCanvas
1787
1761
  */
@@ -1806,6 +1780,104 @@ class DiagramElement {
1806
1780
  return this.model.canvas?.selectCanvasView()?.select(`g#${this.id}`);
1807
1781
  }
1808
1782
  }
1783
+ /**
1784
+ * Represents a collection of diagram entities of a type that exists as part of a diagram model.
1785
+ * @see DiagramEntity
1786
+ * @see DiagramModel
1787
+ */
1788
+ class DiagramEntitySet {
1789
+ constructor() {
1790
+ /**
1791
+ * The list of entities contained in this set.
1792
+ */
1793
+ this.entities = [];
1794
+ /**
1795
+ * A mapping of entity ids to their corresponding entity in this set for quickly fetching entities based on their id.
1796
+ */
1797
+ this.entityMap = {};
1798
+ }
1799
+ /**
1800
+ * The number of entities of this set.
1801
+ */
1802
+ get length() {
1803
+ return this.entities.length;
1804
+ }
1805
+ /**
1806
+ * Gets all of the entities of this set.
1807
+ * @returns An array containing all of the entities of this set.
1808
+ */
1809
+ all() {
1810
+ return [...this.entities];
1811
+ }
1812
+ /**
1813
+ * Adds an entity to this set if there are no entities with the same id. Has no effect if there already exists an entity with the same id as the given entity.
1814
+ * For creating entities with relationships with other entities, the new() method should be used instead. The add() method adds an entity but doesn't take care of setting that entity's relationships with other entities.
1815
+ * @param entity An entity to be added to this set.
1816
+ */
1817
+ add(entity) {
1818
+ if (this.entityMap[entity.id] === undefined) {
1819
+ this.entityMap[entity.id] = entity;
1820
+ this.entities.push(entity);
1821
+ }
1822
+ }
1823
+ /**
1824
+ * Removes all the entities in this set.
1825
+ */
1826
+ clear() {
1827
+ // remove each entity individually in case classes that extend this implement their own specific cleanup
1828
+ while (this.entities.length > 0) {
1829
+ this.remove(this.entities[0].id);
1830
+ }
1831
+ }
1832
+ /**
1833
+ * Checks if this set contains an entity with the given id.
1834
+ * @param id An id.
1835
+ * @returns `true` if this set contains an entity with the given id, `false` otherwise.
1836
+ */
1837
+ contains(id) {
1838
+ return this.entityMap[id] !== undefined;
1839
+ }
1840
+ /**
1841
+ * Gets all of the entities of this set filtered following given criteria.
1842
+ * @returns An array containing the entities of this set that meet the given criteria.
1843
+ */
1844
+ filter() {
1845
+ return this.all();
1846
+ }
1847
+ /**
1848
+ * Gets an entity of this set matching specific criteria.
1849
+ * @returns An entity of this set.
1850
+ */
1851
+ find() {
1852
+ return this.entities.length > 0 ? this.entities[0] : undefined;
1853
+ }
1854
+ /**
1855
+ * Gets an entity from this set.
1856
+ * @param id An id.
1857
+ * @returns An entity with the given id, or `undefined` if there are no entities with the given id.
1858
+ */
1859
+ get(id) {
1860
+ return this.entityMap[id];
1861
+ }
1862
+ /**
1863
+ * Attempts to find and remove an entity with the given id. Has no effect if there are no entities with the given id.
1864
+ * @param id An id.
1865
+ */
1866
+ remove(id) {
1867
+ const entity = this.get(id);
1868
+ if (entity !== undefined) {
1869
+ delete this.entityMap[id];
1870
+ removeIfExists(this.entities, entity);
1871
+ }
1872
+ }
1873
+ *[Symbol.iterator]() {
1874
+ let counter = 0;
1875
+ while (counter < this.entities.length) {
1876
+ yield this.entities[counter];
1877
+ ++counter;
1878
+ }
1879
+ }
1880
+ }
1809
1881
 
1810
1882
  class Property {
1811
1883
  constructor(name, type, defaultValue, basic, editable, rootAttribute) {
@@ -2130,13 +2202,13 @@ class DiagramConnection extends DiagramElement {
2130
2202
  }
2131
2203
  constructor(model, type, start, end, id) {
2132
2204
  let uniqueId;
2133
- if (id !== undefined && model.getConnection(id) === undefined) {
2205
+ if (id !== undefined && model.connections.get(id) === undefined) {
2134
2206
  uniqueId = id;
2135
2207
  }
2136
2208
  else {
2137
2209
  do {
2138
2210
  uniqueId = `diagram-connection-${++idTicker$4}`;
2139
- } while (model.getConnection(uniqueId) !== undefined);
2211
+ } while (model.connections.get(uniqueId) !== undefined);
2140
2212
  }
2141
2213
  super(model, uniqueId);
2142
2214
  this.startCoords = [0, 0];
@@ -2200,56 +2272,62 @@ class DiagramConnection extends DiagramElement {
2200
2272
  }
2201
2273
  }
2202
2274
  }
2275
+ class DiagramConnectionSet extends DiagramEntitySet {
2276
+ constructor(model) {
2277
+ super();
2278
+ this.types = new DiagramEntitySet();
2279
+ this.model = model;
2280
+ }
2281
+ new(type, start, end, id) {
2282
+ const connection = new DiagramConnection(this.model, type, start, end, id);
2283
+ super.add(connection);
2284
+ connection.updateInView();
2285
+ return connection;
2286
+ }
2287
+ remove(id) {
2288
+ const connection = this.get(id);
2289
+ if (connection) {
2290
+ // remove from ports
2291
+ removeIfExists(connection.start?.outgoingConnections || [], connection);
2292
+ removeIfExists(connection.end?.incomingConnections || [], connection);
2293
+ // remove from set of connections
2294
+ super.remove(id);
2295
+ // remove from canvas
2296
+ connection.updateInView();
2297
+ }
2298
+ }
2299
+ filter(type, threshold) {
2300
+ return this.entities.filter((e) => (type ? e.type.id === type : true) &&
2301
+ (threshold
2302
+ ? (e.start?.getNode()?.type?.priority || Number.NEGATIVE_INFINITY) >=
2303
+ threshold &&
2304
+ (e.end?.getNode()?.type?.priority || Number.NEGATIVE_INFINITY) >=
2305
+ threshold
2306
+ : true));
2307
+ }
2308
+ find(type, threshold) {
2309
+ return this.entities.find((e) => (type ? e.type.id === type : true) &&
2310
+ (threshold
2311
+ ? (e.start?.getNode()?.type?.priority || Number.NEGATIVE_INFINITY) >=
2312
+ threshold &&
2313
+ (e.end?.getNode()?.type?.priority || Number.NEGATIVE_INFINITY) >=
2314
+ threshold
2315
+ : true));
2316
+ }
2317
+ }
2203
2318
 
2204
2319
  let idTicker$3 = 0;
2205
- const DIAGRAM_LOOK_DEFAULTS = {
2206
- lookType: 'shaped-look',
2207
- shape: ClosedShape.Rectangle,
2208
- color: '#FFFFFF',
2209
- borderColor: '#000000',
2210
- selectedColor: '#FFFFFF',
2211
- selectedBorderColor: '#000000'
2212
- };
2213
- const DIAGRAM_NODE_TYPE_DEFAULTS = {
2214
- name: '',
2215
- defaultWidth: 0,
2216
- defaultHeight: 0,
2320
+ const DIAGRAM_SECTION_DEFAULTS = {
2321
+ sectionsX: 1,
2322
+ sectionsY: 1,
2217
2323
  minWidth: 0,
2218
2324
  minHeight: 0,
2219
- resizableX: false,
2220
- resizableY: false,
2325
+ margin: 0,
2221
2326
  label: null,
2222
2327
  ports: [],
2223
- sections: null,
2224
- look: DIAGRAM_LOOK_DEFAULTS,
2225
- isUnique: false,
2226
- priority: 0,
2227
- properties: []
2328
+ look: DIAGRAM_LOOK_DEFAULTS
2228
2329
  };
2229
- class DiagramNodeType {
2230
- constructor(options) {
2231
- const values = {
2232
- ...DIAGRAM_NODE_TYPE_DEFAULTS,
2233
- ...options
2234
- };
2235
- this.id = values.id;
2236
- this.name = values.name;
2237
- this.defaultWidth = values.defaultWidth;
2238
- this.defaultHeight = values.defaultHeight;
2239
- this.minWidth = values.minWidth;
2240
- this.minHeight = values.minHeight;
2241
- this.resizableX = values.resizableX;
2242
- this.resizableY = values.resizableY;
2243
- this.label = values.label;
2244
- this.ports = values.ports;
2245
- this.sections = values.sections;
2246
- this.look = values.look;
2247
- this.isUnique = values.isUnique;
2248
- this.priority = values.priority;
2249
- this.propertySet = new PropertySet(options?.properties || []);
2250
- }
2251
- }
2252
- class DiagramNode extends DiagramElement {
2330
+ class DiagramSection extends DiagramElement {
2253
2331
  get name() {
2254
2332
  return this.label?.text || '';
2255
2333
  }
@@ -2259,29 +2337,26 @@ class DiagramNode extends DiagramElement {
2259
2337
  this.label.updateInView();
2260
2338
  }
2261
2339
  }
2262
- constructor(model, type, coords = [0, 0], id) {
2340
+ constructor(model, node, coords, width, height, id) {
2263
2341
  let uniqueId;
2264
- if (id !== undefined && model.getNode(id) === undefined) {
2342
+ if (id !== undefined && model.sections.get(id) === undefined) {
2265
2343
  uniqueId = id;
2266
2344
  }
2267
2345
  else {
2268
2346
  do {
2269
- uniqueId = `diagram-node-${++idTicker$3}`;
2270
- } while (model.getNode(uniqueId) !== undefined);
2347
+ uniqueId = `diagram-section-${++idTicker$3}`;
2348
+ } while (model.sections.get(uniqueId) !== undefined);
2271
2349
  }
2272
2350
  super(model, uniqueId);
2273
- this.sections = [];
2274
2351
  this.ports = [];
2275
- this.type = type;
2276
- this.valueSet = new ValueSet(type.propertySet, this);
2277
- this.originalData = {};
2352
+ this.node = node;
2278
2353
  this.coords = coords;
2279
- this.width = type.defaultWidth;
2280
- this.height = type.defaultHeight;
2354
+ this.width = width;
2355
+ this.height = height;
2281
2356
  }
2282
2357
  updateInView() {
2283
2358
  if (this.model.canvas && this.model.renderToCanvas) {
2284
- this.model.canvas.updateNodesInView(this.id);
2359
+ this.model.canvas.updateSectionsInView(this.id);
2285
2360
  }
2286
2361
  }
2287
2362
  getClosestPortToPoint(coords) {
@@ -2328,36 +2403,12 @@ class DiagramNode extends DiagramElement {
2328
2403
  }
2329
2404
  return result;
2330
2405
  }
2331
- getAdjacentNodes() {
2332
- const result = [];
2333
- for (const port of this.ports) {
2334
- for (const incomingConnection of port.incomingConnections) {
2335
- const otherNode = incomingConnection.start?.getNode();
2336
- if (otherNode) {
2337
- result.push(otherNode);
2338
- }
2339
- }
2340
- for (const outgoingConnection of port.outgoingConnections) {
2341
- const otherNode = outgoingConnection.end?.getNode();
2342
- if (otherNode) {
2343
- result.push(otherNode);
2344
- }
2345
- }
2346
- }
2347
- return result;
2348
- }
2349
2406
  move(coords) {
2350
2407
  const coordDifferences = [
2351
2408
  coords[0] - this.coords[0],
2352
2409
  coords[1] - this.coords[1]
2353
2410
  ];
2354
2411
  this.coords = coords;
2355
- for (const section of this.sections) {
2356
- section.move([
2357
- section.coords[0] + coordDifferences[0],
2358
- section.coords[1] + coordDifferences[1]
2359
- ]);
2360
- }
2361
2412
  for (const port of this.ports) {
2362
2413
  port.move([
2363
2414
  port.coords[0] + coordDifferences[0],
@@ -2382,29 +2433,49 @@ class DiagramNode extends DiagramElement {
2382
2433
  case Side.Left:
2383
2434
  newCoordsX = [oldCoordsX[0] - distance, oldCoordsX[1]];
2384
2435
  newCoordsY = [oldCoordsY[0], oldCoordsY[1]];
2385
- if (newCoordsX[1] - newCoordsX[0] < this.type.minWidth) {
2386
- newCoordsX[0] = newCoordsX[1] - this.type.minWidth;
2436
+ if (newCoordsX[1] - newCoordsX[0] <
2437
+ (this.node?.type?.sections?.minWidth ||
2438
+ DIAGRAM_SECTION_DEFAULTS.minWidth)) {
2439
+ newCoordsX[0] =
2440
+ newCoordsX[1] -
2441
+ (this.node?.type?.sections?.minWidth ||
2442
+ DIAGRAM_SECTION_DEFAULTS.minWidth);
2387
2443
  }
2388
2444
  break;
2389
2445
  case Side.Top:
2390
2446
  newCoordsX = [oldCoordsX[0], oldCoordsX[1]];
2391
2447
  newCoordsY = [oldCoordsY[0] - distance, oldCoordsY[1]];
2392
- if (newCoordsY[1] - newCoordsY[0] < this.type.minHeight) {
2393
- newCoordsY[0] = newCoordsY[1] - this.type.minHeight;
2448
+ if (newCoordsY[1] - newCoordsY[0] <
2449
+ (this.node?.type?.sections?.minHeight ||
2450
+ DIAGRAM_SECTION_DEFAULTS.minHeight)) {
2451
+ newCoordsY[0] =
2452
+ newCoordsY[1] -
2453
+ (this.node?.type?.sections?.minHeight ||
2454
+ DIAGRAM_SECTION_DEFAULTS.minHeight);
2394
2455
  }
2395
2456
  break;
2396
2457
  case Side.Right:
2397
2458
  newCoordsX = [oldCoordsX[0], oldCoordsX[1] + distance];
2398
2459
  newCoordsY = [oldCoordsY[0], oldCoordsY[1]];
2399
- if (newCoordsX[1] - newCoordsX[0] < this.type.minWidth) {
2400
- newCoordsX[1] = newCoordsX[0] + this.type.minWidth;
2460
+ if (newCoordsX[1] - newCoordsX[0] <
2461
+ (this.node?.type?.sections?.minWidth ||
2462
+ DIAGRAM_SECTION_DEFAULTS.minWidth)) {
2463
+ newCoordsX[1] =
2464
+ newCoordsX[0] +
2465
+ (this.node?.type?.sections?.minWidth ||
2466
+ DIAGRAM_SECTION_DEFAULTS.minWidth);
2401
2467
  }
2402
2468
  break;
2403
2469
  case Side.Bottom:
2404
2470
  newCoordsX = [oldCoordsX[0], oldCoordsX[1]];
2405
2471
  newCoordsY = [oldCoordsY[0], oldCoordsY[1] + distance];
2406
- if (newCoordsY[1] - newCoordsY[0] < this.type.minHeight) {
2407
- newCoordsY[1] = newCoordsY[0] + this.type.minHeight;
2472
+ if (newCoordsY[1] - newCoordsY[0] <
2473
+ (this.node?.type?.sections?.minHeight ||
2474
+ DIAGRAM_SECTION_DEFAULTS.minHeight)) {
2475
+ newCoordsY[1] =
2476
+ newCoordsY[0] +
2477
+ (this.node?.type?.sections?.minHeight ||
2478
+ DIAGRAM_SECTION_DEFAULTS.minHeight);
2408
2479
  }
2409
2480
  break;
2410
2481
  }
@@ -2416,74 +2487,181 @@ class DiagramNode extends DiagramElement {
2416
2487
  }
2417
2488
  if (this.label) {
2418
2489
  this.label.coords = [
2419
- this.coords[0] + (this.type.label?.margin || 0),
2420
- this.coords[1] + (this.type.label?.margin || 0)
2490
+ this.coords[0] + (this.node?.type?.sections?.label?.margin || 0),
2491
+ this.coords[1] + (this.node?.type?.sections?.label?.margin || 0)
2421
2492
  ];
2422
- (this.label.width = this.width - (this.type.label?.margin || 0) * 2),
2423
- (this.label.height = this.height - (this.type.label?.margin || 0) * 2);
2493
+ (this.label.width =
2494
+ this.width - (this.node?.type?.sections?.label?.margin || 0) * 2),
2495
+ (this.label.height =
2496
+ this.height - (this.node?.type?.sections?.label?.margin || 0) * 2);
2424
2497
  }
2425
- // we ignore this.sections, the stretching of a node with sections is handled in the stretchSections method
2426
2498
  this.updateInView();
2427
2499
  }
2428
- stretchSections(direction, distance, point) {
2429
- switch (direction) {
2430
- case Side.Bottom:
2431
- for (const section of this.sections) {
2432
- if (section.coords[1] === point[1]) {
2433
- section.stretch(direction, distance);
2434
- }
2435
- else if (section.coords[1] > point[1]) {
2436
- section.move([section.coords[0], section.coords[1] + distance]);
2437
- }
2438
- }
2439
- break;
2440
- case Side.Right:
2441
- for (const section of this.sections) {
2442
- if (section.coords[0] === point[0]) {
2443
- section.stretch(direction, distance);
2444
- }
2445
- else if (section.coords[0] > point[0]) {
2446
- section.move([section.coords[0] + distance, section.coords[1]]);
2500
+ }
2501
+ class DiagramSectionSet extends DiagramEntitySet {
2502
+ constructor(model) {
2503
+ super();
2504
+ this.model = model;
2505
+ }
2506
+ new(node, coords, width, height, id, portIds, portLabelIds) {
2507
+ const section = new DiagramSection(this.model, node, coords, width, height, id);
2508
+ super.add(section);
2509
+ section.updateInView();
2510
+ // add this section to its node
2511
+ node.sections.push(section);
2512
+ node.updateInView();
2513
+ // add section ports
2514
+ if (node.type.sections?.ports && node.type.sections.ports.length > 0) {
2515
+ for (let i = 0; i < node.type.sections.ports.length; ++i) {
2516
+ const portConfig = node.type.sections.ports[i];
2517
+ const port = this.model.ports.new(section, [
2518
+ section.coords[0] + portConfig.coords[0],
2519
+ section.coords[1] + portConfig.coords[1]
2520
+ ], portConfig.direction, portIds && portIds.length > i ? portIds[i] : undefined);
2521
+ if (portConfig.label) {
2522
+ const labelConfiguration = {
2523
+ ...DIAGRAM_FIELD_DEFAULTS,
2524
+ ...portConfig.label
2525
+ };
2526
+ let labelCoords;
2527
+ switch (port.direction) {
2528
+ case Side.Top:
2529
+ case Side.Left:
2530
+ labelCoords = [
2531
+ port.coords[0] - labelConfiguration.fontSize,
2532
+ port.coords[1] - labelConfiguration.fontSize
2533
+ ];
2534
+ break;
2535
+ case Side.Bottom:
2536
+ labelCoords = [
2537
+ port.coords[0] - labelConfiguration.fontSize,
2538
+ port.coords[1] + labelConfiguration.fontSize
2539
+ ];
2540
+ break;
2541
+ case Side.Right:
2542
+ labelCoords = [
2543
+ port.coords[0] + labelConfiguration.fontSize,
2544
+ port.coords[1] - labelConfiguration.fontSize
2545
+ ];
2546
+ break;
2547
+ default:
2548
+ labelCoords = port.coords;
2447
2549
  }
2550
+ this.model.fields.new(port, labelCoords, labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, labelConfiguration.fontSize, labelConfiguration.fontSize, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, portLabelIds && portLabelIds.length > i
2551
+ ? portLabelIds[i]
2552
+ : undefined);
2448
2553
  }
2449
- break;
2450
- case Side.Top:
2451
- for (const section of this.sections) {
2452
- if (section.coords[1] === point[1]) {
2453
- section.stretch(direction, distance);
2454
- }
2455
- else if (section.coords[1] < point[1]) {
2456
- section.move([section.coords[0], section.coords[1] - distance]);
2457
- }
2554
+ }
2555
+ }
2556
+ // add section label
2557
+ if (node.type.sections?.label) {
2558
+ const labelConfiguration = {
2559
+ ...DIAGRAM_FIELD_DEFAULTS,
2560
+ ...node.type.sections.label
2561
+ };
2562
+ this.model.fields.new(section, [
2563
+ section.coords[0] + labelConfiguration.margin,
2564
+ section.coords[1] + labelConfiguration.margin
2565
+ ], labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, section.width - labelConfiguration.margin * 2, section.height - labelConfiguration.margin * 2, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, id);
2566
+ }
2567
+ return section;
2568
+ }
2569
+ remove(id) {
2570
+ const section = this.get(id);
2571
+ if (section) {
2572
+ // remove all ports
2573
+ while (section.ports.length > 0) {
2574
+ this.model.ports.remove(section.ports[0].id);
2575
+ }
2576
+ // remove label
2577
+ if (section.label) {
2578
+ this.model.fields.remove(section.label.id);
2579
+ }
2580
+ // remove from root element
2581
+ if (section.node) {
2582
+ removeIfExists(section.node.sections, section);
2583
+ }
2584
+ // remove from set of sections
2585
+ super.remove(id);
2586
+ // remove from canvas
2587
+ section.updateInView();
2588
+ }
2589
+ }
2590
+ filter(threshold) {
2591
+ return this.entities.filter((e) => {
2592
+ if (threshold) {
2593
+ const node = e.node;
2594
+ if (node) {
2595
+ return node.type.priority >= threshold;
2458
2596
  }
2459
- break;
2460
- case Side.Left:
2461
- for (const section of this.sections) {
2462
- if (section.coords[0] === point[0]) {
2463
- section.stretch(direction, distance);
2464
- }
2465
- else if (section.coords[0] < point[0]) {
2466
- section.move([section.coords[0] - distance, section.coords[1]]);
2467
- }
2597
+ return false;
2598
+ }
2599
+ return true;
2600
+ });
2601
+ }
2602
+ find(threshold) {
2603
+ return this.entities.find((e) => {
2604
+ if (threshold) {
2605
+ const node = e.node;
2606
+ if (node) {
2607
+ return node.type.priority >= threshold;
2468
2608
  }
2469
- break;
2470
- }
2471
- this.stretch(direction, distance);
2609
+ return false;
2610
+ }
2611
+ return true;
2612
+ });
2472
2613
  }
2473
2614
  }
2474
2615
 
2475
2616
  let idTicker$2 = 0;
2476
- const DIAGRAM_SECTION_DEFAULTS = {
2477
- sectionsX: 1,
2478
- sectionsY: 1,
2617
+ const DIAGRAM_LOOK_DEFAULTS = {
2618
+ lookType: 'shaped-look',
2619
+ shape: ClosedShape.Rectangle,
2620
+ color: '#FFFFFF',
2621
+ borderColor: '#000000',
2622
+ selectedColor: '#FFFFFF',
2623
+ selectedBorderColor: '#000000'
2624
+ };
2625
+ const DIAGRAM_NODE_TYPE_DEFAULTS = {
2626
+ name: '',
2627
+ defaultWidth: 0,
2628
+ defaultHeight: 0,
2479
2629
  minWidth: 0,
2480
2630
  minHeight: 0,
2481
- margin: 0,
2631
+ resizableX: false,
2632
+ resizableY: false,
2482
2633
  label: null,
2483
2634
  ports: [],
2484
- look: DIAGRAM_LOOK_DEFAULTS
2635
+ sections: null,
2636
+ look: DIAGRAM_LOOK_DEFAULTS,
2637
+ isUnique: false,
2638
+ priority: 0,
2639
+ properties: []
2485
2640
  };
2486
- class DiagramSection extends DiagramElement {
2641
+ class DiagramNodeType {
2642
+ constructor(options) {
2643
+ const values = {
2644
+ ...DIAGRAM_NODE_TYPE_DEFAULTS,
2645
+ ...options
2646
+ };
2647
+ this.id = values.id;
2648
+ this.name = values.name;
2649
+ this.defaultWidth = values.defaultWidth;
2650
+ this.defaultHeight = values.defaultHeight;
2651
+ this.minWidth = values.minWidth;
2652
+ this.minHeight = values.minHeight;
2653
+ this.resizableX = values.resizableX;
2654
+ this.resizableY = values.resizableY;
2655
+ this.label = values.label;
2656
+ this.ports = values.ports;
2657
+ this.sections = values.sections;
2658
+ this.look = values.look;
2659
+ this.isUnique = values.isUnique;
2660
+ this.priority = values.priority;
2661
+ this.propertySet = new PropertySet(options?.properties || []);
2662
+ }
2663
+ }
2664
+ class DiagramNode extends DiagramElement {
2487
2665
  get name() {
2488
2666
  return this.label?.text || '';
2489
2667
  }
@@ -2493,26 +2671,29 @@ class DiagramSection extends DiagramElement {
2493
2671
  this.label.updateInView();
2494
2672
  }
2495
2673
  }
2496
- constructor(model, node, coords, width, height, id) {
2674
+ constructor(model, type, coords = [0, 0], id) {
2497
2675
  let uniqueId;
2498
- if (id !== undefined && model.getNode(id) === undefined) {
2676
+ if (id !== undefined && model.nodes.get(id) === undefined) {
2499
2677
  uniqueId = id;
2500
2678
  }
2501
2679
  else {
2502
2680
  do {
2503
- uniqueId = `diagram-section-${++idTicker$2}`;
2504
- } while (model.getNode(uniqueId) !== undefined);
2681
+ uniqueId = `diagram-node-${++idTicker$2}`;
2682
+ } while (model.nodes.get(uniqueId) !== undefined);
2505
2683
  }
2506
2684
  super(model, uniqueId);
2685
+ this.sections = [];
2507
2686
  this.ports = [];
2508
- this.node = node;
2687
+ this.type = type;
2688
+ this.valueSet = new ValueSet(type.propertySet, this);
2689
+ this.originalData = {};
2509
2690
  this.coords = coords;
2510
- this.width = width;
2511
- this.height = height;
2691
+ this.width = type.defaultWidth;
2692
+ this.height = type.defaultHeight;
2512
2693
  }
2513
2694
  updateInView() {
2514
2695
  if (this.model.canvas && this.model.renderToCanvas) {
2515
- this.model.canvas.updateSectionsInView(this.id);
2696
+ this.model.canvas.updateNodesInView(this.id);
2516
2697
  }
2517
2698
  }
2518
2699
  getClosestPortToPoint(coords) {
@@ -2559,12 +2740,36 @@ class DiagramSection extends DiagramElement {
2559
2740
  }
2560
2741
  return result;
2561
2742
  }
2743
+ getAdjacentNodes() {
2744
+ const result = [];
2745
+ for (const port of this.ports) {
2746
+ for (const incomingConnection of port.incomingConnections) {
2747
+ const otherNode = incomingConnection.start?.getNode();
2748
+ if (otherNode) {
2749
+ result.push(otherNode);
2750
+ }
2751
+ }
2752
+ for (const outgoingConnection of port.outgoingConnections) {
2753
+ const otherNode = outgoingConnection.end?.getNode();
2754
+ if (otherNode) {
2755
+ result.push(otherNode);
2756
+ }
2757
+ }
2758
+ }
2759
+ return result;
2760
+ }
2562
2761
  move(coords) {
2563
2762
  const coordDifferences = [
2564
2763
  coords[0] - this.coords[0],
2565
2764
  coords[1] - this.coords[1]
2566
2765
  ];
2567
2766
  this.coords = coords;
2767
+ for (const section of this.sections) {
2768
+ section.move([
2769
+ section.coords[0] + coordDifferences[0],
2770
+ section.coords[1] + coordDifferences[1]
2771
+ ]);
2772
+ }
2568
2773
  for (const port of this.ports) {
2569
2774
  port.move([
2570
2775
  port.coords[0] + coordDifferences[0],
@@ -2589,49 +2794,29 @@ class DiagramSection extends DiagramElement {
2589
2794
  case Side.Left:
2590
2795
  newCoordsX = [oldCoordsX[0] - distance, oldCoordsX[1]];
2591
2796
  newCoordsY = [oldCoordsY[0], oldCoordsY[1]];
2592
- if (newCoordsX[1] - newCoordsX[0] <
2593
- (this.node?.type?.sections?.minWidth ||
2594
- DIAGRAM_SECTION_DEFAULTS.minWidth)) {
2595
- newCoordsX[0] =
2596
- newCoordsX[1] -
2597
- (this.node?.type?.sections?.minWidth ||
2598
- DIAGRAM_SECTION_DEFAULTS.minWidth);
2797
+ if (newCoordsX[1] - newCoordsX[0] < this.type.minWidth) {
2798
+ newCoordsX[0] = newCoordsX[1] - this.type.minWidth;
2599
2799
  }
2600
2800
  break;
2601
2801
  case Side.Top:
2602
2802
  newCoordsX = [oldCoordsX[0], oldCoordsX[1]];
2603
2803
  newCoordsY = [oldCoordsY[0] - distance, oldCoordsY[1]];
2604
- if (newCoordsY[1] - newCoordsY[0] <
2605
- (this.node?.type?.sections?.minHeight ||
2606
- DIAGRAM_SECTION_DEFAULTS.minHeight)) {
2607
- newCoordsY[0] =
2608
- newCoordsY[1] -
2609
- (this.node?.type?.sections?.minHeight ||
2610
- DIAGRAM_SECTION_DEFAULTS.minHeight);
2804
+ if (newCoordsY[1] - newCoordsY[0] < this.type.minHeight) {
2805
+ newCoordsY[0] = newCoordsY[1] - this.type.minHeight;
2611
2806
  }
2612
2807
  break;
2613
2808
  case Side.Right:
2614
2809
  newCoordsX = [oldCoordsX[0], oldCoordsX[1] + distance];
2615
2810
  newCoordsY = [oldCoordsY[0], oldCoordsY[1]];
2616
- if (newCoordsX[1] - newCoordsX[0] <
2617
- (this.node?.type?.sections?.minWidth ||
2618
- DIAGRAM_SECTION_DEFAULTS.minWidth)) {
2619
- newCoordsX[1] =
2620
- newCoordsX[0] +
2621
- (this.node?.type?.sections?.minWidth ||
2622
- DIAGRAM_SECTION_DEFAULTS.minWidth);
2811
+ if (newCoordsX[1] - newCoordsX[0] < this.type.minWidth) {
2812
+ newCoordsX[1] = newCoordsX[0] + this.type.minWidth;
2623
2813
  }
2624
2814
  break;
2625
2815
  case Side.Bottom:
2626
2816
  newCoordsX = [oldCoordsX[0], oldCoordsX[1]];
2627
2817
  newCoordsY = [oldCoordsY[0], oldCoordsY[1] + distance];
2628
- if (newCoordsY[1] - newCoordsY[0] <
2629
- (this.node?.type?.sections?.minHeight ||
2630
- DIAGRAM_SECTION_DEFAULTS.minHeight)) {
2631
- newCoordsY[1] =
2632
- newCoordsY[0] +
2633
- (this.node?.type?.sections?.minHeight ||
2634
- DIAGRAM_SECTION_DEFAULTS.minHeight);
2818
+ if (newCoordsY[1] - newCoordsY[0] < this.type.minHeight) {
2819
+ newCoordsY[1] = newCoordsY[0] + this.type.minHeight;
2635
2820
  }
2636
2821
  break;
2637
2822
  }
@@ -2643,15 +2828,186 @@ class DiagramSection extends DiagramElement {
2643
2828
  }
2644
2829
  if (this.label) {
2645
2830
  this.label.coords = [
2646
- this.coords[0] + (this.node?.type?.sections?.label?.margin || 0),
2647
- this.coords[1] + (this.node?.type?.sections?.label?.margin || 0)
2831
+ this.coords[0] + (this.type.label?.margin || 0),
2832
+ this.coords[1] + (this.type.label?.margin || 0)
2648
2833
  ];
2649
- (this.label.width =
2650
- this.width - (this.node?.type?.sections?.label?.margin || 0) * 2),
2651
- (this.label.height =
2652
- this.height - (this.node?.type?.sections?.label?.margin || 0) * 2);
2834
+ (this.label.width = this.width - (this.type.label?.margin || 0) * 2),
2835
+ (this.label.height = this.height - (this.type.label?.margin || 0) * 2);
2836
+ }
2837
+ // we ignore this.sections, the stretching of a node with sections is handled in the stretchSections method
2838
+ this.updateInView();
2839
+ }
2840
+ stretchSections(direction, distance, point) {
2841
+ switch (direction) {
2842
+ case Side.Bottom:
2843
+ for (const section of this.sections) {
2844
+ if (section.coords[1] === point[1]) {
2845
+ section.stretch(direction, distance);
2846
+ }
2847
+ else if (section.coords[1] > point[1]) {
2848
+ section.move([section.coords[0], section.coords[1] + distance]);
2849
+ }
2850
+ }
2851
+ break;
2852
+ case Side.Right:
2853
+ for (const section of this.sections) {
2854
+ if (section.coords[0] === point[0]) {
2855
+ section.stretch(direction, distance);
2856
+ }
2857
+ else if (section.coords[0] > point[0]) {
2858
+ section.move([section.coords[0] + distance, section.coords[1]]);
2859
+ }
2860
+ }
2861
+ break;
2862
+ case Side.Top:
2863
+ for (const section of this.sections) {
2864
+ if (section.coords[1] === point[1]) {
2865
+ section.stretch(direction, distance);
2866
+ }
2867
+ else if (section.coords[1] < point[1]) {
2868
+ section.move([section.coords[0], section.coords[1] - distance]);
2869
+ }
2870
+ }
2871
+ break;
2872
+ case Side.Left:
2873
+ for (const section of this.sections) {
2874
+ if (section.coords[0] === point[0]) {
2875
+ section.stretch(direction, distance);
2876
+ }
2877
+ else if (section.coords[0] < point[0]) {
2878
+ section.move([section.coords[0] - distance, section.coords[1]]);
2879
+ }
2880
+ }
2881
+ break;
2882
+ }
2883
+ this.stretch(direction, distance);
2884
+ }
2885
+ }
2886
+ class DiagramNodeSet extends DiagramEntitySet {
2887
+ constructor(model) {
2888
+ super();
2889
+ this.types = new DiagramEntitySet();
2890
+ this.model = model;
2891
+ }
2892
+ new(type, coords, id, sectionIds, sectionPortIds, sectionPortLabelIds, portIds, portLabelIds, labelId) {
2893
+ const node = new DiagramNode(this.model, type, coords, id);
2894
+ super.add(node);
2895
+ node.updateInView();
2896
+ // add node sections
2897
+ if (type.sections !== null &&
2898
+ (type.sections.sectionsX || 0) > 0 &&
2899
+ (type.sections.sectionsY || 0) > 0) {
2900
+ const sectionConfiguration = {
2901
+ ...DIAGRAM_SECTION_DEFAULTS,
2902
+ ...type.sections
2903
+ };
2904
+ const sectionsX = sectionConfiguration.sectionsX;
2905
+ const sectionsY = sectionConfiguration.sectionsY;
2906
+ const margin = sectionConfiguration.margin;
2907
+ const widthPerSection = (node.width - margin * (sectionsX + 1)) / sectionsX;
2908
+ const heightPerSection = (node.height - margin * (sectionsY + 1)) / sectionsY;
2909
+ let sectionCount = 0;
2910
+ for (let j = 0; j < sectionsY; ++j) {
2911
+ for (let i = 0; i < sectionsX; ++i) {
2912
+ const coords = [
2913
+ node.coords[0] + margin + i * (widthPerSection + margin),
2914
+ node.coords[1] + margin + j * (heightPerSection + margin)
2915
+ ];
2916
+ this.model.sections.new(node, coords, widthPerSection, heightPerSection, sectionIds && sectionIds.length > sectionCount
2917
+ ? sectionIds[sectionCount]
2918
+ : undefined, sectionPortIds && sectionPortIds.length > sectionCount
2919
+ ? sectionPortIds[sectionCount]
2920
+ : undefined, sectionPortLabelIds && sectionPortLabelIds.length > sectionCount
2921
+ ? sectionPortLabelIds[sectionCount]
2922
+ : undefined);
2923
+ ++sectionCount;
2924
+ }
2925
+ }
2926
+ }
2927
+ // add node ports
2928
+ if (type.ports.length > 0) {
2929
+ for (let i = 0; i < type.ports.length; ++i) {
2930
+ const portConfig = type.ports[i];
2931
+ const port = this.model.ports.new(node, [
2932
+ node.coords[0] + portConfig.coords[0],
2933
+ node.coords[1] + portConfig.coords[1]
2934
+ ], portConfig.direction, portIds && portIds.length > i ? portIds[i] : undefined);
2935
+ if (portConfig.label) {
2936
+ const labelConfiguration = {
2937
+ ...DIAGRAM_FIELD_DEFAULTS,
2938
+ ...portConfig.label
2939
+ };
2940
+ let labelCoords;
2941
+ switch (port.direction) {
2942
+ case Side.Top:
2943
+ case Side.Left:
2944
+ labelCoords = [
2945
+ port.coords[0] - labelConfiguration.fontSize,
2946
+ port.coords[1] - labelConfiguration.fontSize
2947
+ ];
2948
+ break;
2949
+ case Side.Bottom:
2950
+ labelCoords = [
2951
+ port.coords[0] - labelConfiguration.fontSize,
2952
+ port.coords[1] + labelConfiguration.fontSize
2953
+ ];
2954
+ break;
2955
+ case Side.Right:
2956
+ labelCoords = [
2957
+ port.coords[0] + labelConfiguration.fontSize,
2958
+ port.coords[1] - labelConfiguration.fontSize
2959
+ ];
2960
+ break;
2961
+ default:
2962
+ labelCoords = port.coords;
2963
+ }
2964
+ this.model.fields.new(port, labelCoords, labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, labelConfiguration.fontSize, labelConfiguration.fontSize, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, portLabelIds && portLabelIds.length > i
2965
+ ? portLabelIds[i]
2966
+ : undefined);
2967
+ }
2968
+ }
2653
2969
  }
2654
- this.updateInView();
2970
+ // add node label
2971
+ if (type.label) {
2972
+ const labelConfiguration = {
2973
+ ...DIAGRAM_FIELD_DEFAULTS,
2974
+ ...type.label
2975
+ };
2976
+ this.model.fields.new(node, [
2977
+ node.coords[0] + labelConfiguration.margin,
2978
+ node.coords[1] + labelConfiguration.margin
2979
+ ], labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, node.width - labelConfiguration.margin * 2, node.height - labelConfiguration.margin * 2, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, labelId);
2980
+ }
2981
+ return node;
2982
+ }
2983
+ remove(id) {
2984
+ const node = this.get(id);
2985
+ if (node) {
2986
+ // remove all sections
2987
+ while (node.sections.length > 0) {
2988
+ this.model.sections.remove(node.sections[0].id);
2989
+ }
2990
+ // remove all ports
2991
+ while (node.ports.length > 0) {
2992
+ this.model.ports.remove(node.ports[0].id);
2993
+ }
2994
+ // remove label
2995
+ if (node.label) {
2996
+ this.model.fields.remove(node.label.id);
2997
+ }
2998
+ // remove from set of nodes
2999
+ super.remove(id);
3000
+ // remove from canvas
3001
+ node.updateInView();
3002
+ }
3003
+ }
3004
+ filter(type, threshold) {
3005
+ return this.entities.filter((e) => (type ? e.type.id === type : true) &&
3006
+ (threshold ? e.type.priority >= threshold : true));
3007
+ }
3008
+ find(type, threshold) {
3009
+ return this.entities.find((e) => (type ? e.type.id === type : true) &&
3010
+ (threshold ? e.type.priority >= threshold : true));
2655
3011
  }
2656
3012
  }
2657
3013
 
@@ -2664,13 +3020,13 @@ const DIAGRAM_PORT_DEFAULTS = {
2664
3020
  class DiagramPort extends DiagramElement {
2665
3021
  constructor(model, rootElement, coords, direction, id) {
2666
3022
  let uniqueId;
2667
- if (id !== undefined && model.getPort(id) === undefined) {
3023
+ if (id !== undefined && model.ports.get(id) === undefined) {
2668
3024
  uniqueId = id;
2669
3025
  }
2670
3026
  else {
2671
3027
  do {
2672
3028
  uniqueId = `diagram-port-${++idTicker$1}`;
2673
- } while (model.getPort(uniqueId) !== undefined);
3029
+ } while (model.ports.get(uniqueId) !== undefined);
2674
3030
  }
2675
3031
  super(model, uniqueId);
2676
3032
  this.outgoingConnections = [];
@@ -2723,6 +3079,71 @@ class DiagramPort extends DiagramElement {
2723
3079
  return distanceBetweenPoints(this.coords, coords);
2724
3080
  }
2725
3081
  }
3082
+ class DiagramPortSet extends DiagramEntitySet {
3083
+ constructor(model) {
3084
+ super();
3085
+ this.model = model;
3086
+ }
3087
+ new(rootElement, coords, direction, id) {
3088
+ const port = new DiagramPort(this.model, rootElement, coords, direction, id);
3089
+ super.add(port);
3090
+ port.updateInView();
3091
+ // add this port to its root element
3092
+ if (rootElement !== undefined) {
3093
+ rootElement.ports.push(port);
3094
+ }
3095
+ return port;
3096
+ }
3097
+ remove(id) {
3098
+ const port = this.get(id);
3099
+ if (port) {
3100
+ // remove all connections
3101
+ while (port.outgoingConnections.length > 0) {
3102
+ this.model.connections.remove(port.outgoingConnections[0].id);
3103
+ }
3104
+ while (port.incomingConnections.length > 0) {
3105
+ this.model.connections.remove(port.incomingConnections[0].id);
3106
+ }
3107
+ // remove label
3108
+ if (port.label) {
3109
+ this.model.fields.remove(port.label.id);
3110
+ }
3111
+ // remove from root element
3112
+ if (port.rootElement instanceof DiagramNode ||
3113
+ port.rootElement instanceof DiagramSection) {
3114
+ removeIfExists(port.rootElement.ports, port);
3115
+ }
3116
+ // remove from set of ports
3117
+ super.remove(id);
3118
+ // remove from canvas
3119
+ port.updateInView();
3120
+ }
3121
+ }
3122
+ filter(threshold) {
3123
+ return this.entities.filter((e) => {
3124
+ if (threshold) {
3125
+ const node = e.getNode();
3126
+ if (node) {
3127
+ return node !== undefined && node.type.priority >= threshold;
3128
+ }
3129
+ return false;
3130
+ }
3131
+ return true;
3132
+ });
3133
+ }
3134
+ find(threshold) {
3135
+ return this.entities.find((e) => {
3136
+ if (threshold) {
3137
+ const node = e.getNode();
3138
+ if (node) {
3139
+ return node !== undefined && node.type.priority >= threshold;
3140
+ }
3141
+ return false;
3142
+ }
3143
+ return true;
3144
+ });
3145
+ }
3146
+ }
2726
3147
 
2727
3148
  let idTicker = 0;
2728
3149
  const DIAGRAM_FIELD_DEFAULTS = {
@@ -2749,13 +3170,13 @@ class DiagramField extends DiagramElement {
2749
3170
  }
2750
3171
  constructor(model, rootElement, coords, width, height, fontSize, fontFamily, color, selectedColor, horizontalAlign, verticalAlign, text, editable, id) {
2751
3172
  let uniqueId;
2752
- if (id !== undefined && model.getField(id) === undefined) {
3173
+ if (id !== undefined && model.fields.get(id) === undefined) {
2753
3174
  uniqueId = id;
2754
3175
  }
2755
3176
  else {
2756
3177
  do {
2757
3178
  uniqueId = `diagram-field-${++idTicker}`;
2758
- } while (model.getField(uniqueId) !== undefined);
3179
+ } while (model.fields.get(uniqueId) !== undefined);
2759
3180
  }
2760
3181
  super(model, uniqueId);
2761
3182
  this.rootElement = rootElement;
@@ -2794,6 +3215,57 @@ class DiagramField extends DiagramElement {
2794
3215
  return undefined;
2795
3216
  }
2796
3217
  }
3218
+ class DiagramFieldSet extends DiagramEntitySet {
3219
+ constructor(model) {
3220
+ super();
3221
+ this.model = model;
3222
+ }
3223
+ new(rootElement, coords, fontSize, fontFamily, color, selectedColor, width, height, horizontalAlign, verticalAlign, text, editable, id) {
3224
+ const field = new DiagramField(this.model, rootElement, coords, width, height, fontSize, fontFamily, color, selectedColor, horizontalAlign, verticalAlign, text, editable, id);
3225
+ super.add(field);
3226
+ field.updateInView();
3227
+ // add this field to its root element
3228
+ if (rootElement !== undefined) {
3229
+ rootElement.label = field;
3230
+ }
3231
+ return field;
3232
+ }
3233
+ remove(id) {
3234
+ const field = this.get(id);
3235
+ if (field) {
3236
+ // remove from root element
3237
+ if (field.rootElement instanceof DiagramNode ||
3238
+ field.rootElement instanceof DiagramSection ||
3239
+ field.rootElement instanceof DiagramPort) {
3240
+ if (field.rootElement.label === field) {
3241
+ field.rootElement.label = undefined;
3242
+ }
3243
+ }
3244
+ // remove from set of fields
3245
+ super.remove(id);
3246
+ // remove from canvas
3247
+ field.updateInView();
3248
+ }
3249
+ }
3250
+ filter(threshold) {
3251
+ return this.entities.filter((e) => {
3252
+ if (threshold) {
3253
+ const node = e.getClosestNode();
3254
+ return node !== undefined && node.type.priority >= threshold;
3255
+ }
3256
+ return true;
3257
+ });
3258
+ }
3259
+ find(threshold) {
3260
+ return this.entities.find((e) => {
3261
+ if (threshold) {
3262
+ const node = e.getClosestNode();
3263
+ return node !== undefined && node.type.priority >= threshold;
3264
+ }
3265
+ return true;
3266
+ });
3267
+ }
3268
+ }
2797
3269
 
2798
3270
  class DiagramModel {
2799
3271
  // canvas attribute accesors
@@ -2808,13 +3280,11 @@ class DiagramModel {
2808
3280
  }
2809
3281
  constructor(canvas, id, name, description, type, properties = []) {
2810
3282
  this.renderToCanvas = true;
2811
- this.nodeTypes = [];
2812
- this.connectionTypes = [];
2813
- this.nodes = [];
2814
- this.sections = [];
2815
- this.ports = [];
2816
- this.connections = [];
2817
- this.fields = [];
3283
+ this.nodes = new DiagramNodeSet(this);
3284
+ this.sections = new DiagramSectionSet(this);
3285
+ this.ports = new DiagramPortSet(this);
3286
+ this.connections = new DiagramConnectionSet(this);
3287
+ this.fields = new DiagramFieldSet(this);
2818
3288
  this.canvas = canvas;
2819
3289
  this.id = id;
2820
3290
  this.name = name;
@@ -2838,390 +3308,29 @@ class DiagramModel {
2838
3308
  this.id = undefined;
2839
3309
  this.name = '';
2840
3310
  this.description = undefined;
2841
- this.nodes = [];
2842
- this.ports = [];
2843
- this.connections = [];
2844
- this.fields = [];
2845
3311
  this.createdAt = new Date();
2846
3312
  this.updatedAt = new Date();
3313
+ this.nodes.clear();
3314
+ this.sections.clear();
3315
+ this.ports.clear();
3316
+ this.connections.clear();
3317
+ this.fields.clear();
2847
3318
  this.valueSet.resetValues();
2848
3319
  if (this.renderToCanvas) {
2849
3320
  this.canvas?.cancelAllUserActions();
2850
3321
  this.canvas?.updateModelInView();
2851
3322
  }
2852
3323
  }
2853
- getElement(id) {
2854
- return (this.getNode(id) ||
2855
- this.getSection(id) ||
2856
- this.getPort(id) ||
2857
- this.getConnection(id) ||
2858
- this.getField(id));
2859
- }
2860
- deleteElement(element) {
2861
- if (element instanceof DiagramNode) {
2862
- this.deleteNode(element);
2863
- }
2864
- else if (element instanceof DiagramSection) {
2865
- this.deleteSection(element);
2866
- }
2867
- else if (element instanceof DiagramPort) {
2868
- this.deletePort(element);
2869
- }
2870
- else if (element instanceof DiagramConnection) {
2871
- this.deleteConnection(element);
2872
- }
2873
- else if (element instanceof DiagramField) {
2874
- this.deleteField(element);
2875
- }
2876
- }
2877
- getNodeType(name) {
2878
- return this.nodeTypes.find((e) => e.id === name);
2879
- }
2880
- getConnectionType(name) {
2881
- return this.connectionTypes.find((e) => e.id === name);
2882
- }
2883
- getNode(id) {
2884
- return this.nodes.find((e) => e.id === id);
2885
- }
2886
- getNodes(threshold) {
2887
- if (threshold === undefined) {
2888
- return this.nodes;
2889
- }
2890
- else {
2891
- return this.nodes.filter((e) => e.type.priority >= threshold);
2892
- }
2893
- }
2894
- getNodesOfType(type) {
2895
- return this.nodes.filter((e) => e.type.id === type);
2896
- }
2897
- addNode(type, coords, id, sectionIds, sectionPortIds, sectionPortLabelIds, portIds, portLabelIds, labelId) {
2898
- const newNode = new DiagramNode(this, type, coords, id);
2899
- this.nodes.push(newNode);
2900
- newNode.updateInView();
2901
- // add node sections
2902
- if (type.sections !== null &&
2903
- (type.sections.sectionsX || 0) > 0 &&
2904
- (type.sections.sectionsY || 0) > 0) {
2905
- const sectionConfiguration = {
2906
- ...DIAGRAM_SECTION_DEFAULTS,
2907
- ...type.sections
2908
- };
2909
- const sectionsX = sectionConfiguration.sectionsX;
2910
- const sectionsY = sectionConfiguration.sectionsY;
2911
- const margin = sectionConfiguration.margin;
2912
- const widthPerSection = (newNode.width - margin * (sectionsX + 1)) / sectionsX;
2913
- const heightPerSection = (newNode.height - margin * (sectionsY + 1)) / sectionsY;
2914
- let sectionCount = 0;
2915
- for (let j = 0; j < sectionsY; ++j) {
2916
- for (let i = 0; i < sectionsX; ++i) {
2917
- const coords = [
2918
- newNode.coords[0] + margin + i * (widthPerSection + margin),
2919
- newNode.coords[1] + margin + j * (heightPerSection + margin)
2920
- ];
2921
- this.addSection(newNode, coords, widthPerSection, heightPerSection, sectionIds && sectionIds.length > sectionCount
2922
- ? sectionIds[sectionCount]
2923
- : undefined, sectionPortIds && sectionPortIds.length > sectionCount
2924
- ? sectionPortIds[sectionCount]
2925
- : undefined, sectionPortLabelIds && sectionPortLabelIds.length > sectionCount
2926
- ? sectionPortLabelIds[sectionCount]
2927
- : undefined);
2928
- ++sectionCount;
2929
- }
2930
- }
2931
- }
2932
- // add node ports
2933
- if (type.ports.length > 0) {
2934
- for (let i = 0; i < type.ports.length; ++i) {
2935
- const portConfig = type.ports[i];
2936
- const newPort = this.addPort(newNode, [
2937
- newNode.coords[0] + portConfig.coords[0],
2938
- newNode.coords[1] + portConfig.coords[1]
2939
- ], portConfig.direction, portIds && portIds.length > i ? portIds[i] : undefined);
2940
- if (portConfig.label) {
2941
- const labelConfiguration = {
2942
- ...DIAGRAM_FIELD_DEFAULTS,
2943
- ...portConfig.label
2944
- };
2945
- let labelCoords;
2946
- switch (newPort.direction) {
2947
- case Side.Top:
2948
- case Side.Left:
2949
- labelCoords = [
2950
- newPort.coords[0] - labelConfiguration.fontSize,
2951
- newPort.coords[1] - labelConfiguration.fontSize
2952
- ];
2953
- break;
2954
- case Side.Bottom:
2955
- labelCoords = [
2956
- newPort.coords[0] - labelConfiguration.fontSize,
2957
- newPort.coords[1] + labelConfiguration.fontSize
2958
- ];
2959
- break;
2960
- case Side.Right:
2961
- labelCoords = [
2962
- newPort.coords[0] + labelConfiguration.fontSize,
2963
- newPort.coords[1] - labelConfiguration.fontSize
2964
- ];
2965
- break;
2966
- default:
2967
- labelCoords = newPort.coords;
2968
- }
2969
- const newField = this.addField(newPort, labelCoords, labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, labelConfiguration.fontSize, labelConfiguration.fontSize, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, portLabelIds && portLabelIds.length > i
2970
- ? portLabelIds[i]
2971
- : undefined);
2972
- newPort.label = newField;
2973
- }
2974
- }
2975
- }
2976
- // add node label
2977
- if (type.label) {
2978
- const labelConfiguration = {
2979
- ...DIAGRAM_FIELD_DEFAULTS,
2980
- ...type.label
2981
- };
2982
- const newField = this.addField(newNode, [
2983
- newNode.coords[0] + labelConfiguration.margin,
2984
- newNode.coords[1] + labelConfiguration.margin
2985
- ], labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, newNode.width - labelConfiguration.margin * 2, newNode.height - labelConfiguration.margin * 2, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, labelId);
2986
- newNode.label = newField;
2987
- }
2988
- return newNode;
2989
- }
2990
- deleteNode(node) {
2991
- // remove all ports
2992
- while (node.sections.length > 0) {
2993
- this.deleteSection(node.sections[0]);
2994
- }
2995
- while (node.ports.length > 0) {
2996
- this.deletePort(node.ports[0]);
2997
- }
2998
- if (node.label) {
2999
- this.deleteField(node.label);
3000
- }
3001
- // remove from list of nodes
3002
- removeIfExists(this.nodes, node);
3003
- node.updateInView();
3004
- }
3005
- hasNodeOfType(type) {
3006
- return this.nodes.find((e) => e.type.id === type) !== undefined;
3007
- }
3008
- getSection(id) {
3009
- return this.sections.find((e) => e.id === id);
3010
- }
3011
- getSections(threshold) {
3012
- if (threshold === undefined) {
3013
- return this.sections;
3014
- }
3015
- else {
3016
- return this.sections.filter((e) => (e.node?.type?.priority || Number.NEGATIVE_INFINITY) >= threshold);
3017
- }
3018
- }
3019
- addSection(node, coords, width, height, id, portIds, portLabelIds) {
3020
- const newSection = new DiagramSection(this, node, coords, width, height, id);
3021
- this.sections.push(newSection);
3022
- newSection.updateInView();
3023
- // add to node
3024
- node.sections.push(newSection);
3025
- node.updateInView();
3026
- // add section ports
3027
- if (node.type.sections?.ports && node.type.sections.ports.length > 0) {
3028
- for (let i = 0; i < node.type.sections.ports.length; ++i) {
3029
- const portConfig = node.type.sections.ports[i];
3030
- const newPort = this.addPort(newSection, [
3031
- newSection.coords[0] + portConfig.coords[0],
3032
- newSection.coords[1] + portConfig.coords[1]
3033
- ], portConfig.direction, portIds && portIds.length > i ? portIds[i] : undefined);
3034
- if (portConfig.label) {
3035
- const labelConfiguration = {
3036
- ...DIAGRAM_FIELD_DEFAULTS,
3037
- ...portConfig.label
3038
- };
3039
- let labelCoords;
3040
- switch (newPort.direction) {
3041
- case Side.Top:
3042
- case Side.Left:
3043
- labelCoords = [
3044
- newPort.coords[0] - labelConfiguration.fontSize,
3045
- newPort.coords[1] - labelConfiguration.fontSize
3046
- ];
3047
- break;
3048
- case Side.Bottom:
3049
- labelCoords = [
3050
- newPort.coords[0] - labelConfiguration.fontSize,
3051
- newPort.coords[1] + labelConfiguration.fontSize
3052
- ];
3053
- break;
3054
- case Side.Right:
3055
- labelCoords = [
3056
- newPort.coords[0] + labelConfiguration.fontSize,
3057
- newPort.coords[1] - labelConfiguration.fontSize
3058
- ];
3059
- break;
3060
- default:
3061
- labelCoords = newPort.coords;
3062
- }
3063
- const newField = this.addField(newPort, labelCoords, labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, labelConfiguration.fontSize, labelConfiguration.fontSize, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, portLabelIds && portLabelIds.length > i
3064
- ? portLabelIds[i]
3065
- : undefined);
3066
- newPort.label = newField;
3067
- }
3068
- }
3069
- }
3070
- // add section label
3071
- if (node.type.sections?.label) {
3072
- const labelConfiguration = {
3073
- ...DIAGRAM_FIELD_DEFAULTS,
3074
- ...node.type.sections.label
3075
- };
3076
- const newField = this.addField(newSection, [
3077
- newSection.coords[0] + labelConfiguration.margin,
3078
- newSection.coords[1] + labelConfiguration.margin
3079
- ], labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, newSection.width - labelConfiguration.margin * 2, newSection.height - labelConfiguration.margin * 2, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable, id);
3080
- newSection.label = newField;
3081
- }
3082
- return newSection;
3083
- }
3084
- deleteSection(section) {
3085
- // remove all ports
3086
- while (section.ports.length > 0) {
3087
- this.deletePort(section.ports[0]);
3088
- }
3089
- if (section.label) {
3090
- this.deleteField(section.label);
3091
- }
3092
- // remove from list of sections
3093
- if (section.node) {
3094
- removeIfExists(section.node?.sections, section);
3095
- }
3096
- removeIfExists(this.sections, section);
3097
- section.updateInView();
3098
- }
3099
- getPort(id) {
3100
- return this.ports.find((e) => e.id === id);
3101
- }
3102
- getPorts(threshold) {
3103
- if (threshold === undefined) {
3104
- return this.ports;
3105
- }
3106
- else {
3107
- return this.ports.filter((e) => (e.getNode()?.type?.priority || Number.NEGATIVE_INFINITY) >= threshold);
3108
- }
3109
- }
3110
- addPort(rootElement, coords, direction, id) {
3111
- const newPort = new DiagramPort(this, rootElement, coords, direction, id);
3112
- this.ports.push(newPort);
3113
- if (rootElement instanceof DiagramNode) {
3114
- rootElement.ports.push(newPort);
3115
- }
3116
- else if (rootElement instanceof DiagramSection) {
3117
- rootElement.ports.push(newPort);
3118
- }
3119
- newPort.updateInView();
3120
- return newPort;
3121
- }
3122
- deletePort(port) {
3123
- // remove all connections
3124
- while (port.outgoingConnections.length > 0) {
3125
- this.deleteConnection(port.outgoingConnections[0]);
3126
- }
3127
- while (port.incomingConnections.length > 0) {
3128
- this.deleteConnection(port.incomingConnections[0]);
3129
- }
3130
- // remove label
3131
- if (port.label) {
3132
- this.deleteField(port.label);
3133
- }
3134
- // remove from lists of ports
3135
- if (port.rootElement instanceof DiagramNode) {
3136
- removeIfExists(port.rootElement.ports, port);
3137
- }
3138
- else if (port.rootElement instanceof DiagramSection) {
3139
- removeIfExists(port.rootElement.ports, port);
3140
- }
3141
- removeIfExists(this.ports, port);
3142
- // remove from canvas
3143
- port.updateInView();
3144
- }
3145
- getConnection(id) {
3146
- return this.connections.find((e) => e.id === id);
3147
- }
3148
- getConnections(threshold) {
3149
- if (threshold === undefined) {
3150
- return this.connections;
3151
- }
3152
- else {
3153
- return this.connections.filter((e) => (e.start?.getNode()?.type?.priority || Number.NEGATIVE_INFINITY) >=
3154
- threshold &&
3155
- (e.end?.getNode()?.type?.priority || Number.NEGATIVE_INFINITY) >=
3156
- threshold);
3157
- }
3158
- }
3159
- getConnectionsOfType(type) {
3160
- return this.connections.filter((e) => e.type.id === type);
3161
- }
3162
- addConnection(type, start, end, id) {
3163
- const newConnection = new DiagramConnection(this, type, start, end, id);
3164
- this.connections.push(newConnection);
3165
- newConnection.updateInView();
3166
- return newConnection;
3167
- }
3168
- deleteConnection(connection) {
3169
- // remove port labels
3170
- if (connection.start?.label) {
3171
- this.deleteField(connection.start.label);
3172
- }
3173
- if (connection.end?.label) {
3174
- this.deleteField(connection.end.label);
3175
- }
3176
- // remove from lists of connections
3177
- removeIfExists(connection.start?.outgoingConnections || [], connection);
3178
- removeIfExists(connection.end?.incomingConnections || [], connection);
3179
- removeIfExists(this.connections, connection);
3180
- // remove from canvas
3181
- connection.updateInView();
3182
- }
3183
- getField(id) {
3184
- return this.fields.find((e) => e.id === id);
3185
- }
3186
- getFields(threshold) {
3187
- if (threshold === undefined) {
3188
- return this.fields;
3189
- }
3190
- else {
3191
- return this.fields.filter((e) => {
3192
- const node = e.getClosestNode();
3193
- return node !== undefined && node.type.priority >= threshold;
3194
- });
3195
- }
3196
- }
3197
- addField(rootElement, coords, fontSize, fontFamily, color, selectedColor, width, height, horizontalAlign, verticalAlign, text, editable, id) {
3198
- const newField = new DiagramField(this, rootElement, coords, width, height, fontSize, fontFamily, color, selectedColor, horizontalAlign, verticalAlign, text, editable, id);
3199
- this.fields.push(newField);
3200
- newField.updateInView();
3201
- return newField;
3202
- }
3203
- deleteField(field) {
3204
- // remove from lists of fields
3205
- removeIfExists(this.fields, field);
3206
- if (field.rootElement instanceof DiagramNode) {
3207
- if (field.rootElement.label === field) {
3208
- field.rootElement.label = undefined;
3209
- }
3210
- }
3211
- else if (field.rootElement instanceof DiagramPort) {
3212
- if (field.rootElement.label === field) {
3213
- field.rootElement.label = undefined;
3214
- }
3215
- }
3216
- // remove from canvas
3217
- field.updateInView();
3218
- }
3219
3324
  }
3220
3325
 
3221
3326
  /**
3222
3327
  * Thickness of the invisible path around a connection used to make it easier to click on, in pixels.
3223
3328
  */
3224
3329
  const CONNECTION_PATH_BOX_THICKNESS = 12;
3330
+ /**
3331
+ * Thickness of the resizer line used to resize nodes and sections on drag, in pixels.
3332
+ */
3333
+ const RESIZER_THICKNESS = 6;
3225
3334
  /**
3226
3335
  * Text to display as the title of the property editor when editing this diagram's properties.
3227
3336
  * @see PropertyEditorComponent
@@ -3264,7 +3373,7 @@ class DiagramCanvas {
3264
3373
  ...config.nodeTypeDefaults,
3265
3374
  ...nodeTypeConfig
3266
3375
  });
3267
- this.model.nodeTypes.push(nodeType);
3376
+ this.model.nodes.types.add(nodeType);
3268
3377
  }
3269
3378
  }
3270
3379
  // load connection types
@@ -3274,11 +3383,11 @@ class DiagramCanvas {
3274
3383
  ...config.connectionTypeDefaults,
3275
3384
  ...connectionTypeConfig
3276
3385
  });
3277
- this.model.connectionTypes.push(connectionType);
3386
+ this.model.connections.types.add(connectionType);
3278
3387
  }
3279
3388
  this.connectionType =
3280
3389
  config.defaultConnection !== undefined
3281
- ? this.model.getConnectionType(config.defaultConnection)
3390
+ ? this.model.connections.types.get(config.defaultConnection)
3282
3391
  : undefined;
3283
3392
  }
3284
3393
  }
@@ -3295,11 +3404,9 @@ class DiagramCanvas {
3295
3404
  this.diagramRoot = d3.select(appendTo).append('div').node();
3296
3405
  d3.select(this.diagramRoot)
3297
3406
  .attr('tabindex', 0) // make element focusable
3298
- .style('position', 'absolute')
3299
3407
  .style('width', '100%')
3300
3408
  .style('height', '100%')
3301
3409
  .append('svg')
3302
- .style('position', 'absolute')
3303
3410
  .style('width', '100%')
3304
3411
  .style('height', '100%');
3305
3412
  d3.select(this.diagramRoot)
@@ -3456,13 +3563,13 @@ class DiagramCanvas {
3456
3563
  // if there are no nodes, we have nothing to do here
3457
3564
  if (this.model.nodes.length > 0) {
3458
3565
  const canvasViewBoundingBox = this.selectCanvasView().select('rect').node().getBBox();
3459
- const minimumX = Math.min(...this.model.nodes.map((n) => n.coords[0]));
3460
- const maximumX = Math.max(...this.model.nodes.map((n) => n.coords[0] + n.width));
3566
+ const minimumX = Math.min(...this.model.nodes.all().map((n) => n.coords[0]));
3567
+ const maximumX = Math.max(...this.model.nodes.all().map((n) => n.coords[0] + n.width));
3461
3568
  const averageX = (minimumX + maximumX) / 2;
3462
3569
  const rangeX = maximumX - minimumX;
3463
3570
  const windowRangeX = canvasViewBoundingBox.width;
3464
- const minimumY = Math.min(...this.model.nodes.map((n) => n.coords[1]));
3465
- const maximumY = Math.max(...this.model.nodes.map((n) => n.coords[1] + n.height));
3571
+ const minimumY = Math.min(...this.model.nodes.all().map((n) => n.coords[1]));
3572
+ const maximumY = Math.max(...this.model.nodes.all().map((n) => n.coords[1] + n.height));
3466
3573
  const averageY = (minimumY + maximumY) / 2;
3467
3574
  const rangeY = maximumY - minimumY;
3468
3575
  const windowRangeY = canvasViewBoundingBox.height;
@@ -3524,7 +3631,7 @@ class DiagramCanvas {
3524
3631
  updateNodesInView(...ids) {
3525
3632
  let updateSelection = this.selectCanvas()
3526
3633
  .selectAll('g.diagram-node')
3527
- .data(this.model.getNodes(this.priorityThreshold), (d) => d.id);
3634
+ .data(this.model.nodes.filter(undefined, this.priorityThreshold), (d) => d.id);
3528
3635
  const exitSelection = updateSelection.exit();
3529
3636
  const enterSelection = updateSelection
3530
3637
  .enter()
@@ -3643,7 +3750,7 @@ class DiagramCanvas {
3643
3750
  .append('line')
3644
3751
  .attr('class', 'left-resizer')
3645
3752
  .attr('stroke', 'transparent')
3646
- .attr('stroke-width', '5px')
3753
+ .attr('stroke-width', `${RESIZER_THICKNESS}px`)
3647
3754
  .on(Events.MouseOver, (event, d) => {
3648
3755
  if (d.type.resizableX) {
3649
3756
  d3.select('body').style('cursor', 'ew-resize');
@@ -3686,7 +3793,7 @@ class DiagramCanvas {
3686
3793
  .append('line')
3687
3794
  .attr('class', 'top-resizer')
3688
3795
  .attr('stroke', 'transparent')
3689
- .attr('stroke-width', '5px')
3796
+ .attr('stroke-width', `${RESIZER_THICKNESS}px`)
3690
3797
  .on(Events.MouseOver, (event, d) => {
3691
3798
  if (d.type.resizableY) {
3692
3799
  d3.select('body').style('cursor', 'ns-resize');
@@ -3729,7 +3836,7 @@ class DiagramCanvas {
3729
3836
  .append('line')
3730
3837
  .attr('class', 'right-resizer')
3731
3838
  .attr('stroke', 'transparent')
3732
- .attr('stroke-width', '5px')
3839
+ .attr('stroke-width', `${RESIZER_THICKNESS}px`)
3733
3840
  .on(Events.MouseOver, (event, d) => {
3734
3841
  if (d.type.resizableX) {
3735
3842
  d3.select('body').style('cursor', 'ew-resize');
@@ -3772,7 +3879,7 @@ class DiagramCanvas {
3772
3879
  .append('line')
3773
3880
  .attr('class', 'bottom-resizer')
3774
3881
  .attr('stroke', 'transparent')
3775
- .attr('stroke-width', '5px')
3882
+ .attr('stroke-width', `${RESIZER_THICKNESS}px`)
3776
3883
  .on(Events.MouseOver, (event, d) => {
3777
3884
  if (d.type.resizableY) {
3778
3885
  d3.select('body').style('cursor', 'ns-resize');
@@ -3945,8 +4052,8 @@ class DiagramCanvas {
3945
4052
  mergeSelection
3946
4053
  .filter('.resizable-x')
3947
4054
  .select('line.left-resizer')
3948
- .attr('x1', 0)
3949
- .attr('x2', 0)
4055
+ .attr('x1', RESIZER_THICKNESS / 2)
4056
+ .attr('x2', RESIZER_THICKNESS / 2)
3950
4057
  .attr('y1', 0)
3951
4058
  .attr('y2', (d) => d.height);
3952
4059
  mergeSelection
@@ -3954,13 +4061,13 @@ class DiagramCanvas {
3954
4061
  .select('line.top-resizer')
3955
4062
  .attr('x1', 0)
3956
4063
  .attr('x2', (d) => d.width)
3957
- .attr('y1', 0)
3958
- .attr('y2', 0);
4064
+ .attr('y1', RESIZER_THICKNESS / 2)
4065
+ .attr('y2', RESIZER_THICKNESS / 2);
3959
4066
  mergeSelection
3960
4067
  .filter('.resizable-x')
3961
4068
  .select('line.right-resizer')
3962
- .attr('x1', (d) => d.width)
3963
- .attr('x2', (d) => d.width)
4069
+ .attr('x1', (d) => d.width - RESIZER_THICKNESS / 2)
4070
+ .attr('x2', (d) => d.width - RESIZER_THICKNESS / 2)
3964
4071
  .attr('y1', 0)
3965
4072
  .attr('y2', (d) => d.height);
3966
4073
  mergeSelection
@@ -3968,13 +4075,13 @@ class DiagramCanvas {
3968
4075
  .select('line.bottom-resizer')
3969
4076
  .attr('x1', 0)
3970
4077
  .attr('x2', (d) => d.width)
3971
- .attr('y1', (d) => d.height)
3972
- .attr('y2', (d) => d.height);
4078
+ .attr('y1', (d) => d.height - RESIZER_THICKNESS / 2)
4079
+ .attr('y2', (d) => d.height - RESIZER_THICKNESS / 2);
3973
4080
  }
3974
4081
  updateSectionsInView(...ids) {
3975
4082
  let updateSelection = this.selectCanvas()
3976
4083
  .selectAll('g.diagram-section')
3977
- .data(this.model.getSections(this.priorityThreshold), (d) => d.id);
4084
+ .data(this.model.sections.filter(this.priorityThreshold), (d) => d.id);
3978
4085
  const exitSelection = updateSelection.exit();
3979
4086
  const enterSelection = updateSelection
3980
4087
  .enter()
@@ -4096,7 +4203,7 @@ class DiagramCanvas {
4096
4203
  .append('line')
4097
4204
  .attr('class', 'left-resizer')
4098
4205
  .attr('stroke', 'transparent')
4099
- .attr('stroke-width', '5px')
4206
+ .attr('stroke-width', `${RESIZER_THICKNESS}px`)
4100
4207
  .on(Events.MouseOver, (event, d) => {
4101
4208
  if (d.node?.type?.resizableX) {
4102
4209
  d3.select('body').style('cursor', 'ew-resize');
@@ -4139,7 +4246,7 @@ class DiagramCanvas {
4139
4246
  .append('line')
4140
4247
  .attr('class', 'top-resizer')
4141
4248
  .attr('stroke', 'transparent')
4142
- .attr('stroke-width', '5px')
4249
+ .attr('stroke-width', `${RESIZER_THICKNESS}px`)
4143
4250
  .on(Events.MouseOver, (event, d) => {
4144
4251
  if (d.node?.type?.resizableY) {
4145
4252
  d3.select('body').style('cursor', 'ns-resize');
@@ -4182,7 +4289,7 @@ class DiagramCanvas {
4182
4289
  .append('line')
4183
4290
  .attr('class', 'right-resizer')
4184
4291
  .attr('stroke', 'transparent')
4185
- .attr('stroke-width', '5px')
4292
+ .attr('stroke-width', `${RESIZER_THICKNESS}px`)
4186
4293
  .on(Events.MouseOver, (event, d) => {
4187
4294
  if (d.node?.type?.resizableX) {
4188
4295
  d3.select('body').style('cursor', 'ew-resize');
@@ -4225,7 +4332,7 @@ class DiagramCanvas {
4225
4332
  .append('line')
4226
4333
  .attr('class', 'bottom-resizer')
4227
4334
  .attr('stroke', 'transparent')
4228
- .attr('stroke-width', '5px')
4335
+ .attr('stroke-width', `${RESIZER_THICKNESS}px`)
4229
4336
  .on(Events.MouseOver, (event, d) => {
4230
4337
  if (d.node?.type?.resizableY) {
4231
4338
  d3.select('body').style('cursor', 'ns-resize');
@@ -4427,8 +4534,8 @@ class DiagramCanvas {
4427
4534
  mergeSelection
4428
4535
  .filter('.resizable-x')
4429
4536
  .select('line.left-resizer')
4430
- .attr('x1', 0)
4431
- .attr('x2', 0)
4537
+ .attr('x1', RESIZER_THICKNESS / 2)
4538
+ .attr('x2', RESIZER_THICKNESS / 2)
4432
4539
  .attr('y1', 0)
4433
4540
  .attr('y2', (d) => d.height);
4434
4541
  mergeSelection
@@ -4436,13 +4543,13 @@ class DiagramCanvas {
4436
4543
  .select('line.top-resizer')
4437
4544
  .attr('x1', 0)
4438
4545
  .attr('x2', (d) => d.width)
4439
- .attr('y1', 0)
4440
- .attr('y2', 0);
4546
+ .attr('y1', RESIZER_THICKNESS / 2)
4547
+ .attr('y2', RESIZER_THICKNESS / 2);
4441
4548
  mergeSelection
4442
4549
  .filter('.resizable-x')
4443
4550
  .select('line.right-resizer')
4444
- .attr('x1', (d) => d.width)
4445
- .attr('x2', (d) => d.width)
4551
+ .attr('x1', (d) => d.width - RESIZER_THICKNESS / 2)
4552
+ .attr('x2', (d) => d.width - RESIZER_THICKNESS / 2)
4446
4553
  .attr('y1', 0)
4447
4554
  .attr('y2', (d) => d.height);
4448
4555
  mergeSelection
@@ -4450,13 +4557,13 @@ class DiagramCanvas {
4450
4557
  .select('line.bottom-resizer')
4451
4558
  .attr('x1', 0)
4452
4559
  .attr('x2', (d) => d.width)
4453
- .attr('y1', (d) => d.height)
4454
- .attr('y2', (d) => d.height);
4560
+ .attr('y1', (d) => d.height - RESIZER_THICKNESS / 2)
4561
+ .attr('y2', (d) => d.height - RESIZER_THICKNESS / 2);
4455
4562
  }
4456
4563
  updatePortsInView(...ids) {
4457
4564
  let updateSelection = this.selectCanvas()
4458
4565
  .selectAll('g.diagram-port')
4459
- .data(this.model.getPorts(this.priorityThreshold), (d) => d.id);
4566
+ .data(this.model.ports.filter(this.priorityThreshold), (d) => d.id);
4460
4567
  const exitSelection = updateSelection.exit();
4461
4568
  const enterSelection = updateSelection
4462
4569
  .enter()
@@ -4547,7 +4654,7 @@ class DiagramCanvas {
4547
4654
  }
4548
4655
  updateConnectionsInView(...ids) {
4549
4656
  const connectionList = [
4550
- ...this.model.getConnections(this.priorityThreshold)
4657
+ ...this.model.connections.filter(undefined, this.priorityThreshold)
4551
4658
  ];
4552
4659
  if (this.unfinishedConnection) {
4553
4660
  connectionList.push(this.unfinishedConnection);
@@ -4643,7 +4750,7 @@ class DiagramCanvas {
4643
4750
  updateFieldsInView(...ids) {
4644
4751
  let updateSelection = this.selectCanvas()
4645
4752
  .selectAll('foreignObject.diagram-field')
4646
- .data(this.model.getFields(this.priorityThreshold), (d) => d.id);
4753
+ .data(this.model.fields.filter(this.priorityThreshold), (d) => d.id);
4647
4754
  const exitSelection = updateSelection.exit();
4648
4755
  const enterSelection = updateSelection
4649
4756
  .enter()
@@ -4979,9 +5086,13 @@ class DiagramCanvas {
4979
5086
  }
4980
5087
  else {
4981
5088
  if (this.guessConnectionType) {
4982
- let differentConnectionType = this.model.connectionTypes.find((t) => t.canStartFromType(port.getNode()?.type?.id || ''));
5089
+ let differentConnectionType = this.model.connections.types
5090
+ .all()
5091
+ .find((t) => t.canStartFromType(port.getNode()?.type?.id || ''));
4983
5092
  if (differentConnectionType === undefined) {
4984
- differentConnectionType = this.model.connectionTypes.find((t) => t.canFinishOnType(port.getNode()?.type?.id || ''));
5093
+ differentConnectionType = this.model.connections.types
5094
+ .all()
5095
+ .find((t) => t.canFinishOnType(port.getNode()?.type?.id || ''));
4985
5096
  }
4986
5097
  if (differentConnectionType !== undefined) {
4987
5098
  this.unfinishedConnection = new DiagramConnection(this.model, differentConnectionType, port, undefined, 'diagram-connection-unfinished');
@@ -5018,10 +5129,15 @@ class DiagramCanvas {
5018
5129
  }
5019
5130
  else {
5020
5131
  if (this.guessConnectionType) {
5021
- let differentConnectionType = this.model.connectionTypes.find((t) => t.canStartFromType(this.unfinishedConnection?.start?.getNode()?.type?.id || '') && t.canFinishOnType(port.getNode()?.type?.id || ''));
5132
+ let differentConnectionType = this.model.connections.types
5133
+ .all()
5134
+ .find((t) => t.canStartFromType(this.unfinishedConnection?.start?.getNode()?.type?.id || '') && t.canFinishOnType(port.getNode()?.type?.id || ''));
5022
5135
  let invertConnection = false;
5023
5136
  if (differentConnectionType === undefined) {
5024
- differentConnectionType = this.model.connectionTypes.find((t) => t.canFinishOnType(this.unfinishedConnection?.start?.getNode()?.type?.id || '') && t.canStartFromType(port.getNode()?.type?.id || ''));
5137
+ differentConnectionType = this.model.connections.types
5138
+ .all()
5139
+ .find((t) => t.canFinishOnType(this.unfinishedConnection?.start?.getNode()?.type?.id ||
5140
+ '') && t.canStartFromType(port.getNode()?.type?.id || ''));
5025
5141
  invertConnection = true;
5026
5142
  }
5027
5143
  if (differentConnectionType !== undefined) {
@@ -5415,7 +5531,8 @@ class ErrorsComponent {
5415
5531
  }
5416
5532
  showError(error) {
5417
5533
  if (error.elementId && error.propertyNames) {
5418
- this.canvas.setPropertyEditorSelection(this.canvas.model.getElement(error.elementId));
5534
+ this.canvas.setPropertyEditorSelection(this.canvas.model.nodes.get(error.elementId) ||
5535
+ this.canvas.model.connections.get(error.elementId));
5419
5536
  this.canvas.parentComponent.propertyEditor?.highlightProperty(...error.propertyNames);
5420
5537
  }
5421
5538
  else if (!error.elementId && error.propertyNames) {
@@ -5510,7 +5627,7 @@ class PaletteComponent {
5510
5627
  }
5511
5628
  appendTemplate(template, classes) {
5512
5629
  if (template.templateType === 'node') {
5513
- const nodeType = this.canvas.model.getNodeType(template.type);
5630
+ const nodeType = this.canvas.model.nodes.types.get(template.type);
5514
5631
  if (nodeType) {
5515
5632
  this.appendNodeTemplate(nodeType, template, classes);
5516
5633
  }
@@ -5520,7 +5637,7 @@ class PaletteComponent {
5520
5637
  }
5521
5638
  else if (template.templateType === 'connection') {
5522
5639
  {
5523
- const connectionType = this.canvas.model.getConnectionType(template.type);
5640
+ const connectionType = this.canvas.model.connections.types.get(template.type);
5524
5641
  if (connectionType) {
5525
5642
  this.appendConnectionTemplate(connectionType, template, classes);
5526
5643
  }
@@ -5578,7 +5695,8 @@ class PaletteComponent {
5578
5695
  .style('top', 0)
5579
5696
  .style('z-index', 'auto');
5580
5697
  // try to place node
5581
- if (type.isUnique && this.canvas.model.hasNodeOfType(type.id)) {
5698
+ if (type.isUnique &&
5699
+ this.canvas.model.nodes.find(type.id) !== undefined) {
5582
5700
  // can't place, it's unique and that node is already in the model
5583
5701
  return;
5584
5702
  }
@@ -6163,11 +6281,11 @@ class DiagramComponent {
6163
6281
  this.configurationService.init(this.config);
6164
6282
  }
6165
6283
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.6", ngImport: i0, type: DiagramComponent, deps: [{ token: DagaConfigurationService }, { token: CanvasProviderService }], target: i0.ɵɵFactoryTarget.Component }); }
6166
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.6", type: DiagramComponent, isStandalone: true, selector: "daga-diagram", inputs: { config: "config" }, providers: [CanvasProviderService, DagaConfigurationService], ngImport: i0, template: `<ng-content></ng-content>`, isInline: true, styles: [":host{position:absolute;min-width:40rem;min-height:20rem}\n"] }); }
6284
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.6", type: DiagramComponent, isStandalone: true, selector: "daga-diagram", inputs: { config: "config" }, providers: [CanvasProviderService, DagaConfigurationService], ngImport: i0, template: `<ng-content></ng-content>`, isInline: true, styles: [":host{position:relative;display:block;min-width:40rem;min-height:20rem;width:100%;height:100%}\n"] }); }
6167
6285
  }
6168
6286
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.6", ngImport: i0, type: DiagramComponent, decorators: [{
6169
6287
  type: Component,
6170
- args: [{ standalone: true, selector: 'daga-diagram', template: `<ng-content></ng-content>`, providers: [CanvasProviderService, DagaConfigurationService], styles: [":host{position:absolute;min-width:40rem;min-height:20rem}\n"] }]
6288
+ args: [{ standalone: true, selector: 'daga-diagram', template: `<ng-content></ng-content>`, providers: [CanvasProviderService, DagaConfigurationService], styles: [":host{position:relative;display:block;min-width:40rem;min-height:20rem;width:100%;height:100%}\n"] }]
6171
6289
  }], ctorParameters: () => [{ type: DagaConfigurationService }, { type: CanvasProviderService }], propDecorators: { config: [{
6172
6290
  type: Input
6173
6291
  }] } });
@@ -6315,10 +6433,10 @@ class DagaImporter {
6315
6433
  model.createdAt = new Date(data.createdAt);
6316
6434
  model.updatedAt = new Date(data.updatedAt);
6317
6435
  for (const node of data.nodes || []) {
6318
- const newNodeType = model.getNodeType(node.type);
6436
+ const newNodeType = model.nodes.types.get(node.type);
6319
6437
  if (newNodeType) {
6320
6438
  const newNode = new DiagramNode(model, newNodeType, node.coords, node.id);
6321
- model.nodes.push(newNode);
6439
+ model.nodes.add(newNode);
6322
6440
  newNode.width = node.width;
6323
6441
  newNode.height = node.height;
6324
6442
  if (node.data) {
@@ -6337,13 +6455,13 @@ class DagaImporter {
6337
6455
  ], newNode.width - labelConfiguration.margin * 2, newNode.height - labelConfiguration.margin * 2, labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable);
6338
6456
  newField.text = node.label;
6339
6457
  newNode.label = newField;
6340
- model.fields.push(newField);
6458
+ model.fields.add(newField);
6341
6459
  }
6342
6460
  }
6343
6461
  for (const section of node.sections || []) {
6344
6462
  const newSection = new DiagramSection(model, newNode, section.coords, section.width, section.height, section.id);
6345
6463
  newNode.sections?.push(newSection);
6346
- model.sections.push(newSection);
6464
+ model.sections.add(newSection);
6347
6465
  if (section.label) {
6348
6466
  // add section label
6349
6467
  if (newNodeType.sections?.label) {
@@ -6357,14 +6475,14 @@ class DagaImporter {
6357
6475
  ], newSection.width - labelConfiguration.margin * 2, newSection.height - labelConfiguration.margin * 2, labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable);
6358
6476
  newField.text = section.label;
6359
6477
  newSection.label = newField;
6360
- model.fields.push(newField);
6478
+ model.fields.add(newField);
6361
6479
  }
6362
6480
  }
6363
6481
  let portCounter = 0;
6364
6482
  for (const port of section.ports || []) {
6365
6483
  const newPort = new DiagramPort(model, newSection, port.coords, port.direction, port.id);
6366
6484
  newSection.ports.push(newPort);
6367
- model.ports.push(newPort);
6485
+ model.ports.add(newPort);
6368
6486
  if (port.label) {
6369
6487
  // add port label
6370
6488
  if (newNodeType.ports.length > portCounter &&
@@ -6400,7 +6518,7 @@ class DagaImporter {
6400
6518
  const newField = new DiagramField(model, newPort, labelCoords, labelConfiguration.fontSize, labelConfiguration.fontSize, labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable);
6401
6519
  newField.text = port.label;
6402
6520
  newPort.label = newField;
6403
- model.fields.push(newField);
6521
+ model.fields.add(newField);
6404
6522
  }
6405
6523
  ++portCounter;
6406
6524
  }
@@ -6410,7 +6528,7 @@ class DagaImporter {
6410
6528
  for (const port of node.ports || []) {
6411
6529
  const newPort = new DiagramPort(model, newNode, port.coords, port.direction, port.id);
6412
6530
  newNode.ports.push(newPort);
6413
- model.ports.push(newPort);
6531
+ model.ports.add(newPort);
6414
6532
  if (port.label) {
6415
6533
  // add port label
6416
6534
  if (newNodeType.ports.length > portCounter &&
@@ -6446,7 +6564,7 @@ class DagaImporter {
6446
6564
  const newField = new DiagramField(model, newPort, labelCoords, labelConfiguration.fontSize, labelConfiguration.fontSize, labelConfiguration.fontSize, labelConfiguration.fontFamily, labelConfiguration.color, labelConfiguration.selectedColor, labelConfiguration.horizontalAlign, labelConfiguration.verticalAlign, '', labelConfiguration.editable);
6447
6565
  newField.text = port.label;
6448
6566
  newPort.label = newField;
6449
- model.fields.push(newField);
6567
+ model.fields.add(newField);
6450
6568
  }
6451
6569
  ++portCounter;
6452
6570
  }
@@ -6454,10 +6572,10 @@ class DagaImporter {
6454
6572
  }
6455
6573
  }
6456
6574
  for (const connection of data.connections || []) {
6457
- const newConnectionType = model.getConnectionType(connection.type);
6575
+ const newConnectionType = model.connections.types.get(connection.type);
6458
6576
  if (newConnectionType) {
6459
- const newConnection = new DiagramConnection(model, newConnectionType, connection.start ? model.getPort(connection.start) : undefined, connection.end ? model.getPort(connection.end) : undefined, connection.id);
6460
- model.connections.push(newConnection);
6577
+ const newConnection = new DiagramConnection(model, newConnectionType, connection.start ? model.ports.get(connection.start) : undefined, connection.end ? model.ports.get(connection.end) : undefined, connection.id);
6578
+ model.connections.add(newConnection);
6461
6579
  newConnection.startLabel = connection.startLabel;
6462
6580
  newConnection.middleLabel = connection.middleLabel;
6463
6581
  newConnection.endLabel = connection.endLabel;