@peter.prib/renderengine 0.15.0 → 0.15.2
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/dist/renderengine-workspace.umd.js +776 -229
- package/dist/renderengine.umd.js +390 -107
- package/documentation/REFERENCE.md +496 -6
- package/examples/decision-workbench.html +26 -0
- package/package.json +2 -1
- package/src/charting/ArchimateDiagramEditor.js +2 -1
- package/src/charting/Edge.js +22 -0
- package/src/charting/archimate/ArchimateCanvasEditor.js +21 -5
- package/src/charting/archimate/ViewGroupTemplate.js +5 -2
- package/src/charting/diagramModel/DiagramJsonFileFormat.js +32 -0
- package/src/charting/diagramModel/DiagramModel.js +39 -0
- package/src/charting/diagramModel/DiagramView.js +97 -61
- package/src/charting/diagramModel/index.js +11 -10
- package/src/charting/diagrams/AddGroupToViewCommand.js +35 -0
- package/src/charting/diagrams/ArchimateModel.js +53 -13
- package/src/charting/diagrams/NestInstanceCommand.js +2 -1
- package/src/charting/templates/templateRegistry.js +70 -0
- package/src/index.js +4 -3
- package/src/workspace/index.js +3 -0
- package/src/workspace/parts/ArchimateEditorPart.js +2 -2
- package/src/workspace/parts/DecisionWorkbenchPart.js +58 -0
- package/src/workspace/parts/DiagramEditorPart.js +144 -131
- package/src/workspace/parts/ViewsPart.js +196 -0
package/dist/renderengine.umd.js
CHANGED
|
@@ -33564,6 +33564,67 @@
|
|
|
33564
33564
|
}
|
|
33565
33565
|
}
|
|
33566
33566
|
|
|
33567
|
+
/**
|
|
33568
|
+
* AddGroupToViewCommand — add a view-specific group to a view: its layout entry
|
|
33569
|
+
* is stored in view.folderLayout. Undo removes it.
|
|
33570
|
+
*/
|
|
33571
|
+
class AddGroupToViewCommand extends Command {
|
|
33572
|
+
/**
|
|
33573
|
+
* @param {ArchimateView} view
|
|
33574
|
+
* @param {Object} [options]
|
|
33575
|
+
* @param {string} [options.id]
|
|
33576
|
+
* @param {string} [options.name]
|
|
33577
|
+
* @param {number} [options.x]
|
|
33578
|
+
* @param {number} [options.y]
|
|
33579
|
+
* @param {number} [options.width]
|
|
33580
|
+
* @param {number} [options.height]
|
|
33581
|
+
* @param {number} [options.zIndex]
|
|
33582
|
+
* @param {Object} [options.appearance]
|
|
33583
|
+
* @param {string} [options.parentId]
|
|
33584
|
+
*/
|
|
33585
|
+
constructor(view, { id = `group-${Date.now().toString(36)}`, name = 'Group', x = 100, y = 100, width = 400, height = 140, zIndex = 0, appearance = {}, parentId = undefined } = {}) {
|
|
33586
|
+
super('Add group to view');
|
|
33587
|
+
this.view = view;
|
|
33588
|
+
this.groupId = id;
|
|
33589
|
+
this.entry = { x, y, width, height, name, zIndex, appearance, parentId };
|
|
33590
|
+
}
|
|
33591
|
+
|
|
33592
|
+
execute() {
|
|
33593
|
+
this.view.folderLayout[this.groupId] = { ...this.entry };
|
|
33594
|
+
}
|
|
33595
|
+
|
|
33596
|
+
undo() {
|
|
33597
|
+
delete this.view.folderLayout[this.groupId];
|
|
33598
|
+
}
|
|
33599
|
+
}
|
|
33600
|
+
|
|
33601
|
+
/**
|
|
33602
|
+
* RemoveGroupFromViewCommand — take a group off a view: its layout entry
|
|
33603
|
+
* goes, and what was drawn in it stays where it is (on the view, or in the
|
|
33604
|
+
* group around it). The model folder stays. Undo puts the same entry back.
|
|
33605
|
+
*/
|
|
33606
|
+
class RemoveGroupFromViewCommand extends Command {
|
|
33607
|
+
/**
|
|
33608
|
+
* @param {ArchimateView} view
|
|
33609
|
+
* @param {string} folderId - The folder the group draws
|
|
33610
|
+
*/
|
|
33611
|
+
constructor(view, folderId) {
|
|
33612
|
+
super('Remove group from view');
|
|
33613
|
+
this.view = view;
|
|
33614
|
+
this.folderId = folderId;
|
|
33615
|
+
this._entry = null;
|
|
33616
|
+
}
|
|
33617
|
+
|
|
33618
|
+
execute() {
|
|
33619
|
+
this._entry = this.view.folderLayout[this.folderId] ?? null;
|
|
33620
|
+
delete this.view.folderLayout[this.folderId];
|
|
33621
|
+
}
|
|
33622
|
+
|
|
33623
|
+
undo() {
|
|
33624
|
+
if (this._entry) this.view.folderLayout[this.folderId] = this._entry;
|
|
33625
|
+
}
|
|
33626
|
+
}
|
|
33627
|
+
|
|
33567
33628
|
/**
|
|
33568
33629
|
* Canonical, id-indexed home for ArchiMate model data (elements, relationships, views).
|
|
33569
33630
|
* Replaces ad-hoc flat-array handling and fixes multi-view import flattening.
|
|
@@ -34717,27 +34778,65 @@
|
|
|
34717
34778
|
}
|
|
34718
34779
|
|
|
34719
34780
|
/**
|
|
34720
|
-
* The folders drawn on this view as groups:
|
|
34721
|
-
*
|
|
34722
|
-
*
|
|
34723
|
-
* folder sits on the view itself).
|
|
34781
|
+
* The folders drawn on this view as groups: both model repository folders
|
|
34782
|
+
* and view-specific groups with bounds in `folderLayout`, bounds applied,
|
|
34783
|
+
* each after its parent. `parentId` is the nearest ancestor also drawn here.
|
|
34724
34784
|
*/
|
|
34725
34785
|
get placedFolders() {
|
|
34726
|
-
const
|
|
34727
|
-
const
|
|
34728
|
-
|
|
34729
|
-
|
|
34730
|
-
|
|
34731
|
-
|
|
34732
|
-
|
|
34786
|
+
const drawn = new Set(Object.keys(this.folderLayout));
|
|
34787
|
+
const modelFolders = this.model.allFolders();
|
|
34788
|
+
const modelFolderIds = new Set(modelFolders.map(f => f.id));
|
|
34789
|
+
|
|
34790
|
+
const result = [];
|
|
34791
|
+
for (const folder of modelFolders.filter(f => this.folderLayout[f.id])) {
|
|
34792
|
+
result.push({
|
|
34793
|
+
...folder,
|
|
34794
|
+
...this.folderLayout[folder.id],
|
|
34795
|
+
name: this.folderLayout[folder.id].name ?? folder.name,
|
|
34796
|
+
parentId: this._nearestPlaced(folder.parentId, drawn),
|
|
34797
|
+
});
|
|
34798
|
+
}
|
|
34799
|
+
for (const [id, layout] of Object.entries(this.folderLayout)) {
|
|
34800
|
+
if (!modelFolderIds.has(id)) {
|
|
34801
|
+
result.push({
|
|
34802
|
+
id,
|
|
34803
|
+
name: layout.name || 'Group',
|
|
34804
|
+
...layout,
|
|
34805
|
+
parentId: layout.parentId && drawn.has(layout.parentId) ? layout.parentId : undefined,
|
|
34806
|
+
});
|
|
34807
|
+
}
|
|
34808
|
+
}
|
|
34809
|
+
return result;
|
|
34733
34810
|
}
|
|
34734
34811
|
|
|
34735
|
-
/** The group on this view an element is drawn in: its
|
|
34812
|
+
/** The group on this view an element is drawn in: its explicit view parent group, or its model folder's nearest drawn ancestor. */
|
|
34736
34813
|
placedFolderOf(elementId) {
|
|
34737
|
-
const
|
|
34814
|
+
const inst = this.elementInstancesFor(elementId)[0];
|
|
34815
|
+
if (inst?.archi?.parent && this.folderLayout[inst.archi.parent]) {
|
|
34816
|
+
return inst.archi.parent;
|
|
34817
|
+
}
|
|
34818
|
+
if (inst?.parentId && this.folderLayout[inst.parentId]) {
|
|
34819
|
+
return inst.parentId;
|
|
34820
|
+
}
|
|
34821
|
+
const drawn = new Set(Object.keys(this.folderLayout));
|
|
34738
34822
|
return this._nearestPlaced(this.model.getElementFolder(elementId), drawn);
|
|
34739
34823
|
}
|
|
34740
34824
|
|
|
34825
|
+
/** Add a view-specific group to this view. One undo step (AddGroupToViewCommand). */
|
|
34826
|
+
addGroup(spec = {}) {
|
|
34827
|
+
const id = spec.id || `group-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
|
|
34828
|
+
const cmd = new AddGroupToViewCommand(this, { id, ...spec });
|
|
34829
|
+
this.history.execute(cmd);
|
|
34830
|
+
return this.folderLayout[id];
|
|
34831
|
+
}
|
|
34832
|
+
|
|
34833
|
+
/** Remove a group (view-specific or placed model folder) from this view. One undo step (RemoveGroupFromViewCommand). */
|
|
34834
|
+
removeGroup(groupId) {
|
|
34835
|
+
if (!this.folderLayout[groupId]) return false;
|
|
34836
|
+
this.history.execute(new RemoveGroupFromViewCommand(this, groupId));
|
|
34837
|
+
return true;
|
|
34838
|
+
}
|
|
34839
|
+
|
|
34741
34840
|
/** @private */
|
|
34742
34841
|
_nearestPlaced(folderId, drawn) {
|
|
34743
34842
|
for (let id = folderId; id; id = this.model.getFolder(id)?.parentId) {
|
|
@@ -35871,6 +35970,28 @@
|
|
|
35871
35970
|
clearWaypoints() {
|
|
35872
35971
|
this.waypoints = [];
|
|
35873
35972
|
}
|
|
35973
|
+
|
|
35974
|
+
/** The edge as plain JSON: its endpoints, label, waypoints, side pins and style overrides. */
|
|
35975
|
+
toJSON() {
|
|
35976
|
+
return {
|
|
35977
|
+
id: this.id,
|
|
35978
|
+
sourceId: this.sourceId,
|
|
35979
|
+
targetId: this.targetId,
|
|
35980
|
+
label: this.label,
|
|
35981
|
+
waypoints: this.waypoints.map(w => ({ x: w.x, y: w.y })),
|
|
35982
|
+
sourceSide: this.sourceSide,
|
|
35983
|
+
targetSide: this.targetSide,
|
|
35984
|
+
visible: this.visible,
|
|
35985
|
+
...this.styleOverrides(),
|
|
35986
|
+
};
|
|
35987
|
+
}
|
|
35988
|
+
|
|
35989
|
+
/** Reconstruct an Edge from plain JSON. */
|
|
35990
|
+
static fromJSON(json) {
|
|
35991
|
+
if (!json) throw new TypeError('Edge.fromJSON requires a JSON object');
|
|
35992
|
+
const { id, sourceId, targetId, ...rest } = json;
|
|
35993
|
+
return new Edge(id, sourceId, targetId, rest);
|
|
35994
|
+
}
|
|
35874
35995
|
}
|
|
35875
35996
|
|
|
35876
35997
|
/** Style keys the line's Archi type bits decide (dashes, arrows). */
|
|
@@ -44232,7 +44353,8 @@
|
|
|
44232
44353
|
execute() {
|
|
44233
44354
|
const { instance, parent } = this;
|
|
44234
44355
|
const { parent: _was, ...rest } = instance.archi ?? {};
|
|
44235
|
-
|
|
44356
|
+
const parentId = parent ? (parent.visualId ?? parent.id) : null;
|
|
44357
|
+
instance.archi = parentId ? { ...rest, parent: parentId } : (Object.keys(rest).length ? rest : null);
|
|
44236
44358
|
if (parent && (instance.zIndex ?? 0) <= (parent.zIndex ?? 0)) instance.zIndex = (parent.zIndex ?? 0) + 1;
|
|
44237
44359
|
}
|
|
44238
44360
|
|
|
@@ -44357,8 +44479,11 @@
|
|
|
44357
44479
|
return this.view.model.getFolder(this.id);
|
|
44358
44480
|
}
|
|
44359
44481
|
|
|
44360
|
-
get name() { return this.folder?.name ?? 'Group'; }
|
|
44361
|
-
set name(value) {
|
|
44482
|
+
get name() { return this.folder?.name ?? this.layout?.name ?? 'Group'; }
|
|
44483
|
+
set name(value) {
|
|
44484
|
+
if (this.folder) this.folder.name = value || 'Group';
|
|
44485
|
+
if (this.layout) this.layout.name = value || 'Group';
|
|
44486
|
+
}
|
|
44362
44487
|
|
|
44363
44488
|
// The layout keeps the top-left corner; a template is placed by its centre.
|
|
44364
44489
|
get x() { return this.layout.x + this.width / 2; }
|
|
@@ -44446,33 +44571,6 @@
|
|
|
44446
44571
|
}
|
|
44447
44572
|
}
|
|
44448
44573
|
|
|
44449
|
-
/**
|
|
44450
|
-
* RemoveGroupFromViewCommand — take a group off a view: its layout entry
|
|
44451
|
-
* goes, and what was drawn in it stays where it is (on the view, or in the
|
|
44452
|
-
* group around it). The model folder stays. Undo puts the same entry back.
|
|
44453
|
-
*/
|
|
44454
|
-
class RemoveGroupFromViewCommand extends Command {
|
|
44455
|
-
/**
|
|
44456
|
-
* @param {ArchimateView} view
|
|
44457
|
-
* @param {string} folderId - The folder the group draws
|
|
44458
|
-
*/
|
|
44459
|
-
constructor(view, folderId) {
|
|
44460
|
-
super('Remove group from view');
|
|
44461
|
-
this.view = view;
|
|
44462
|
-
this.folderId = folderId;
|
|
44463
|
-
this._entry = null;
|
|
44464
|
-
}
|
|
44465
|
-
|
|
44466
|
-
execute() {
|
|
44467
|
-
this._entry = this.view.folderLayout[this.folderId] ?? null;
|
|
44468
|
-
delete this.view.folderLayout[this.folderId];
|
|
44469
|
-
}
|
|
44470
|
-
|
|
44471
|
-
undo() {
|
|
44472
|
-
if (this._entry) this.view.folderLayout[this.folderId] = this._entry;
|
|
44473
|
-
}
|
|
44474
|
-
}
|
|
44475
|
-
|
|
44476
44574
|
/**
|
|
44477
44575
|
* ElementFilterRule — a filter's result on an ArchiMate view: shapes of the
|
|
44478
44576
|
* model elements it kept are drawn as usual, every other element dimmed.
|
|
@@ -46085,15 +46183,28 @@
|
|
|
46085
46183
|
return element ? treeLayerOf(element) : 'other';
|
|
46086
46184
|
}
|
|
46087
46185
|
|
|
46088
|
-
/** An element's box holds any box
|
|
46186
|
+
/** An element's box holds any box; a group holds any box or nested group; on a canvas, a block holds boxes. */
|
|
46089
46187
|
canHold(parentId, childId) {
|
|
46188
|
+
if (!parentId || !childId || parentId === childId) return false;
|
|
46090
46189
|
const parent = this.templates.get(parentId), child = this.templates.get(childId);
|
|
46091
|
-
if (!parent
|
|
46190
|
+
if (!parent || !child) return false;
|
|
46191
|
+
if (child instanceof ViewGroupTemplate && parent instanceof ViewGroupTemplate) {
|
|
46192
|
+
return !this.isAncestor(childId, parentId);
|
|
46193
|
+
}
|
|
46194
|
+
if (parent instanceof ViewGroupTemplate) {
|
|
46195
|
+
return !this.isAncestor(childId, parentId);
|
|
46196
|
+
}
|
|
46197
|
+
if (child instanceof ViewGroupTemplate) return false;
|
|
46198
|
+
if (!parent.instance || !child.instance) return false;
|
|
46092
46199
|
return !!this._elementOf(parentId) || parent.instance.content?.archiVisualType === 'canvas-model-block';
|
|
46093
46200
|
}
|
|
46094
46201
|
|
|
46095
|
-
/** An element dropped on another nests there when a relationship a nesting stands for (NESTING_KINDS) is allowed between them. */
|
|
46202
|
+
/** An element dropped on another nests there when a relationship a nesting stands for (NESTING_KINDS) is allowed between them, or when dropped into a group. */
|
|
46096
46203
|
nestsOnDrop(parentId, childId) {
|
|
46204
|
+
const parent = this.templates.get(parentId);
|
|
46205
|
+
if (parent instanceof ViewGroupTemplate) {
|
|
46206
|
+
return this.canHold(parentId, childId);
|
|
46207
|
+
}
|
|
46097
46208
|
if (!this._elementOf(parentId) || !this._elementOf(childId)) return false;
|
|
46098
46209
|
return this.allowedKinds(parentId, childId).some(kind => NESTING_KINDS.includes(kind));
|
|
46099
46210
|
}
|
|
@@ -46101,13 +46212,16 @@
|
|
|
46101
46212
|
nestCommand(childId, parentId) {
|
|
46102
46213
|
const child = this.templates.get(childId)?.instance;
|
|
46103
46214
|
if (!child) return null;
|
|
46104
|
-
|
|
46215
|
+
const parentTemplate = parentId ? this.templates.get(parentId) : null;
|
|
46216
|
+
const parentTarget = parentTemplate?.instance ?? (parentTemplate instanceof ViewGroupTemplate ? parentTemplate : null);
|
|
46217
|
+
return new NestInstanceCommand(child, parentTarget);
|
|
46105
46218
|
}
|
|
46106
46219
|
|
|
46107
|
-
/** After nesting an element in another: offer the relationship the nesting stands for (nestingKinds). */
|
|
46220
|
+
/** After nesting an element in another: offer the relationship the nesting stands for (nestingKinds). Groups have no relationship. */
|
|
46108
46221
|
nested(changes) {
|
|
46109
46222
|
let chain = Promise.resolve();
|
|
46110
46223
|
for (const { childId, parentId } of changes) {
|
|
46224
|
+
if (this.templates.get(parentId) instanceof ViewGroupTemplate) continue;
|
|
46111
46225
|
chain = chain.then(() => this.offerNestingRelationship(parentId, childId)); // taken out: nothing to offer
|
|
46112
46226
|
}
|
|
46113
46227
|
return chain;
|
|
@@ -49746,64 +49860,159 @@
|
|
|
49746
49860
|
new DrawioFileFormat(),
|
|
49747
49861
|
]);
|
|
49748
49862
|
|
|
49749
|
-
|
|
49750
|
-
|
|
49751
|
-
|
|
49752
|
-
|
|
49753
|
-
|
|
49754
|
-
|
|
49755
|
-
|
|
49756
|
-
|
|
49757
|
-
|
|
49758
|
-
|
|
49759
|
-
|
|
49760
|
-
|
|
49761
|
-
|
|
49762
|
-
|
|
49763
|
-
|
|
49764
|
-
|
|
49765
|
-
|
|
49766
|
-
|
|
49767
|
-
|
|
49768
|
-
|
|
49769
|
-
|
|
49770
|
-
|
|
49771
|
-
|
|
49772
|
-
|
|
49773
|
-
|
|
49774
|
-
|
|
49775
|
-
|
|
49776
|
-
|
|
49777
|
-
|
|
49778
|
-
|
|
49779
|
-
|
|
49780
|
-
|
|
49781
|
-
|
|
49782
|
-
|
|
49783
|
-
|
|
49784
|
-
|
|
49785
|
-
|
|
49786
|
-
|
|
49787
|
-
|
|
49788
|
-
|
|
49789
|
-
|
|
49790
|
-
|
|
49791
|
-
|
|
49792
|
-
|
|
49793
|
-
|
|
49794
|
-
|
|
49795
|
-
|
|
49796
|
-
|
|
49797
|
-
|
|
49798
|
-
|
|
49799
|
-
|
|
49800
|
-
|
|
49801
|
-
|
|
49802
|
-
|
|
49803
|
-
|
|
49804
|
-
|
|
49805
|
-
|
|
49806
|
-
|
|
49863
|
+
const TEMPLATE_CLASSES = Object.freeze({
|
|
49864
|
+
'rectangle': RectangleTemplate,
|
|
49865
|
+
'rounded-rectangle': RoundedRectangleTemplate,
|
|
49866
|
+
'stadium': StadiumTemplate,
|
|
49867
|
+
'predefined-process': PredefinedProcessTemplate,
|
|
49868
|
+
'class': ClassTemplate,
|
|
49869
|
+
'component': ComponentTemplate,
|
|
49870
|
+
'swimlane': SwimlaneTemplate,
|
|
49871
|
+
'circle': CircleTemplate,
|
|
49872
|
+
'final-state': FinalStateTemplate,
|
|
49873
|
+
'ellipse': EllipseTemplate,
|
|
49874
|
+
'diamond': DiamondTemplate,
|
|
49875
|
+
'triangle': TriangleTemplate,
|
|
49876
|
+
'pentagon': PentagonTemplate,
|
|
49877
|
+
'hexagon': HexagonTemplate,
|
|
49878
|
+
'octagon': OctagonTemplate,
|
|
49879
|
+
'star': StarTemplate,
|
|
49880
|
+
'parallelogram': ParallelogramTemplate,
|
|
49881
|
+
'trapezoid': TrapezoidTemplate,
|
|
49882
|
+
'manual-input': ManualInputTemplate,
|
|
49883
|
+
'cylinder': CylinderTemplate,
|
|
49884
|
+
'document': DocumentTemplate,
|
|
49885
|
+
'note': NoteTemplate,
|
|
49886
|
+
'cloud': CloudTemplate,
|
|
49887
|
+
'actor': ActorTemplate,
|
|
49888
|
+
'package': PackageTemplate,
|
|
49889
|
+
'box': BoxTemplate,
|
|
49890
|
+
'data-store': DataStoreTemplate,
|
|
49891
|
+
'lifeline': LifelineTemplate,
|
|
49892
|
+
});
|
|
49893
|
+
|
|
49894
|
+
const CLASS_TO_KEY = new Map(Object.entries(TEMPLATE_CLASSES).map(([k, c]) => [c, k]));
|
|
49895
|
+
|
|
49896
|
+
// Assign static templateType to each class
|
|
49897
|
+
for (const [type, cls] of Object.entries(TEMPLATE_CLASSES)) {
|
|
49898
|
+
cls.templateType = type;
|
|
49899
|
+
}
|
|
49900
|
+
|
|
49901
|
+
/** Returns the stable serialized type key for a template instance or template class. */
|
|
49902
|
+
function templateTypeKey(templateOrClass) {
|
|
49903
|
+
if (!templateOrClass) return 'rectangle';
|
|
49904
|
+
const c = typeof templateOrClass === 'function' ? templateOrClass : templateOrClass.constructor;
|
|
49905
|
+
if (CLASS_TO_KEY.has(c)) return CLASS_TO_KEY.get(c);
|
|
49906
|
+
if (Object.hasOwn(c, 'templateType')) return c.templateType;
|
|
49907
|
+
const name = c.name || '';
|
|
49908
|
+
const withoutSuffix = name.replace(/Template$/, '');
|
|
49909
|
+
const kebab = withoutSuffix.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
|
49910
|
+
return TEMPLATE_CLASSES[kebab] ? kebab : 'rectangle';
|
|
49911
|
+
}
|
|
49912
|
+
|
|
49913
|
+
/** Resolves a template class by its stable type key or class name, defaulting to RectangleTemplate. */
|
|
49914
|
+
function templateClassFor(key) {
|
|
49915
|
+
if (!key) return RectangleTemplate;
|
|
49916
|
+
if (TEMPLATE_CLASSES[key]) return TEMPLATE_CLASSES[key];
|
|
49917
|
+
const lower = String(key).toLowerCase();
|
|
49918
|
+
if (TEMPLATE_CLASSES[lower]) return TEMPLATE_CLASSES[lower];
|
|
49919
|
+
for (const [k, c] of Object.entries(TEMPLATE_CLASSES)) {
|
|
49920
|
+
if (c.name === key || c.name?.toLowerCase() === lower) return c;
|
|
49921
|
+
}
|
|
49922
|
+
return RectangleTemplate;
|
|
49923
|
+
}
|
|
49924
|
+
|
|
49925
|
+
/**
|
|
49926
|
+
* DiagramView — one diagram (tab) of a DiagramModel: its shapes, lines,
|
|
49927
|
+
* diagram-level line style and its own undo history (from DiagramEditorState).
|
|
49928
|
+
*
|
|
49929
|
+
* A DiagramEditor is bound directly to `templates`/`edges`, so edits land here
|
|
49930
|
+
* with nothing to save back, and the history survives the editor being rebuilt.
|
|
49931
|
+
*/
|
|
49932
|
+
class DiagramView extends DiagramEditorState {
|
|
49933
|
+
/**
|
|
49934
|
+
* @param {Object} options
|
|
49935
|
+
* @param {string} options.id
|
|
49936
|
+
* @param {string} options.title
|
|
49937
|
+
* @param {Map<string, Template>} [options.templates]
|
|
49938
|
+
* @param {Map<string, Edge>} [options.edges]
|
|
49939
|
+
* @param {Object} [options.edgeStyle] - Diagram-level line style defaults
|
|
49940
|
+
* @param {Object} [options.historyOptions] - Passed to CommandHistory (e.g. onChange)
|
|
49941
|
+
* @param {string} [options.documentation]
|
|
49942
|
+
* @param {Arrangement} [options.arrangement]
|
|
49943
|
+
*/
|
|
49944
|
+
constructor({ id, title, templates = new Map(), edges = new Map(), edgeStyle = {}, historyOptions = {}, documentation = undefined, arrangement = null }) {
|
|
49945
|
+
super({ historyOptions, arrangement });
|
|
49946
|
+
this.historyOptions = historyOptions;
|
|
49947
|
+
this.id = id;
|
|
49948
|
+
this.title = title;
|
|
49949
|
+
this.documentation = documentation;
|
|
49950
|
+
this.templates = templates;
|
|
49951
|
+
this.edges = edges;
|
|
49952
|
+
this.edgeStyle = edgeStyle;
|
|
49953
|
+
}
|
|
49954
|
+
|
|
49955
|
+
/** The shapes are what stack. */
|
|
49956
|
+
layerItems() {
|
|
49957
|
+
return [...this.templates.values()];
|
|
49958
|
+
}
|
|
49959
|
+
|
|
49960
|
+
/** The diagram as plain JSON: its shapes (by id and stable type), lines, line style and documentation. */
|
|
49961
|
+
toJSON() {
|
|
49962
|
+
return {
|
|
49963
|
+
id: this.id,
|
|
49964
|
+
title: this.title,
|
|
49965
|
+
documentation: this.documentation,
|
|
49966
|
+
templates: [...this.templates].map(([id, t]) => ({
|
|
49967
|
+
id,
|
|
49968
|
+
type: templateTypeKey(t),
|
|
49969
|
+
name: t.name,
|
|
49970
|
+
data: t.serialize(),
|
|
49971
|
+
})),
|
|
49972
|
+
edges: [...this.edges.values()].map(e => (typeof e.toJSON === 'function' ? e.toJSON() : JSON.parse(JSON.stringify(e)))),
|
|
49973
|
+
edgeStyle: JSON.parse(JSON.stringify(this.edgeStyle ?? {})),
|
|
49974
|
+
...(this.arrangement && { arrangement: this.arrangement.toJSON() }),
|
|
49975
|
+
};
|
|
49976
|
+
}
|
|
49977
|
+
|
|
49978
|
+
/** Reconstruct a DiagramView from plain JSON. */
|
|
49979
|
+
static fromJSON(json, historyOptions = {}) {
|
|
49980
|
+
if (!json) throw new TypeError('DiagramView.fromJSON requires a JSON object');
|
|
49981
|
+
const templates = new Map();
|
|
49982
|
+
for (const t of (json.templates ?? [])) {
|
|
49983
|
+
const Class = templateClassFor(t.type);
|
|
49984
|
+
templates.set(t.id, new Class(t.id, t.name, t.data ?? {}));
|
|
49985
|
+
}
|
|
49986
|
+
const edges = new Map();
|
|
49987
|
+
for (const e of (json.edges ?? [])) {
|
|
49988
|
+
edges.set(e.id, Edge.fromJSON(e));
|
|
49989
|
+
}
|
|
49990
|
+
const arrangement = json.arrangement ? Arrangement.fromJSON(json.arrangement) : null;
|
|
49991
|
+
return new DiagramView({
|
|
49992
|
+
id: json.id,
|
|
49993
|
+
title: json.title,
|
|
49994
|
+
templates,
|
|
49995
|
+
edges,
|
|
49996
|
+
edgeStyle: json.edgeStyle ?? {},
|
|
49997
|
+
documentation: json.documentation,
|
|
49998
|
+
historyOptions,
|
|
49999
|
+
arrangement,
|
|
50000
|
+
});
|
|
50001
|
+
}
|
|
50002
|
+
|
|
50003
|
+
/** An independent copy: shapes, lines, style and documentation are copied; history starts empty (same options). */
|
|
50004
|
+
copy(id, title, historyOptions = this.historyOptions) {
|
|
50005
|
+
return new DiagramView({
|
|
50006
|
+
id,
|
|
50007
|
+
title,
|
|
50008
|
+
templates: new Map([...this.templates].map(([tid, t]) => [tid, new t.constructor(tid, t.name, t.serialize())])),
|
|
50009
|
+
edges: new Map([...this.edges].map(([eid, e]) => [eid, e.clone()])),
|
|
50010
|
+
edgeStyle: { ...this.edgeStyle },
|
|
50011
|
+
documentation: this.documentation,
|
|
50012
|
+
historyOptions,
|
|
50013
|
+
arrangement: this.arrangement.copy(), // template ids are kept
|
|
50014
|
+
});
|
|
50015
|
+
}
|
|
49807
50016
|
}
|
|
49808
50017
|
|
|
49809
50018
|
/**
|
|
@@ -49861,6 +50070,75 @@
|
|
|
49861
50070
|
setTemplateType(templateType) {
|
|
49862
50071
|
this.templateType = templateType;
|
|
49863
50072
|
}
|
|
50073
|
+
|
|
50074
|
+
/** The diagram model as plain JSON: its name, templateType, line style defaults, active view and views. */
|
|
50075
|
+
toJSON() {
|
|
50076
|
+
return {
|
|
50077
|
+
version: 1,
|
|
50078
|
+
name: this.name,
|
|
50079
|
+
templateType: this.templateType,
|
|
50080
|
+
edgeStyle: JSON.parse(JSON.stringify(this.edgeStyle ?? {})),
|
|
50081
|
+
currentViewId: this.currentViewId,
|
|
50082
|
+
views: this.views().map(v => v.toJSON()),
|
|
50083
|
+
};
|
|
50084
|
+
}
|
|
50085
|
+
|
|
50086
|
+
/** Reconstruct a DiagramModel from plain JSON. */
|
|
50087
|
+
static fromJSON(json, historyOptions = {}) {
|
|
50088
|
+
if (!json) throw new TypeError('DiagramModel.fromJSON requires a JSON object');
|
|
50089
|
+
const model = new DiagramModel({
|
|
50090
|
+
name: json.name ?? '',
|
|
50091
|
+
templateType: json.templateType ?? 'generic',
|
|
50092
|
+
edgeStyle: json.edgeStyle ?? {},
|
|
50093
|
+
historyOptions,
|
|
50094
|
+
});
|
|
50095
|
+
const views = (json.views ?? []).map(vData => DiagramView.fromJSON(vData, model.historyOptions));
|
|
50096
|
+
for (const view of views) {
|
|
50097
|
+
model._insertView(model._adopt(view), { current: view.id === json.currentViewId });
|
|
50098
|
+
}
|
|
50099
|
+
if (json.currentViewId && model._views.has(json.currentViewId)) {
|
|
50100
|
+
model.currentViewId = json.currentViewId;
|
|
50101
|
+
} else if (model._views.size > 0 && !model.currentViewId) {
|
|
50102
|
+
model.currentViewId = model._views.keys().next().value;
|
|
50103
|
+
}
|
|
50104
|
+
const maxNum = Math.max(0, ...model.views().map(v => {
|
|
50105
|
+
const m = String(v.id).match(/\d+$/);
|
|
50106
|
+
return m ? parseInt(m[0], 10) : 0;
|
|
50107
|
+
}));
|
|
50108
|
+
model._nextId = maxNum + 1;
|
|
50109
|
+
model.markSaved();
|
|
50110
|
+
return model;
|
|
50111
|
+
}
|
|
50112
|
+
}
|
|
50113
|
+
|
|
50114
|
+
/**
|
|
50115
|
+
* DiagramJsonFileFormat — a diagram model as a file (`.diagram.json` or `.json`):
|
|
50116
|
+
* its name, palette category, line style defaults, views with templates, edges,
|
|
50117
|
+
* waypoints and arrangements (DiagramModel#toJSON), read back by DiagramModel.fromJSON.
|
|
50118
|
+
*/
|
|
50119
|
+
class DiagramJsonFileFormat extends ModelFileFormat {
|
|
50120
|
+
get label() { return '.diagram.json'; }
|
|
50121
|
+
get accept() { return '.diagram.json,.json'; }
|
|
50122
|
+
get fileName() { return 'diagrams.diagram.json'; }
|
|
50123
|
+
get featureName() { return 'DiagramJson'; }
|
|
50124
|
+
|
|
50125
|
+
/** JSON with a diagram model's shape: templateType and views array, or views array of diagrams. */
|
|
50126
|
+
recognizes(text) {
|
|
50127
|
+
try {
|
|
50128
|
+
const json = JSON.parse(text);
|
|
50129
|
+
return !!json && typeof json === 'object' && (Array.isArray(json.views) || typeof json.templateType === 'string');
|
|
50130
|
+
} catch {
|
|
50131
|
+
return false;
|
|
50132
|
+
}
|
|
50133
|
+
}
|
|
50134
|
+
|
|
50135
|
+
export(model) {
|
|
50136
|
+
return { data: JSON.stringify(model.toJSON(), null, 2), mimeType: 'application/json' };
|
|
50137
|
+
}
|
|
50138
|
+
|
|
50139
|
+
import(text) {
|
|
50140
|
+
return DiagramModel.fromJSON(JSON.parse(text));
|
|
50141
|
+
}
|
|
49864
50142
|
}
|
|
49865
50143
|
|
|
49866
50144
|
/**
|
|
@@ -51233,7 +51511,8 @@
|
|
|
51233
51511
|
}
|
|
51234
51512
|
|
|
51235
51513
|
/**
|
|
51236
|
-
* ArchimateDiagramEditor —
|
|
51514
|
+
* ArchimateDiagramEditor — legacy GraphDiagram-based ArchiMate editor extending DiagramEditor.
|
|
51515
|
+
* @deprecated Use ArchimateCanvasEditor (or ArchimateCanvasPart) for ArchiMate editing. RenderEngine.archimateDiagram() remains for read-only charts.
|
|
51237
51516
|
*
|
|
51238
51517
|
* Encapsulates: ArchiMate model, tree navigator, diagram tabs, rendering, controls wiring.
|
|
51239
51518
|
* Inherits: common rendering, drag/drop, toolbar, tree, filtering from DiagramEditor.
|
|
@@ -65434,6 +65713,7 @@ ${cells.map(c => ` <Cell${isHeader ? ' ss:StyleID="Header"' : ''}><Data ss:T
|
|
|
65434
65713
|
exports.DerivedRelationships = DerivedRelationships;
|
|
65435
65714
|
exports.DiagramEditor = DiagramEditor;
|
|
65436
65715
|
exports.DiagramEditorState = DiagramEditorState;
|
|
65716
|
+
exports.DiagramJsonFileFormat = DiagramJsonFileFormat;
|
|
65437
65717
|
exports.DiagramModel = DiagramModel;
|
|
65438
65718
|
exports.DiagramTabs = DiagramTabs;
|
|
65439
65719
|
exports.DiagramView = DiagramView;
|
|
@@ -65610,6 +65890,7 @@ ${cells.map(c => ` <Cell${isHeader ? ' ss:StyleID="Header"' : ''}><Data ss:T
|
|
|
65610
65890
|
exports.StructuredType = StructuredType;
|
|
65611
65891
|
exports.SurfaceChart3D = SurfaceChart3D;
|
|
65612
65892
|
exports.SwimlaneTemplate = SwimlaneTemplate;
|
|
65893
|
+
exports.TEMPLATE_CLASSES = TEMPLATE_CLASSES;
|
|
65613
65894
|
exports.TRACKERS = TRACKERS;
|
|
65614
65895
|
exports.TRACKER_APIS = TRACKER_APIS;
|
|
65615
65896
|
exports.TREE_LAYERS = TREE_LAYERS;
|
|
@@ -65740,6 +66021,8 @@ ${cells.map(c => ` <Cell${isHeader ? ' ss:StyleID="Header"' : ''}><Data ss:T
|
|
|
65740
66021
|
exports.stackingOrder = stackingOrder;
|
|
65741
66022
|
exports.strongerEmphasis = strongerEmphasis;
|
|
65742
66023
|
exports.svgMarkupToPngBlob = svgMarkupToPngBlob;
|
|
66024
|
+
exports.templateClassFor = templateClassFor;
|
|
66025
|
+
exports.templateTypeKey = templateTypeKey;
|
|
65743
66026
|
exports.toArchiExport = toArchiExport;
|
|
65744
66027
|
exports.toArchiFile = toArchiFile;
|
|
65745
66028
|
exports.toArchimateModel = toArchimateModel;
|