@metadev/daga 1.5.3 → 1.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Changelog.md CHANGED
@@ -6,6 +6,19 @@ List of releases and changes.
6
6
 
7
7
  ## Next release Lobera
8
8
 
9
+ ## v. 1.5.5
10
+
11
+ Date: _2024-10-02_
12
+
13
+ - Ensure that decorators are always removed [#167](https://github.com/metadevpro/daga/pull/167)
14
+
15
+ ## v. 1.5.4
16
+
17
+ Date: _2024-09-21_
18
+
19
+ - Add diagram decorators [#164](https://github.com/metadevpro/daga/issues/164) [#166](https://github.com/metadevpro/daga/pull/166)
20
+ - Enable diagram events on diagram objects [#166](https://github.com/metadevpro/daga/pull/166)
21
+
9
22
  ## v. 1.5.3
10
23
 
11
24
  Date: _2024-09-09_
@@ -2207,6 +2207,11 @@ class DiagramSection extends DiagramElement {
2207
2207
  * @public
2208
2208
  */
2209
2209
  this.ports = [];
2210
+ /**
2211
+ * Decorators of this section.
2212
+ * @public
2213
+ */
2214
+ this.decorators = [];
2210
2215
  this.node = node;
2211
2216
  this.indexXInNode = indexXInNode;
2212
2217
  this.indexYInNode = indexYInNode;
@@ -2396,6 +2401,10 @@ class DiagramSection extends DiagramElement {
2396
2401
  this.height - (this.getConfig()?.label?.margin || 0) * 2);
2397
2402
  this.label.updateInView();
2398
2403
  }
2404
+ // Move decorators to match the new coords.
2405
+ for (const decorator of this.decorators) {
2406
+ decorator.move(translatePoint(decorator.coords, oldCoordsX, oldCoordsY, newCoordsX, newCoordsY));
2407
+ }
2399
2408
  // Update canvas.
2400
2409
  this.getConnections().forEach((c) => c.tighten());
2401
2410
  this.updateInView();
@@ -2597,6 +2606,11 @@ class DiagramNode extends DiagramElement {
2597
2606
  * @public
2598
2607
  */
2599
2608
  this.ports = [];
2609
+ /**
2610
+ * Decorators of this node.
2611
+ * @public
2612
+ */
2613
+ this.decorators = [];
2600
2614
  /**
2601
2615
  * Collaborative timestamp for SetGeometryCollabActions.
2602
2616
  * @public
@@ -2913,6 +2927,10 @@ class DiagramNode extends DiagramElement {
2913
2927
  (this.label.height = this.height - (this.type.label?.margin || 0) * 2);
2914
2928
  this.label.updateInView();
2915
2929
  }
2930
+ // Move decorators to match the new coords.
2931
+ for (const decorator of this.decorators) {
2932
+ decorator.move(translatePoint(decorator.coords, oldCoordsX, oldCoordsY, newCoordsX, newCoordsY));
2933
+ }
2916
2934
  // Update canvas.
2917
2935
  this.getConnections().forEach((c) => c.tighten());
2918
2936
  this.updateInView();
@@ -3043,6 +3061,10 @@ class DiagramNodeSet extends DiagramEntitySet {
3043
3061
  while (node.ports.length > 0) {
3044
3062
  this.model.ports.remove(node.ports[0].id);
3045
3063
  }
3064
+ // remove all decorators
3065
+ while (node.decorators.length > 0) {
3066
+ this.model.decorators.remove(node.decorators[0].id);
3067
+ }
3046
3068
  // remove label
3047
3069
  if (node.label) {
3048
3070
  this.model.fields.remove(node.label.id);
@@ -3809,6 +3831,8 @@ class SetSelfRemovedCollabAction {
3809
3831
  this.canvas.updatePortsInView(...this.portIds);
3810
3832
  this.canvas.updateConnectionsInView(...this.connectionIds);
3811
3833
  this.canvas.updateFieldsInView(...this.fieldIds);
3834
+ // some of the nodes and sections may have decorators, so update them
3835
+ this.canvas.updateDecoratorsInView();
3812
3836
  }
3813
3837
  serialize() {
3814
3838
  return {
@@ -4781,8 +4805,8 @@ class PriorityLayout {
4781
4805
  // nothing to arrange...
4782
4806
  return model;
4783
4807
  }
4784
- const maximumPriority = Math.max(...model.nodes.types.all().map((n) => n.priority));
4785
- const minimumPriority = Math.min(...model.nodes.types.all().map((n) => n.priority));
4808
+ const maximumPriority = Math.max(...model.nodes.filter((n) => !n.removed).map((n) => n.getPriority()));
4809
+ const minimumPriority = Math.min(...model.nodes.filter((n) => !n.removed).map((n) => n.getPriority()));
4786
4810
  if (maximumPriority === minimumPriority) {
4787
4811
  // if there's no disparity in priorities, just use breadth layout
4788
4812
  new BreadthLayout().apply(model);
@@ -4880,6 +4904,106 @@ class PriorityLayout {
4880
4904
  }
4881
4905
  }
4882
4906
 
4907
+ /**
4908
+ * A layout which arranges the nodes in trees from left to right by depth relative to the nodes with most priority.
4909
+ * @public
4910
+ */
4911
+ class TreeLayout {
4912
+ apply(model) {
4913
+ if (model.nodes.length === 0) {
4914
+ // nothing to arrange...
4915
+ return model;
4916
+ }
4917
+ const maximumPriority = Math.max(...model.nodes.filter((n) => !n.removed).map((n) => n.getPriority()));
4918
+ const minimumPriority = Math.min(...model.nodes.filter((n) => !n.removed).map((n) => n.getPriority()));
4919
+ if (maximumPriority === minimumPriority) {
4920
+ // if there's no disparity in priorities, just use breadth layout
4921
+ new BreadthLayout().apply(model);
4922
+ return model;
4923
+ }
4924
+ const gapSize = (model.canvas?.gridSize || 0) * 2;
4925
+ const nodesToBeArranged = [...model.nodes].sort((n1, n2) => n2.getPriority() - n1.getPriority());
4926
+ const branches = [];
4927
+ while (nodesToBeArranged.length > 0) {
4928
+ const nodeToBeArranged = nodesToBeArranged[0];
4929
+ nodesToBeArranged.splice(0, 1);
4930
+ const branch = new Branch(undefined, nodeToBeArranged);
4931
+ populateBranches(branch, nodesToBeArranged);
4932
+ branches.push(branch);
4933
+ }
4934
+ const branchArrangement = [];
4935
+ for (const branch of branches) {
4936
+ branchArrangement.push([branch]);
4937
+ arrangeBranches(branch, branchArrangement, branchArrangement.length);
4938
+ }
4939
+ const maximumHeight = Math.max(...model.nodes.all().map((n) => n.height));
4940
+ let widthAccumulator = 0;
4941
+ for (let i = 0; i < branchArrangement.length; ++i) {
4942
+ let heightAccumulator = 0;
4943
+ for (let j = 0; j < branchArrangement[i].length; ++j) {
4944
+ const branch = branchArrangement[i][j];
4945
+ branch.node.move([widthAccumulator, heightAccumulator]);
4946
+ heightAccumulator +=
4947
+ (gapSize + maximumHeight) * branch.countBranchHeight();
4948
+ }
4949
+ const maximumWidth = Math.max(...branchArrangement[i].map((b) => b.node.width));
4950
+ widthAccumulator += gapSize + maximumWidth;
4951
+ }
4952
+ for (const connection of model.connections) {
4953
+ connection.tighten();
4954
+ }
4955
+ model.canvas?.diagramChanges$.next();
4956
+ return model;
4957
+ }
4958
+ }
4959
+ const populateBranches = (branch, nodesToBeArranged) => {
4960
+ for (const adjacentNode of branch.node.getAdjacentNodes()) {
4961
+ const indexOfAdjacentNode = nodesToBeArranged.indexOf(adjacentNode);
4962
+ if (indexOfAdjacentNode >= 0) {
4963
+ nodesToBeArranged.splice(indexOfAdjacentNode, 1);
4964
+ const newBranch = branch.addBranch(adjacentNode);
4965
+ populateBranches(newBranch, nodesToBeArranged);
4966
+ }
4967
+ }
4968
+ };
4969
+ const arrangeBranches = (branch, branchArrangement, index) => {
4970
+ if (branch.branches.length > 0) {
4971
+ while (index >= branchArrangement.length) {
4972
+ branchArrangement.push([]);
4973
+ }
4974
+ for (const subbranch of branch.branches) {
4975
+ branchArrangement[index].push(subbranch);
4976
+ arrangeBranches(subbranch, branchArrangement, index + 1);
4977
+ }
4978
+ }
4979
+ };
4980
+ class Branch {
4981
+ constructor(parent, node) {
4982
+ this.parent = parent;
4983
+ this.branches = [];
4984
+ this.depth = 0;
4985
+ this.node = node;
4986
+ }
4987
+ addBranch(node) {
4988
+ const newBranch = new Branch(this, node);
4989
+ newBranch.depth = this.depth + 1;
4990
+ this.branches.push(newBranch);
4991
+ return newBranch;
4992
+ }
4993
+ countBranchHeight() {
4994
+ if (this.branches.length <= 0) {
4995
+ return 1;
4996
+ }
4997
+ else {
4998
+ let total = 0;
4999
+ for (const subbranch of this.branches) {
5000
+ total += subbranch.countBranchHeight();
5001
+ }
5002
+ return total;
5003
+ }
5004
+ }
5005
+ }
5006
+
4883
5007
  /**
4884
5008
  * A layout which arranges all the nodes in a vertical line.
4885
5009
  * @public
@@ -4913,6 +5037,7 @@ const layouts = {
4913
5037
  force: new ForceLayout(),
4914
5038
  horizontal: new HorizontalLayout(),
4915
5039
  priority: new PriorityLayout(),
5040
+ tree: new TreeLayout(),
4916
5041
  vertical: new VerticalLayout()
4917
5042
  };
4918
5043
 
@@ -5278,6 +5403,109 @@ class DagaExporter {
5278
5403
  }
5279
5404
  }
5280
5405
 
5406
+ /**
5407
+ * Represents an action taken by the user on the diagram.
5408
+ * @public
5409
+ */
5410
+ class DiagramEvent {
5411
+ constructor(cause, type, target, coords) {
5412
+ this.cause = cause;
5413
+ this.type = type;
5414
+ this.target = target;
5415
+ this.coords = coords;
5416
+ this.defaultPrevented = false;
5417
+ }
5418
+ preventDefault() {
5419
+ this.defaultPrevented = true;
5420
+ }
5421
+ }
5422
+
5423
+ /**
5424
+ * A foreign object which is inserted with arbitrary html into a diagram.
5425
+ * Similar to a diagram object, but it's part of a node or section and it moves and stretches as its geometry changes.
5426
+ * Diagram decorators are not serialized with other diagram elements.
5427
+ * @see DiagramNode
5428
+ * @see DiagramObject
5429
+ * @see DiagramSection
5430
+ * @public
5431
+ */
5432
+ class DiagramDecorator extends DiagramElement {
5433
+ constructor(model, rootElement, coords, width, height, priority, html, id) {
5434
+ if (model.objects.get(id) !== undefined) {
5435
+ throw new Error(`DiagramObject with id "${id}" already exists`);
5436
+ }
5437
+ super(model, id);
5438
+ this.rootElement = rootElement;
5439
+ this.coords = coords;
5440
+ this.width = width;
5441
+ this.height = height;
5442
+ this.priority = priority;
5443
+ this.html = html;
5444
+ }
5445
+ select() {
5446
+ return this.model.canvas
5447
+ ?.selectCanvasView()
5448
+ ?.select(`foreignObject#${this.id}`);
5449
+ }
5450
+ get removed() {
5451
+ return (this.selfRemoved ||
5452
+ (this.rootElement !== undefined && this.rootElement.removed));
5453
+ }
5454
+ updateInView() {
5455
+ this.model.canvas?.updateDecoratorsInView(this.id);
5456
+ }
5457
+ /**
5458
+ * Change the coordinates of this decorator to the given coordinates.
5459
+ * @public
5460
+ * @param coords A point in the diagram.
5461
+ */
5462
+ move(coords) {
5463
+ this.coords = coords;
5464
+ this.updateInView();
5465
+ }
5466
+ getPriority() {
5467
+ return this.priority;
5468
+ }
5469
+ }
5470
+ class DiagramDecoratorSet extends DiagramEntitySet {
5471
+ /**
5472
+ * Instance a set of decorators for the given model. This method is used internally.
5473
+ * @private
5474
+ */
5475
+ constructor(model) {
5476
+ super();
5477
+ this.model = model;
5478
+ }
5479
+ /**
5480
+ * Instance a new decorator and add it to this set.
5481
+ * @private
5482
+ */
5483
+ new(rootElement, coords, width, height, priority, html, id) {
5484
+ const decorator = new DiagramDecorator(this.model, rootElement, coords, width, height, priority, html, id);
5485
+ super.add(decorator);
5486
+ decorator.updateInView();
5487
+ // add this port to its root element
5488
+ if (rootElement !== undefined) {
5489
+ rootElement.decorators.push(decorator);
5490
+ }
5491
+ return decorator;
5492
+ }
5493
+ remove(id) {
5494
+ const decorator = this.get(id);
5495
+ if (decorator) {
5496
+ // remove from root element
5497
+ if (decorator.rootElement instanceof DiagramNode ||
5498
+ decorator.rootElement instanceof DiagramSection) {
5499
+ removeIfExists(decorator.rootElement.decorators, decorator);
5500
+ }
5501
+ // remove from set of objects
5502
+ super.remove(id);
5503
+ // remove from canvas
5504
+ decorator.updateInView();
5505
+ }
5506
+ }
5507
+ }
5508
+
5281
5509
  /**
5282
5510
  * A foreign object which is inserted with arbitrary html into a diagram.
5283
5511
  * Diagram objects are not serialized with other diagram elements.
@@ -5392,6 +5620,12 @@ class DiagramModel {
5392
5620
  * @public
5393
5621
  */
5394
5622
  this.objects = new DiagramObjectSet(this);
5623
+ /**
5624
+ * Decorators of this model.
5625
+ * @see DiagramDecorator
5626
+ * @public
5627
+ */
5628
+ this.decorators = new DiagramDecoratorSet(this);
5395
5629
  this.canvas = canvas;
5396
5630
  this.id = id;
5397
5631
  this.name = name;
@@ -5420,28 +5654,12 @@ class DiagramModel {
5420
5654
  this.connections.clear();
5421
5655
  this.fields.clear();
5422
5656
  this.objects.clear();
5657
+ this.decorators.clear();
5423
5658
  this.valueSet.resetValues();
5424
5659
  this.canvas?.updateModelInView();
5425
5660
  }
5426
5661
  }
5427
5662
 
5428
- /**
5429
- * Represents an action taken by the user on the diagram.
5430
- * @public
5431
- */
5432
- class DiagramEvent {
5433
- constructor(cause, type, target, coords) {
5434
- this.cause = cause;
5435
- this.type = type;
5436
- this.target = target;
5437
- this.coords = coords;
5438
- this.defaultPrevented = false;
5439
- }
5440
- preventDefault() {
5441
- this.defaultPrevented = true;
5442
- }
5443
- }
5444
-
5445
5663
  /**
5446
5664
  * Thickness of the invisible path around a connection used to make it easier to click on, in pixels.
5447
5665
  * @private
@@ -5737,6 +5955,7 @@ class DiagramCanvas {
5737
5955
  canvasElements.append('g').attr('class', 'canvas-connections');
5738
5956
  canvasElements.append('g').attr('class', 'canvas-fields');
5739
5957
  canvasElements.append('g').attr('class', 'canvas-objects');
5958
+ canvasElements.append('g').attr('class', 'canvas-decorators');
5740
5959
  this.viewInitialized$.next();
5741
5960
  }
5742
5961
  zoomBy(zoom) {
@@ -5860,6 +6079,7 @@ class DiagramCanvas {
5860
6079
  this.updateConnectionsInView();
5861
6080
  this.updateFieldsInView();
5862
6081
  this.updateObjectsInView();
6082
+ this.updateDecoratorsInView();
5863
6083
  }
5864
6084
  updateNodesInView(...ids) {
5865
6085
  let updateSelection = this.selectCanvasNodes()
@@ -7443,6 +7663,58 @@ class DiagramCanvas {
7443
7663
  .attr('transform', (d) => `translate(${d.coords[0]},${d.coords[1]})`)
7444
7664
  .html((d) => d.html);
7445
7665
  exitSelection.remove();
7666
+ enterSelection
7667
+ .on(Events.ContextMenu, (event) => {
7668
+ const diagramEvent = new DiagramEvent(event, Events.ContextMenu, undefined);
7669
+ this.parentComponent.modelEvent.emit(diagramEvent);
7670
+ if (!diagramEvent.defaultPrevented &&
7671
+ this.canUserPerformAction(DiagramActions.ContextMenu)) {
7672
+ event.preventDefault();
7673
+ this.openContextMenu(event);
7674
+ }
7675
+ })
7676
+ .on(Events.DoubleClick, (event, d) => {
7677
+ const diagramEvent = new DiagramEvent(event, Events.DoubleClick, d);
7678
+ this.parentComponent.modelEvent.emit(diagramEvent);
7679
+ });
7680
+ }
7681
+ updateDecoratorsInView(...ids) {
7682
+ let updateSelection = this.selectCanvasDecorators()
7683
+ .selectAll('foreignObject.diagram-decorator')
7684
+ .data(this.model.decorators.filter((e) => !e.removed &&
7685
+ (this.priorityThreshold !== undefined
7686
+ ? e.getPriority() >= this.priorityThreshold
7687
+ : true)), (d) => d.id);
7688
+ const exitSelection = updateSelection.exit();
7689
+ const enterSelection = updateSelection
7690
+ .enter()
7691
+ .append('foreignObject')
7692
+ .attr('id', (d) => d.id)
7693
+ .attr('class', 'diagram-decorator');
7694
+ if (ids && ids.length > 0) {
7695
+ updateSelection = updateSelection.filter((d) => ids.includes(d.id));
7696
+ }
7697
+ const mergeSelection = enterSelection.merge(updateSelection);
7698
+ mergeSelection
7699
+ .attr('width', (d) => `${d.width}px`)
7700
+ .attr('height', (d) => `${d.height}px`)
7701
+ .attr('transform', (d) => `translate(${d.coords[0]},${d.coords[1]})`)
7702
+ .html((d) => d.html);
7703
+ exitSelection.remove();
7704
+ enterSelection
7705
+ .on(Events.ContextMenu, (event) => {
7706
+ const diagramEvent = new DiagramEvent(event, Events.ContextMenu, undefined);
7707
+ this.parentComponent.modelEvent.emit(diagramEvent);
7708
+ if (!diagramEvent.defaultPrevented &&
7709
+ this.canUserPerformAction(DiagramActions.ContextMenu)) {
7710
+ event.preventDefault();
7711
+ this.openContextMenu(event);
7712
+ }
7713
+ })
7714
+ .on(Events.DoubleClick, (event, d) => {
7715
+ const diagramEvent = new DiagramEvent(event, Events.DoubleClick, d);
7716
+ this.parentComponent.modelEvent.emit(diagramEvent);
7717
+ });
7446
7718
  }
7447
7719
  updateConnectionLabelsInView(connection) {
7448
7720
  const connectionSelection = this.selectCanvasView().select(`g.diagram-connection#${connection.id}`);
@@ -7748,6 +8020,9 @@ class DiagramCanvas {
7748
8020
  selectCanvasObjects() {
7749
8021
  return this.selectRoot().select(`.canvas-objects`);
7750
8022
  }
8023
+ selectCanvasDecorators() {
8024
+ return this.selectRoot().select(`.canvas-decorators`);
8025
+ }
7751
8026
  // User actions
7752
8027
  startConnection(port) {
7753
8028
  if (this.connectionType &&
@@ -10266,5 +10541,5 @@ function now() {
10266
10541
  * Generated bundle index. Do not edit.
10267
10542
  */
10268
10543
 
10269
- export { ACTION_QUEUE_SIZE, ActionQueue, AddConnectionAction, AddNodeAction, AdjacencyLayout, BreadthAdjacencyLayout, BreadthLayout, CanvasProviderService, ClosedShape, CollabClient, CollapseButtonComponent, Corner, DagaConfigurationService, DagaExporter, DagaImporter, DagaModule, DiagramActions, DiagramButtonsComponent, DiagramCanvas, DiagramComponent, DiagramConnection, DiagramConnectionSet, DiagramConnectionType, DiagramEditorComponent, DiagramElement, DiagramEntitySet, DiagramEvent, DiagramField, DiagramFieldSet, DiagramModel, DiagramNode, DiagramNodeSet, DiagramNodeType, DiagramPort, DiagramPortSet, DiagramSection, DiagramSectionSet, EditFieldAction, ErrorsComponent, ForceLayout, HorizontalAlign, HorizontalLayout, LineShape, LineStyle, ObjectEditorComponent, PaletteComponent, PriorityLayout, Property, PropertyEditorComponent, PropertySet, RemoveAction, SetGeometryAction, Side, TextListEditorComponent, TextMapEditorComponent, Type, UpdateValuesAction, ValueSet, VerticalAlign, VerticalLayout, layouts };
10544
+ export { ACTION_QUEUE_SIZE, ActionQueue, AddConnectionAction, AddNodeAction, AdjacencyLayout, BreadthAdjacencyLayout, BreadthLayout, CanvasProviderService, ClosedShape, CollabClient, CollapseButtonComponent, Corner, DagaConfigurationService, DagaExporter, DagaImporter, DagaModule, DiagramActions, DiagramButtonsComponent, DiagramCanvas, DiagramComponent, DiagramConnection, DiagramConnectionSet, DiagramConnectionType, DiagramDecorator, DiagramDecoratorSet, DiagramEditorComponent, DiagramElement, DiagramEntitySet, DiagramEvent, DiagramField, DiagramFieldSet, DiagramModel, DiagramNode, DiagramNodeSet, DiagramNodeType, DiagramObject, DiagramObjectSet, DiagramPort, DiagramPortSet, DiagramSection, DiagramSectionSet, EditFieldAction, ErrorsComponent, ForceLayout, HorizontalAlign, HorizontalLayout, LineShape, LineStyle, ObjectEditorComponent, PaletteComponent, PriorityLayout, Property, PropertyEditorComponent, PropertySet, RemoveAction, SetGeometryAction, Side, TextListEditorComponent, TextMapEditorComponent, TreeLayout, Type, UpdateValuesAction, ValueSet, VerticalAlign, VerticalLayout, layouts };
10270
10545
  //# sourceMappingURL=metadev-daga.mjs.map