@finos/legend-extension-dsl-diagram 1.0.28 → 1.0.31

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. package/lib/DiagramRenderer.d.ts +4 -1
  2. package/lib/DiagramRenderer.d.ts.map +1 -1
  3. package/lib/DiagramRenderer.js +59 -60
  4. package/lib/DiagramRenderer.js.map +1 -1
  5. package/lib/components/studio/ClassDiagramPreview.d.ts.map +1 -1
  6. package/lib/components/studio/ClassDiagramPreview.js +3 -1
  7. package/lib/components/studio/ClassDiagramPreview.js.map +1 -1
  8. package/lib/components/studio/DiagramEditor.d.ts.map +1 -1
  9. package/lib/components/studio/DiagramEditor.js +11 -7
  10. package/lib/components/studio/DiagramEditor.js.map +1 -1
  11. package/lib/graphManager/DSLDiagram_PureGraphManagerPlugin.d.ts +2 -1
  12. package/lib/graphManager/DSLDiagram_PureGraphManagerPlugin.d.ts.map +1 -1
  13. package/lib/graphManager/DSLDiagram_PureGraphManagerPlugin.js +11 -0
  14. package/lib/graphManager/DSLDiagram_PureGraphManagerPlugin.js.map +1 -1
  15. package/lib/graphManager/action/changeDetection/DSLDiagram_ObserverHelper.d.ts +34 -0
  16. package/lib/graphManager/action/changeDetection/DSLDiagram_ObserverHelper.d.ts.map +1 -0
  17. package/lib/graphManager/action/changeDetection/DSLDiagram_ObserverHelper.js +94 -0
  18. package/lib/graphManager/action/changeDetection/DSLDiagram_ObserverHelper.js.map +1 -0
  19. package/lib/helpers/DiagramHelper.d.ts +16 -1
  20. package/lib/helpers/DiagramHelper.d.ts.map +1 -1
  21. package/lib/helpers/DiagramHelper.js +90 -3
  22. package/lib/helpers/DiagramHelper.js.map +1 -1
  23. package/lib/index.css +1 -1
  24. package/lib/index.d.ts +1 -1
  25. package/lib/index.d.ts.map +1 -1
  26. package/lib/index.js +1 -1
  27. package/lib/index.js.map +1 -1
  28. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_AssociationView.d.ts.map +1 -1
  29. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_AssociationView.js +0 -4
  30. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_AssociationView.js.map +1 -1
  31. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_ClassView.d.ts +0 -3
  32. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_ClassView.d.ts.map +1 -1
  33. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_ClassView.js +0 -20
  34. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_ClassView.js.map +1 -1
  35. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_ClassViewReference.d.ts +0 -1
  36. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_ClassViewReference.d.ts.map +1 -1
  37. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_ClassViewReference.js +0 -9
  38. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_ClassViewReference.js.map +1 -1
  39. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_Diagram.d.ts +0 -12
  40. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_Diagram.d.ts.map +1 -1
  41. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_Diagram.js +1 -56
  42. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_Diagram.js.map +1 -1
  43. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_GeneralizationView.d.ts +0 -3
  44. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_GeneralizationView.d.ts.map +1 -1
  45. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_GeneralizationView.js +0 -7
  46. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_GeneralizationView.js.map +1 -1
  47. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_PropertyView.d.ts +0 -4
  48. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_PropertyView.d.ts.map +1 -1
  49. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_PropertyView.js +0 -7
  50. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_PropertyView.js.map +1 -1
  51. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_RelationshipEdgeView.d.ts +6 -3
  52. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_RelationshipEdgeView.d.ts.map +1 -1
  53. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_RelationshipEdgeView.js +6 -14
  54. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_RelationshipEdgeView.js.map +1 -1
  55. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_RelationshipView.d.ts +24 -23
  56. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_RelationshipView.d.ts.map +1 -1
  57. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_RelationshipView.js +57 -129
  58. package/lib/models/metamodels/pure/packageableElements/diagram/DSLDiagram_RelationshipView.js.map +1 -1
  59. package/lib/models/metamodels/pure/packageableElements/diagram/geometry/DSLDiagram_PositionedRectangle.d.ts +0 -8
  60. package/lib/models/metamodels/pure/packageableElements/diagram/geometry/DSLDiagram_PositionedRectangle.d.ts.map +1 -1
  61. package/lib/models/metamodels/pure/packageableElements/diagram/geometry/DSLDiagram_PositionedRectangle.js +0 -19
  62. package/lib/models/metamodels/pure/packageableElements/diagram/geometry/DSLDiagram_PositionedRectangle.js.map +1 -1
  63. package/lib/models/metamodels/pure/packageableElements/diagram/geometry/DSLDiagram_Vector.d.ts +3 -3
  64. package/lib/models/metamodels/pure/packageableElements/diagram/geometry/DSLDiagram_Vector.d.ts.map +1 -1
  65. package/lib/models/metamodels/pure/packageableElements/diagram/geometry/DSLDiagram_Vector.js +1 -1
  66. package/lib/models/metamodels/pure/packageableElements/diagram/geometry/DSLDiagram_Vector.js.map +1 -1
  67. package/lib/models/protocols/pure/v1/transformation/pureGraph/V1_DSLDiagram_GraphBuilderHelper.d.ts.map +1 -1
  68. package/lib/models/protocols/pure/v1/transformation/pureGraph/V1_DSLDiagram_GraphBuilderHelper.js +3 -3
  69. package/lib/models/protocols/pure/v1/transformation/pureGraph/V1_DSLDiagram_GraphBuilderHelper.js.map +1 -1
  70. package/lib/models/protocols/pure/v1/transformation/pureGraph/V1_DSLDiagram_TransformerHelper.js +2 -2
  71. package/lib/models/protocols/pure/v1/transformation/pureGraph/V1_DSLDiagram_TransformerHelper.js.map +1 -1
  72. package/lib/package.json +5 -5
  73. package/lib/stores/studio/DSLDiagram_GraphModifierHelper.d.ts +57 -0
  74. package/lib/stores/studio/DSLDiagram_GraphModifierHelper.d.ts.map +1 -0
  75. package/lib/stores/studio/DSLDiagram_GraphModifierHelper.js +94 -0
  76. package/lib/stores/studio/DSLDiagram_GraphModifierHelper.js.map +1 -0
  77. package/lib/stores/studio/DiagramEditorState.d.ts.map +1 -1
  78. package/lib/stores/studio/DiagramEditorState.js +10 -7
  79. package/lib/stores/studio/DiagramEditorState.js.map +1 -1
  80. package/package.json +12 -12
  81. package/src/DiagramRenderer.ts +133 -68
  82. package/src/components/studio/ClassDiagramPreview.tsx +3 -1
  83. package/src/components/studio/DiagramEditor.tsx +17 -6
  84. package/src/graphManager/DSLDiagram_PureGraphManagerPlugin.ts +17 -0
  85. package/src/graphManager/action/changeDetection/DSLDiagram_ObserverHelper.ts +153 -0
  86. package/src/helpers/DiagramHelper.ts +126 -4
  87. package/src/index.ts +1 -4
  88. package/src/models/metamodels/pure/packageableElements/diagram/DSLDiagram_AssociationView.ts +0 -6
  89. package/src/models/metamodels/pure/packageableElements/diagram/DSLDiagram_ClassView.ts +0 -23
  90. package/src/models/metamodels/pure/packageableElements/diagram/DSLDiagram_ClassViewReference.ts +0 -12
  91. package/src/models/metamodels/pure/packageableElements/diagram/DSLDiagram_Diagram.ts +1 -64
  92. package/src/models/metamodels/pure/packageableElements/diagram/DSLDiagram_GeneralizationView.ts +0 -11
  93. package/src/models/metamodels/pure/packageableElements/diagram/DSLDiagram_PropertyView.ts +0 -17
  94. package/src/models/metamodels/pure/packageableElements/diagram/DSLDiagram_RelationshipEdgeView.ts +6 -16
  95. package/src/models/metamodels/pure/packageableElements/diagram/DSLDiagram_RelationshipView.ts +71 -169
  96. package/src/models/metamodels/pure/packageableElements/diagram/geometry/DSLDiagram_PositionedRectangle.ts +0 -21
  97. package/src/models/metamodels/pure/packageableElements/diagram/geometry/DSLDiagram_Vector.ts +3 -3
  98. package/src/models/protocols/pure/v1/transformation/pureGraph/V1_DSLDiagram_GraphBuilderHelper.ts +6 -3
  99. package/src/models/protocols/pure/v1/transformation/pureGraph/V1_DSLDiagram_TransformerHelper.ts +4 -4
  100. package/src/stores/studio/DSLDiagram_GraphModifierHelper.ts +164 -0
  101. package/src/stores/studio/DiagramEditorState.ts +26 -7
  102. package/tsconfig.json +2 -0
@@ -14,63 +14,31 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import { observable, action, computed, makeObservable } from 'mobx';
18
- import { hashArray, changeEntry, type Hashable } from '@finos/legend-shared';
19
- import { RelationShipEdgeView as RelationshipEdgeView } from './DSLDiagram_RelationshipEdgeView';
17
+ import { hashArray, type Hashable } from '@finos/legend-shared';
18
+ import { RelationshipEdgeView } from './DSLDiagram_RelationshipEdgeView';
20
19
  import { Point } from './geometry/DSLDiagram_Point';
21
20
  import type { ClassView } from './DSLDiagram_ClassView';
22
- import { Vector } from './geometry/DSLDiagram_Vector';
23
21
  import type { Diagram } from './DSLDiagram_Diagram';
24
22
  import { ClassViewExplicitReference } from './DSLDiagram_ClassViewReference';
25
23
  import { DIAGRAM_HASH_STRUCTURE } from '../../../../DSLDiagram_ModelUtils';
26
24
 
27
- /**
28
- * For a path, only counts the points which lie outside of the 2 class views
29
- */
30
- export const manageInsidePointsDynamically = (
31
- path: Point[],
32
- from: ClassView,
33
- to: ClassView,
34
- ): Point[] => {
35
- if (!path.length) {
36
- return [];
37
- }
38
-
39
- let start = 0;
40
- let startPoint = path[start] as Point;
41
-
42
- while (start < path.length - 1 && from.contains(startPoint.x, startPoint.y)) {
43
- start++;
44
- startPoint = path[start] as Point;
45
- }
46
-
47
- let end = path.length - 1;
48
- let endPoint = path[end] as Point;
49
-
50
- while (end > 0 && to.contains(endPoint.x, endPoint.y)) {
51
- end--;
52
- endPoint = path[end] as Point;
53
- }
54
-
55
- return path.slice(start - 1, end + 2);
56
- };
57
-
58
25
  export class RelationshipView implements Hashable {
59
26
  owner: Diagram;
60
27
  from: RelationshipEdgeView;
61
28
  to: RelationshipEdgeView;
62
- // NOTE: to optimize performance for diagram, we have made classview's position and rectangle non-observable
63
- // if we want to further optimize, perhaps we can also remove observability from path
29
+ /**
30
+ * NOTE: Unlike in the protocol model, we don't store the end points in the path but only store the
31
+ * offsets of that point from the center of the end/start classviews. The main purpose here is to
32
+ * make less error. We don't need to bother maintaining these points in the path. They are
33
+ * auto-managed. Even if an erroneous path is set (e.g. an empty list of points), this logic
34
+ * that we have will rectify that and create a sensible path.
35
+ *
36
+ * In exchange, this logic is a little complicated, we have tried to document as much about it as we could
37
+ * but the logic is not straight forward. Perhaps, we could simplify this in the future.
38
+ */
64
39
  path: Point[] = [];
65
40
 
66
41
  constructor(owner: Diagram, from: ClassView, to: ClassView) {
67
- makeObservable(this, {
68
- path: observable,
69
- setPath: action,
70
- changePoint: action,
71
- fullPath: computed,
72
- });
73
-
74
42
  this.owner = owner;
75
43
  this.from = new RelationshipEdgeView(
76
44
  ClassViewExplicitReference.create(from),
@@ -78,15 +46,32 @@ export class RelationshipView implements Hashable {
78
46
  this.to = new RelationshipEdgeView(ClassViewExplicitReference.create(to));
79
47
  }
80
48
 
81
- setPath(val: Point[]): void {
82
- this.path = val;
83
- }
84
- changePoint(val: Point, newVal: Point): void {
85
- changeEntry(this.path, val, newVal);
49
+ /**
50
+ * Calculate the end points of the edge using offset, otherwise, use the center
51
+ */
52
+ private computeEdgeEndpoint(
53
+ edgeView: RelationshipEdgeView,
54
+ allowChange = true,
55
+ ): Point {
56
+ const box = edgeView.classView.value;
57
+ const center = edgeView.classView.value.center();
58
+ const newX = center.x + (edgeView.offsetX ?? 0);
59
+ const newY = center.y + (edgeView.offsetY ?? 0);
60
+ if (box.contains(newX, newY)) {
61
+ return new Point(newX, newY);
62
+ }
63
+ if (allowChange) {
64
+ edgeView.offsetX = 0;
65
+ edgeView.offsetY = 0;
66
+ }
67
+ return new Point(center.x, center.y);
86
68
  }
87
69
 
88
70
  /**
89
- * Compute the full path for an edge, but notice here that the end points are recomputed every time, as such
71
+ * Compute the full path for the relationship view (including the ends even if these
72
+ * ends lie inside of the classviews)
73
+ *
74
+ * Notice here that the end points are recomputed every time, as such
90
75
  * `path` only stores point that matters to the edge but are not end points
91
76
  */
92
77
  buildFullPath(allowChange = true): Point[] {
@@ -98,136 +83,53 @@ export class RelationshipView implements Hashable {
98
83
  }
99
84
 
100
85
  /**
101
- * This method will compute the full path from the offset within class view for persistence purpose
86
+ * For a path, only keep **at most** 1 point at each end that lies inside the class view.
87
+ * If there is no inside points, none of kept, so the path only contains outside points.
102
88
  */
103
- get fullPath(): Point[] {
104
- return manageInsidePointsDynamically(
105
- this.buildFullPath(),
106
- this.from.classView.value,
107
- this.to.classView.value,
108
- );
109
- }
110
-
111
- /**
112
- * Flatten the path if the angle is wide enough
113
- * Also `swallow` points in path which lie inside of the rectangle of a view
114
- */
115
- possiblyFlattenPath(): void {
116
- const fullPath = this.buildFullPath();
117
- // NOTE: this method here will `swallow` up points inside of the boxes
118
- const newPath = manageInsidePointsDynamically(
119
- fullPath,
120
- this.from.classView.value,
121
- this.to.classView.value,
122
- );
123
-
124
- // recompute the offset point from center inside of `from` and `to` classviews.
125
- // for each, we first check if `manageInsidePointsDynamically` removes any points from the full path
126
- // if it does we will update the offset
127
- if (newPath[0] !== fullPath[0]) {
128
- const center = this.from.classView.value.center();
129
- this.from.setOffsetX((newPath[0] as Point).x - center.x);
130
- this.from.setOffsetY((newPath[0] as Point).y - center.y);
89
+ static pruneUnnecessaryInsidePoints = (
90
+ path: Point[],
91
+ from: ClassView,
92
+ to: ClassView,
93
+ ): Point[] => {
94
+ if (!path.length) {
95
+ return [];
131
96
  }
132
97
 
133
- if (newPath[newPath.length - 1] !== fullPath[fullPath.length - 1]) {
134
- const center = this.to.classView.value.center();
135
- this.to.setOffsetX((newPath[newPath.length - 1] as Point).x - center.x);
136
- this.to.setOffsetY((newPath[newPath.length - 1] as Point).y - center.y);
137
- }
98
+ let start = 0;
99
+ let startPoint = path[start] as Point;
138
100
 
139
- // find the point which can be flattened due to its wide angle
140
- const result = [];
141
- for (let i = 0; i < newPath.length - 2; i++) {
142
- const v1 = Vector.fromPoints(
143
- newPath[i + 1] as Point,
144
- newPath[i] as Point,
145
- ).norm();
146
- const v2 = Vector.fromPoints(
147
- newPath[i + 1] as Point,
148
- newPath[i + 2] as Point,
149
- ).norm();
150
- const dot = v1.dotProduct(v2);
151
- const angle = (Math.acos(dot) * 180) / Math.PI;
152
- if (Math.abs(angle - 180) > 5) {
153
- result.push(newPath[i + 1] as Point);
154
- }
101
+ while (
102
+ start < path.length - 1 &&
103
+ from.contains(startPoint.x, startPoint.y)
104
+ ) {
105
+ start++;
106
+ startPoint = path[start] as Point;
155
107
  }
156
- // here's where we will modify the path, i.e. swallow inside points if we have to
157
- this.setPath(result);
158
- }
159
108
 
160
- /**
161
- * Based on the location, find the point on the path that matches or create new point
162
- * (within a threshold of proximity) from the coordinate and put this in the path array
163
- * so it doesn't look too weird
164
- */
165
- findOrBuildPoint(
166
- x: number,
167
- y: number,
168
- zoom: number,
169
- allowChange = true,
170
- ): Point | undefined {
171
- for (const pt of this.path) {
172
- if (
173
- Math.sqrt((x - pt.x) * (x - pt.x) + (y - pt.y) * (y - pt.y)) <
174
- 10 / zoom
175
- ) {
176
- return pt;
177
- }
178
- }
179
-
180
- const fullPath = this.buildFullPath(allowChange);
181
- const newPath = [];
182
- let point;
183
-
184
- for (let i = 0; i < fullPath.length - 1; i++) {
185
- const a = fullPath[i] as Point;
186
- const b = fullPath[i + 1] as Point;
187
- const n = new Vector(a.x, a.y).normal(new Vector(b.x, b.y)).norm();
188
- const v = Vector.fromPoints(a, new Point(x, y));
189
-
190
- if (Math.abs(n.dotProduct(v)) < 5 / zoom) {
191
- const lx = (a.x < b.x ? a.x : b.x) - 5 / zoom;
192
- const hx = (a.x < b.x ? b.x : a.x) + 5 / zoom;
193
- const ly = (a.y < b.y ? a.y : b.y) - 5 / zoom;
194
- const hy = (a.y < b.y ? b.y : a.y) + 5 / zoom;
109
+ // NOTE: due to the usage path, we could make sure `end > start`, but maybe this
110
+ // is an improvement to be done
195
111
 
196
- if (lx <= x && x <= hx && ly <= y && y <= hy) {
197
- point = new Point(x, y);
198
- newPath.push(point);
199
- }
200
- }
112
+ let end = path.length - 1;
113
+ let endPoint = path[end] as Point;
201
114
 
202
- if (i < fullPath.length - 2) {
203
- newPath.push(fullPath[i + 1] as Point);
204
- }
115
+ while (end > 0 && to.contains(endPoint.x, endPoint.y)) {
116
+ end--;
117
+ endPoint = path[end] as Point;
205
118
  }
206
- if (point && allowChange) {
207
- this.setPath(newPath);
208
- }
209
- return point;
210
- }
119
+
120
+ // NOTE: slice upper bound is exclusive, hence the +2 instead of +1
121
+ return path.slice(start - 1, end + 2);
122
+ };
211
123
 
212
124
  /**
213
- * Calculate the end points of the edge using offset, otherwise, use the center
125
+ * This method will compute the full path from the offset within class view for serialization and persistence purpose
214
126
  */
215
- private computeEdgeEndpoint(
216
- edgeView: RelationshipEdgeView,
217
- allowChange = true,
218
- ): Point {
219
- const box = edgeView.classView.value;
220
- const center = edgeView.classView.value.center();
221
- const newX = center.x + (edgeView.offsetX ?? 0);
222
- const newY = center.y + (edgeView.offsetY ?? 0);
223
- if (box.contains(newX, newY)) {
224
- return new Point(newX, newY);
225
- }
226
- if (allowChange) {
227
- edgeView.setOffsetX(0);
228
- edgeView.setOffsetY(0);
229
- }
230
- return new Point(center.x, center.y);
127
+ get pathForSerialization(): Point[] {
128
+ return RelationshipView.pruneUnnecessaryInsidePoints(
129
+ this.buildFullPath(),
130
+ this.from.classView.value,
131
+ this.to.classView.value,
132
+ );
231
133
  }
232
134
 
233
135
  get hashCode(): string {
@@ -235,7 +137,7 @@ export class RelationshipView implements Hashable {
235
137
  DIAGRAM_HASH_STRUCTURE.RELATIONSHIP_VIEW,
236
138
  this.from.classView.value.id,
237
139
  this.to.classView.value.id,
238
- hashArray(this.fullPath),
140
+ hashArray(this.pathForSerialization),
239
141
  ]);
240
142
  }
241
143
  }
@@ -14,7 +14,6 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import { observable, action, makeObservable } from 'mobx';
18
17
  import { hashArray, type Hashable } from '@finos/legend-shared';
19
18
  import { Point } from './DSLDiagram_Point';
20
19
  import { Rectangle } from './DSLDiagram_Rectangle';
@@ -26,30 +25,10 @@ export class PositionedRectangle implements Hashable {
26
25
  dummyObservable = {};
27
26
 
28
27
  constructor(position: Point, rectangle: Rectangle) {
29
- makeObservable(this, {
30
- dummyObservable: observable,
31
- forceRefreshHash: action,
32
- });
33
-
34
28
  this.position = position;
35
29
  this.rectangle = rectangle;
36
30
  }
37
31
 
38
- setRectangle(value: Rectangle): void {
39
- this.rectangle = value;
40
- }
41
- setPosition(value: Point): void {
42
- this.position = value;
43
- }
44
- /**
45
- * NOTE: Having `position` and `rectangle` as observables compromises the performance of diagram
46
- * so we want to have a way to refresh the hash for change detection to pick up new hash when we resize
47
- * the class view box or move it.
48
- */
49
- forceRefreshHash(): void {
50
- this.dummyObservable = {};
51
- }
52
-
53
32
  edgePoint = (): Point =>
54
33
  new Point(
55
34
  this.position.x + this.rectangle.width,
@@ -17,8 +17,8 @@
17
17
  import type { Point } from './DSLDiagram_Point';
18
18
 
19
19
  export class Vector {
20
- x: number;
21
- y: number;
20
+ readonly x: number;
21
+ readonly y: number;
22
22
 
23
23
  constructor(x: number, y: number) {
24
24
  this.x = x;
@@ -29,7 +29,7 @@ export class Vector {
29
29
  return new Vector(b.x - a.x, b.y - a.y);
30
30
  }
31
31
 
32
- norm(): Vector {
32
+ unit(): Vector {
33
33
  const norm = Math.sqrt(this.x * this.x + this.y * this.y);
34
34
  return new Vector(this.x / norm, this.y / norm);
35
35
  }
@@ -35,7 +35,10 @@ import type { V1_Point } from '../../model/packageableElements/diagram/geometry/
35
35
  import type { V1_Rectangle } from '../../model/packageableElements/diagram/geometry/V1_DSLDiagram_Rectangle';
36
36
  import type { V1_PropertyView } from '../../model/packageableElements/diagram/V1_DSLDiagram_PropertyView';
37
37
  import type { V1_GeneralizationView } from '../../model/packageableElements/diagram/V1_DSLDiagram_GeneralizationView';
38
- import { getClassView } from '../../../../../../helpers/DiagramHelper';
38
+ import {
39
+ getClassView,
40
+ _relationshipView_simplifyPath,
41
+ } from '../../../../../../helpers/DiagramHelper';
39
42
 
40
43
  const buildPoint = (point: V1_Point): Point => {
41
44
  const x = guaranteeNonNullable(point.x, `Point 'x' coordinate is missing`);
@@ -115,7 +118,7 @@ export const V1_buildPropertyView = (
115
118
  targetClassView,
116
119
  );
117
120
  view.path = propertyView.line.points.map((point) => buildPoint(point));
118
- view.possiblyFlattenPath(); // transform the line because we store only 2 end points that are inside points and we will calculate the offset
121
+ _relationshipView_simplifyPath(view); // transform the line because we store only 2 end points that are inside points and we will calculate the offset
119
122
  return view;
120
123
  };
121
124
 
@@ -141,7 +144,7 @@ export const V1_buildGeneralizationView = (
141
144
  targetClassView,
142
145
  );
143
146
  view.path = generalizationView.line.points.map((point) => buildPoint(point));
144
- view.possiblyFlattenPath(); // transform the line because we store only 2 end points that are inside points and we will calculate the offset
147
+ _relationshipView_simplifyPath(view); // transform the line because we store only 2 end points that are inside points and we will calculate the offset
145
148
  return view;
146
149
  };
147
150
 
@@ -18,7 +18,7 @@ import type { ClassView } from '../../../../../metamodels/pure/packageableElemen
18
18
  import type { Diagram } from '../../../../../metamodels/pure/packageableElements/diagram/DSLDiagram_Diagram';
19
19
  import type { GeneralizationView } from '../../../../../metamodels/pure/packageableElements/diagram/DSLDiagram_GeneralizationView';
20
20
  import type { PropertyView } from '../../../../../metamodels/pure/packageableElements/diagram/DSLDiagram_PropertyView';
21
- import type { RelationShipEdgeView } from '../../../../../metamodels/pure/packageableElements/diagram/DSLDiagram_RelationshipEdgeView';
21
+ import type { RelationshipEdgeView } from '../../../../../metamodels/pure/packageableElements/diagram/DSLDiagram_RelationshipEdgeView';
22
22
  import { V1_Point } from '../../model/packageableElements/diagram/geometry/V1_DSLDiagram_Point';
23
23
  import { V1_ClassView } from '../../model/packageableElements/diagram/V1_DSLDiagram_ClassView';
24
24
  import { V1_Diagram } from '../../model/packageableElements/diagram/V1_DSLDiagram_Diagram';
@@ -32,7 +32,7 @@ import {
32
32
  V1_transformPropertyReference,
33
33
  } from '@finos/legend-graph';
34
34
 
35
- const relationshipEdgeViewTransformer = (value: RelationShipEdgeView): string =>
35
+ const relationshipEdgeViewTransformer = (value: RelationshipEdgeView): string =>
36
36
  value.classView.value.id;
37
37
 
38
38
  const createRectangle = (height: number, width: number): V1_Rectangle => {
@@ -52,7 +52,7 @@ const createPoint = (x: number, y: number): V1_Point => {
52
52
  const transformPropertyView = (element: PropertyView): V1_PropertyView => {
53
53
  const view = new V1_PropertyView();
54
54
  const line = new V1_Line();
55
- line.points = element.fullPath;
55
+ line.points = element.pathForSerialization;
56
56
  view.line = line;
57
57
  view.property = V1_transformPropertyReference(element.property);
58
58
  view.sourceView = relationshipEdgeViewTransformer(element.from);
@@ -65,7 +65,7 @@ const transformGenerationView = (
65
65
  ): V1_GeneralizationView => {
66
66
  const view = new V1_GeneralizationView();
67
67
  const line = new V1_Line();
68
- line.points = element.fullPath;
68
+ line.points = element.pathForSerialization;
69
69
  view.line = line;
70
70
  view.sourceView = relationshipEdgeViewTransformer(element.from);
71
71
  view.targetView = relationshipEdgeViewTransformer(element.to);
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import { addUniqueEntry, changeEntry, deleteEntry } from '@finos/legend-shared';
18
+ import { action } from 'mobx';
19
+ import type { AssociationView } from '../../models/metamodels/pure/packageableElements/diagram/DSLDiagram_AssociationView';
20
+ import type { ClassView } from '../../models/metamodels/pure/packageableElements/diagram/DSLDiagram_ClassView';
21
+ import type { Diagram } from '../../models/metamodels/pure/packageableElements/diagram/DSLDiagram_Diagram';
22
+ import type { GeneralizationView } from '../../models/metamodels/pure/packageableElements/diagram/DSLDiagram_GeneralizationView';
23
+ import {
24
+ _findOrBuildPoint,
25
+ _relationshipView_simplifyPath,
26
+ _relationshipView_setPath,
27
+ } from '../../helpers/DiagramHelper';
28
+ import type { PropertyView } from '../../models/metamodels/pure/packageableElements/diagram/DSLDiagram_PropertyView';
29
+ import type { RelationshipEdgeView } from '../../models/metamodels/pure/packageableElements/diagram/DSLDiagram_RelationshipEdgeView';
30
+ import type { RelationshipView } from '../../models/metamodels/pure/packageableElements/diagram/DSLDiagram_RelationshipView';
31
+ import type { Point } from '../../models/metamodels/pure/packageableElements/diagram/geometry/DSLDiagram_Point';
32
+ import type { PositionedRectangle } from '../../models/metamodels/pure/packageableElements/diagram/geometry/DSLDiagram_PositionedRectangle';
33
+ import type { Rectangle } from '../../models/metamodels/pure/packageableElements/diagram/geometry/DSLDiagram_Rectangle';
34
+ import {
35
+ observe_AssociationView,
36
+ observe_ClassView,
37
+ observe_GeneralizationView,
38
+ observe_PropertyView,
39
+ } from '../../graphManager/action/changeDetection/DSLDiagram_ObserverHelper';
40
+
41
+ export const diagram_setClassViews = action(
42
+ (diagram: Diagram, val: ClassView[]): void => {
43
+ diagram.classViews = val.map(observe_ClassView);
44
+ },
45
+ );
46
+ export const diagram_addClassView = action(
47
+ (diagram: Diagram, val: ClassView): void => {
48
+ addUniqueEntry(diagram.classViews, observe_ClassView(val));
49
+ },
50
+ );
51
+ export const diagram_deleteClassView = action(
52
+ (diagram: Diagram, val: ClassView): void => {
53
+ deleteEntry(diagram.classViews, val);
54
+ },
55
+ );
56
+ export const diagram_setAssociationViews = action(
57
+ (diagram: Diagram, val: AssociationView[]): void => {
58
+ diagram.associationViews = val.map(observe_AssociationView);
59
+ },
60
+ );
61
+ export const diagram_deleteAssociationView = action(
62
+ (diagram: Diagram, val: AssociationView): void => {
63
+ deleteEntry(diagram.associationViews, val);
64
+ },
65
+ );
66
+ export const diagram_setGeneralizationViews = action(
67
+ (diagram: Diagram, val: GeneralizationView[]): void => {
68
+ diagram.generalizationViews = val.map(observe_GeneralizationView);
69
+ },
70
+ );
71
+ export const diagram_addGeneralizationView = action(
72
+ (diagram: Diagram, val: GeneralizationView): void => {
73
+ addUniqueEntry(
74
+ diagram.generalizationViews,
75
+ observe_GeneralizationView(val),
76
+ );
77
+ },
78
+ );
79
+ export const diagram_deleteGeneralizationView = action(
80
+ (diagram: Diagram, val: GeneralizationView): void => {
81
+ deleteEntry(diagram.generalizationViews, val);
82
+ },
83
+ );
84
+ export const diagram_setPropertyViews = action(
85
+ (diagram: Diagram, val: PropertyView[]): void => {
86
+ diagram.propertyViews = val.map(observe_PropertyView);
87
+ },
88
+ );
89
+ export const diagram_addPropertyView = action(
90
+ (diagram: Diagram, val: PropertyView): void => {
91
+ addUniqueEntry(diagram.propertyViews, observe_PropertyView(val));
92
+ },
93
+ );
94
+ export const diagram_deletePropertyView = action(
95
+ (diagram: Diagram, val: PropertyView): void => {
96
+ deleteEntry(diagram.propertyViews, val);
97
+ },
98
+ );
99
+
100
+ export const classView_setHideProperties = action(
101
+ (cv: ClassView, val: boolean): void => {
102
+ cv.hideProperties = val;
103
+ },
104
+ );
105
+ export const classView_setHideStereotypes = action(
106
+ (cv: ClassView, val: boolean): void => {
107
+ cv.hideStereotypes = val;
108
+ },
109
+ );
110
+ export const classView_setHideTaggedValues = action(
111
+ (cv: ClassView, val: boolean): void => {
112
+ cv.hideTaggedValues = val;
113
+ },
114
+ );
115
+ export const relationshipEdgeView_setOffsetX = action(
116
+ (r: RelationshipEdgeView, val: number): void => {
117
+ r.offsetX = val;
118
+ },
119
+ );
120
+ export const relationshipEdgeView_setOffsetY = action(
121
+ (r: RelationshipEdgeView, val: number): void => {
122
+ r.offsetY = val;
123
+ },
124
+ );
125
+
126
+ // To optimize performance we will not observe point (path)
127
+ export const relationshipView_changePoint = action(
128
+ (v: RelationshipView, val: Point, newVal: Point): void => {
129
+ changeEntry(v.path, val, newVal);
130
+ },
131
+ );
132
+ export const relationshipView_simplifyPath = action(
133
+ _relationshipView_simplifyPath,
134
+ );
135
+
136
+ export const findOrBuildPoint = action(_findOrBuildPoint);
137
+ export const relationshipView_setPath = action(_relationshipView_setPath);
138
+
139
+ // To optimize performance we will not observe rectangle
140
+ export const positionedRectangle_setRectangle = action(
141
+ (pR: PositionedRectangle, value: Rectangle): void => {
142
+ pR.rectangle = value;
143
+ },
144
+ );
145
+
146
+ // To optimize performance we will not observe point (path)
147
+ export const positionedRectangle_setPosition = action(
148
+ (pR: PositionedRectangle, value: Point): void => {
149
+ pR.position = value;
150
+ },
151
+ );
152
+ /**
153
+ * NOTE: Having `position` and `rectangle` as observables compromises the performance of diagram
154
+ * so we want to have a way to refresh the hash for change detection to pick up new hash when we resize
155
+ * the class view box or move it.
156
+ *
157
+ * We should re-consider the usefulness of this method, maybe it's more worthwhile to recompute hash
158
+ * for the whole diagram instead?
159
+ */
160
+ export const positionedRectangle_forceRefreshHash = action(
161
+ (pR: PositionedRectangle): void => {
162
+ pR.dummyObservable = {};
163
+ },
164
+ );
@@ -275,18 +275,24 @@ export class DiagramEditorState extends ElementEditorState {
275
275
  return 'diagram-editor__cursor--resize';
276
276
  } else if (this.renderer.mouseOverClassProperty) {
277
277
  return this.isReadOnly ||
278
- this.renderer.mouseOverClassProperty.owner.isReadOnly
278
+ this.editorStore.graphManagerState.isElementReadOnly(
279
+ this.renderer.mouseOverClassProperty.owner,
280
+ )
279
281
  ? 'diagram-editor__cursor--not-allowed'
280
282
  : 'diagram-editor__cursor--text';
281
283
  } else if (this.renderer.mouseOverPropertyHolderViewLabel) {
282
284
  return this.isReadOnly ||
283
- this.renderer.mouseOverPropertyHolderViewLabel.property.value.owner
284
- .isReadOnly
285
+ this.editorStore.graphManagerState.isElementReadOnly(
286
+ this.renderer.mouseOverPropertyHolderViewLabel.property.value
287
+ .owner,
288
+ )
285
289
  ? 'diagram-editor__cursor--not-allowed'
286
290
  : 'diagram-editor__cursor--text';
287
291
  } else if (this.renderer.mouseOverClassName) {
288
292
  return this.isReadOnly ||
289
- this.renderer.mouseOverClassName.class.value.isReadOnly
293
+ this.editorStore.graphManagerState.isElementReadOnly(
294
+ this.renderer.mouseOverClassName.class.value,
295
+ )
290
296
  ? 'diagram-editor__cursor--not-allowed'
291
297
  : 'diagram-editor__cursor--text';
292
298
  } else if (this.renderer.mouseOverClassView) {
@@ -375,7 +381,12 @@ export class DiagramEditorState extends ElementEditorState {
375
381
  classView: ClassView,
376
382
  point: Point,
377
383
  ): void => {
378
- if (!this.isReadOnly && !classView.class.value.isReadOnly) {
384
+ if (
385
+ !this.isReadOnly &&
386
+ !this.editorStore.graphManagerState.isElementReadOnly(
387
+ classView.class.value,
388
+ )
389
+ ) {
379
390
  this.setInlineClassRenamerState(
380
391
  new DiagramEditorInlineClassRenamerState(this, classView, point),
381
392
  );
@@ -386,7 +397,10 @@ export class DiagramEditorState extends ElementEditorState {
386
397
  point: Point,
387
398
  propertyHolderView: PropertyHolderView | undefined,
388
399
  ): void => {
389
- if (!this.isReadOnly && !property.owner.isReadOnly) {
400
+ if (
401
+ !this.isReadOnly &&
402
+ !this.editorStore.graphManagerState.isElementReadOnly(property.owner)
403
+ ) {
390
404
  this.setInlinePropertyEditorState(
391
405
  new DiagramEditorInlinePropertyEditorState(
392
406
  this,
@@ -400,7 +414,12 @@ export class DiagramEditorState extends ElementEditorState {
400
414
  this.renderer.onClassPropertyDoubleClick = editProperty;
401
415
  this.renderer.handleEditProperty = editProperty;
402
416
  this.renderer.handleAddSimpleProperty = (classView: ClassView): void => {
403
- if (!this.isReadOnly && !classView.class.value.isReadOnly) {
417
+ if (
418
+ !this.isReadOnly &&
419
+ !this.editorStore.graphManagerState.isElementReadOnly(
420
+ classView.class.value,
421
+ )
422
+ ) {
404
423
  const _class = classView.class.value;
405
424
  class_addProperty(
406
425
  _class,
package/tsconfig.json CHANGED
@@ -44,6 +44,7 @@
44
44
  "./src/graph/DSLDiagram_PureGraphPlugin.ts",
45
45
  "./src/graphManager/DSLDiagram_GraphManagerHelper.ts",
46
46
  "./src/graphManager/DSLDiagram_PureGraphManagerPlugin.ts",
47
+ "./src/graphManager/action/changeDetection/DSLDiagram_ObserverHelper.ts",
47
48
  "./src/helpers/DiagramHelper.ts",
48
49
  "./src/models/DSLDiagram_ModelUtils.ts",
49
50
  "./src/models/metamodels/pure/packageableElements/diagram/DSLDiagram_AssociationView.ts",
@@ -73,6 +74,7 @@
73
74
  "./src/models/protocols/pure/v1/transformation/pureGraph/V1_DSLDiagram_GraphBuilderHelper.ts",
74
75
  "./src/models/protocols/pure/v1/transformation/pureGraph/V1_DSLDiagram_TransformerHelper.ts",
75
76
  "./src/models/protocols/pure/v1/transformation/pureProtocol/V1_DSLDiagram_ProtocolHelper.ts",
77
+ "./src/stores/studio/DSLDiagram_GraphModifierHelper.ts",
76
78
  "./src/stores/studio/DiagramEditorState.ts",
77
79
  "./src/components/studio/ClassDiagramPreview.tsx",
78
80
  "./src/components/studio/DSLDiagram_LegendStudioPlugin.tsx",