bpmn-auto-layout 0.2.0 → 0.4.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.
- package/README.md +8 -7
- package/dist/index.cjs +798 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.esm.js +796 -0
- package/dist/index.esm.js.map +1 -0
- package/package.json +21 -8
- package/index.js +0 -1
- package/lib/AutoLayout.js +0 -514
- package/lib/DiFactory.js +0 -152
- package/lib/DiUtil.js +0 -263
- package/lib/Tree.js +0 -335
package/lib/AutoLayout.js
DELETED
|
@@ -1,514 +0,0 @@
|
|
|
1
|
-
import BpmnModdle from 'bpmn-moddle';
|
|
2
|
-
|
|
3
|
-
import Tree from './Tree.js';
|
|
4
|
-
import DiFactory from './DiFactory.js';
|
|
5
|
-
import { is,getExpandedBounds, getBendpoints } from './DiUtil.js';
|
|
6
|
-
|
|
7
|
-
var PADDING_NODE = 'padding_node';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export default function AutoLayout() {
|
|
11
|
-
this.moddle = new BpmnModdle();
|
|
12
|
-
this.DiFactory = new DiFactory(this.moddle);
|
|
13
|
-
this.nodeCount = -1;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
AutoLayout.prototype.layoutProcess = async function(xmlStr) {
|
|
17
|
-
var self = this;
|
|
18
|
-
var moddle = this.moddle;
|
|
19
|
-
var createDiPlane = this.DiFactory.createDiPlane.bind(this.DiFactory);
|
|
20
|
-
var createDiDiagram = this.DiFactory.createDiDiagram.bind(this.DiFactory);
|
|
21
|
-
|
|
22
|
-
try {
|
|
23
|
-
var { rootElement: moddleWithoutDi } = await moddle.fromXML(xmlStr);
|
|
24
|
-
|
|
25
|
-
// create new di section
|
|
26
|
-
var root = moddleWithoutDi.get('rootElements').find(el => el.$type === 'bpmn:Process');
|
|
27
|
-
var rootDi = createDiPlane({
|
|
28
|
-
id: 'BPMNPlane_1',
|
|
29
|
-
bpmnElement: root
|
|
30
|
-
});
|
|
31
|
-
var newDiagram = createDiDiagram({
|
|
32
|
-
id: 'BPMNDiagram_1',
|
|
33
|
-
plane: rootDi
|
|
34
|
-
});
|
|
35
|
-
moddleWithoutDi.diagrams = [ newDiagram ];
|
|
36
|
-
|
|
37
|
-
// build the tree layout
|
|
38
|
-
self.tree = new Tree();
|
|
39
|
-
self._addTreeNode(root, root.flowElements);
|
|
40
|
-
self._buildTreeBreadFirstSearch(root);
|
|
41
|
-
console.log('tree built');
|
|
42
|
-
self.tree.UpdateTree();
|
|
43
|
-
console.log('tree updated');
|
|
44
|
-
|
|
45
|
-
// create di
|
|
46
|
-
self._layoutTreeBreadFirstSearch(root, rootDi);
|
|
47
|
-
console.log('bpmn element layout complete');
|
|
48
|
-
|
|
49
|
-
var { xml: result } = await moddle.toXML(moddleWithoutDi);
|
|
50
|
-
return Promise.resolve(result);
|
|
51
|
-
} catch (error) {
|
|
52
|
-
return Promise.reject(error);
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
AutoLayout.prototype._buildTreeBreadFirstSearch = function(rootFlowElement) {
|
|
57
|
-
var self = this;
|
|
58
|
-
var children = rootFlowElement.flowElements;
|
|
59
|
-
|
|
60
|
-
// queue holds visited elements
|
|
61
|
-
var queue = children ? [ ...children ] : [];
|
|
62
|
-
var elementOrConnection;
|
|
63
|
-
var outgoings;
|
|
64
|
-
while (queue.length !== 0) {
|
|
65
|
-
|
|
66
|
-
// get first
|
|
67
|
-
elementOrConnection = queue.shift();
|
|
68
|
-
if (elementOrConnection.$type !== 'bpmn:SequenceFlow' &&
|
|
69
|
-
elementOrConnection.$type !== 'bpmn:SubProcess') {
|
|
70
|
-
|
|
71
|
-
// add this node to the tree
|
|
72
|
-
self._addTreeNode(elementOrConnection, children);
|
|
73
|
-
}
|
|
74
|
-
if (elementOrConnection.$type === 'bpmn:SubProcess') {
|
|
75
|
-
self._explodeSubprocess(elementOrConnection, children);
|
|
76
|
-
}
|
|
77
|
-
if (elementOrConnection.$type !== 'bpmn:SequenceFlow') {
|
|
78
|
-
|
|
79
|
-
// only if source is an element
|
|
80
|
-
outgoings = getOutgoingConnection(elementOrConnection, children);
|
|
81
|
-
if (outgoings.length) {
|
|
82
|
-
outgoings.forEach(function(connection) {
|
|
83
|
-
|
|
84
|
-
// for layouting the connection
|
|
85
|
-
if (!connection.build_marked) {
|
|
86
|
-
connection.build_marked = true;
|
|
87
|
-
queue.push(connection);
|
|
88
|
-
}
|
|
89
|
-
var target = connection.get('targetRef');
|
|
90
|
-
if (!target.build_marked) {
|
|
91
|
-
self._addTreeNode(target, children);
|
|
92
|
-
queue.push(target);
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
AutoLayout.prototype._explodeSubprocess = function(flowElement, flowElements) {
|
|
101
|
-
|
|
102
|
-
// this element is a subprocess, append the subprocess node to the tree,
|
|
103
|
-
// then append the subprocess child elements to the subprocess node,
|
|
104
|
-
// then add the subprocess element children to the subprocess end node
|
|
105
|
-
/*
|
|
106
|
-
Before (Bpmn):
|
|
107
|
-
Process:
|
|
108
|
-
[start] --- [ subprocess_01 ] --- [end]
|
|
109
|
-
subprocess_01:
|
|
110
|
-
[sub_start] --- [ task_01 ] --- [sub_end]
|
|
111
|
-
|
|
112
|
-
After (Tree Nodes):
|
|
113
|
-
[start] --- [ subprocess_01 ] --- [sub_start] --- [ task_01] --- [sub_end] --- [end]
|
|
114
|
-
*/
|
|
115
|
-
// the idea is that the subprocess node will be positioned correctly within the overall tree
|
|
116
|
-
// and the rest of the tree will respect the sub processes elements.
|
|
117
|
-
// we'd just need to tweak the 'offsets' caused by the subprocess tree node when drawing
|
|
118
|
-
|
|
119
|
-
var self = this;
|
|
120
|
-
var subprocessNode = self._addTreeNode(flowElement, flowElements);
|
|
121
|
-
self._buildTreeBreadFirstSearch(flowElement);
|
|
122
|
-
if (flowElement.flowElements) {
|
|
123
|
-
var subprocessStartEvents = getStartEvents(flowElement.flowElements);
|
|
124
|
-
var subprocessStartNodes = subprocessStartEvents.map(startEvent => {
|
|
125
|
-
var startNode = self.tree.getNodeByName(startEvent.id);
|
|
126
|
-
return startNode;
|
|
127
|
-
});
|
|
128
|
-
var subprocessEndEvents = getEndEvents(flowElement.flowElements);
|
|
129
|
-
var subprocessEndNode = subprocessEndEvents.map(endEvent => {
|
|
130
|
-
return self.tree.getNodeByName(endEvent.id);
|
|
131
|
-
})[0]; // assume only one end node
|
|
132
|
-
// set the children of the subprocessNode as the children of the subprocessEndNode
|
|
133
|
-
var outgoing = getOutgoingConnection(flowElement, flowElements);
|
|
134
|
-
if (outgoing.length) {
|
|
135
|
-
outgoing.forEach(function(connection) {
|
|
136
|
-
var source = connection.get('targetRef');
|
|
137
|
-
let child;
|
|
138
|
-
if (source.build_marked) {
|
|
139
|
-
child = self.tree.getNodeByName(source.id);
|
|
140
|
-
} else {
|
|
141
|
-
child = self._addTreeNode(source, flowElements);
|
|
142
|
-
}
|
|
143
|
-
self.tree.addParentToNode(child.id, subprocessNode.id);
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
var childNodes = [ ...subprocessNode.children ].filter(child => {
|
|
147
|
-
return !subprocessStartNodes.find(startNode => startNode.id === child.id);
|
|
148
|
-
});
|
|
149
|
-
childNodes.forEach(childNode => {
|
|
150
|
-
this.tree.addParentToNode(childNode.id, subprocessEndNode.id);
|
|
151
|
-
self._balanceTreeNodeParentLevels(childNode);
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
// remove children from subprocess node
|
|
155
|
-
subprocessNode.children.forEach(childNode => {
|
|
156
|
-
this.tree.removeParentFromNode(childNode.id, subprocessNode.id);
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
// remove parents from subprocessStartNodes
|
|
160
|
-
subprocessStartNodes.forEach(subprocessStartNode => {
|
|
161
|
-
var parents = [ ...subprocessStartNode.parents ];
|
|
162
|
-
parents.forEach(parentNode => {
|
|
163
|
-
this.tree.removeParentFromNode(subprocessStartNode.id, parentNode.id);
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
// set the subprocessStartNodes as the children of the subprocessNode
|
|
168
|
-
subprocessStartNodes.forEach(subprocessStartNode => {
|
|
169
|
-
this.tree.addParentToNode(subprocessStartNode.id, subprocessNode.id);
|
|
170
|
-
self._balanceTreeNodeParentLevels(subprocessStartNode);
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
AutoLayout.prototype._addTreeNode = function(flowElement, flowElements) {
|
|
176
|
-
var getDefaultSize = this.DiFactory._getDefaultSize.bind(this.DiFactory);
|
|
177
|
-
var self = this;
|
|
178
|
-
let node;
|
|
179
|
-
if (!flowElement.build_marked) {
|
|
180
|
-
|
|
181
|
-
// add the node
|
|
182
|
-
flowElement.build_marked = true;
|
|
183
|
-
var parentNodes = [];
|
|
184
|
-
|
|
185
|
-
// get parents
|
|
186
|
-
var incoming = getIncomingConnection(flowElement, flowElements);
|
|
187
|
-
if (incoming.length) {
|
|
188
|
-
incoming.forEach(function(connection) {
|
|
189
|
-
var source = connection.get('sourceRef');
|
|
190
|
-
let parent;
|
|
191
|
-
if (source.$type !== 'bpmn:SubProcess') {
|
|
192
|
-
if (source.build_marked) {
|
|
193
|
-
parent = self.tree.getNodeByName(source.id);
|
|
194
|
-
} else {
|
|
195
|
-
parent = self._addTreeNode(source, flowElements);
|
|
196
|
-
}
|
|
197
|
-
} else {
|
|
198
|
-
|
|
199
|
-
// subprocesses are be handled elsewhere
|
|
200
|
-
var subprocessEndEvents = getEndEvents(source.flowElements);
|
|
201
|
-
var subprocessEnd = subprocessEndEvents[0]; // assume only one end elements
|
|
202
|
-
if (subprocessEnd && subprocessEnd.build_marked) {
|
|
203
|
-
parent = self.tree.getNodeByName(subprocessEnd.id);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
if (parent) {
|
|
207
|
-
parentNodes.push(parent);
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
var size = getDefaultSize(flowElement);
|
|
212
|
-
node = this.tree.add(this.nodeCount, flowElement.id, size.width, size.height);
|
|
213
|
-
this.nodeCount += 1;
|
|
214
|
-
if (parentNodes.length === 0) {
|
|
215
|
-
|
|
216
|
-
// root
|
|
217
|
-
this.tree.addParentToNode(node.id, -1);
|
|
218
|
-
} else {
|
|
219
|
-
parentNodes.forEach(parentNode => this.tree.addParentToNode(node.id, parentNode.id));
|
|
220
|
-
}
|
|
221
|
-
console.log('Added ' + node.dsc + ' as Node ' + this.nodeCount);
|
|
222
|
-
self._balanceTreeNodeParentLevels(node);
|
|
223
|
-
flowElement.nodeId = node.id;
|
|
224
|
-
return node;
|
|
225
|
-
} else {
|
|
226
|
-
|
|
227
|
-
// find and return the node
|
|
228
|
-
return self.tree.getNodeByName(flowElement.id);
|
|
229
|
-
}
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
AutoLayout.prototype._balanceTreeNodeParentLevels = function(node) {
|
|
233
|
-
var self = this;
|
|
234
|
-
var maxParentLevel = node._getLevel() - 1;
|
|
235
|
-
|
|
236
|
-
// pad out levels such that node parents are at same level
|
|
237
|
-
var oldParents = [ ...node.parents ];
|
|
238
|
-
oldParents.forEach(parent => {
|
|
239
|
-
let padParent = parent;
|
|
240
|
-
while (padParent._getLevel() < maxParentLevel) {
|
|
241
|
-
var oldParent = padParent;
|
|
242
|
-
self.tree.removeParentFromNode(node.id, oldParent.id);
|
|
243
|
-
padParent = self.tree.add(this.nodeCount, PADDING_NODE, 100, 1);
|
|
244
|
-
|
|
245
|
-
// console messaging
|
|
246
|
-
var message = 'Added ' + PADDING_NODE + padParent.id + ' between ' +
|
|
247
|
-
oldParent.dsc + (oldParent.dsc === PADDING_NODE ? oldParent.id : '') + ' and ' +
|
|
248
|
-
node.dsc + (node.dsc === PADDING_NODE ? node.id : '');
|
|
249
|
-
console.log(message);
|
|
250
|
-
|
|
251
|
-
// sort out parents
|
|
252
|
-
this.nodeCount += 1;
|
|
253
|
-
self.tree.addParentToNode(node.id, padParent.id);
|
|
254
|
-
self.tree.addParentToNode(padParent.id, oldParent.id);
|
|
255
|
-
}
|
|
256
|
-
});
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
AutoLayout.prototype._layoutTreeBreadFirstSearch = function(parentFlowElement, rootDi) {
|
|
260
|
-
var children = parentFlowElement.flowElements;
|
|
261
|
-
var startEvents = children && getStartEvents(children);
|
|
262
|
-
|
|
263
|
-
// groups are elements with the same distance
|
|
264
|
-
var group = {
|
|
265
|
-
elements: [],
|
|
266
|
-
connections: [],
|
|
267
|
-
distance: 0
|
|
268
|
-
};
|
|
269
|
-
if (startEvents) {
|
|
270
|
-
startEvents.forEach(startEvent => {
|
|
271
|
-
startEvent.marked = true;
|
|
272
|
-
startEvent.dist = 0;
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// queue holds visited elements
|
|
277
|
-
var queue = startEvents ? [ ...startEvents ] : [];
|
|
278
|
-
var elementOrConnection;
|
|
279
|
-
var outgoings;
|
|
280
|
-
while (queue.length !== 0) {
|
|
281
|
-
|
|
282
|
-
// get first
|
|
283
|
-
elementOrConnection = queue.shift();
|
|
284
|
-
|
|
285
|
-
// insert element into group
|
|
286
|
-
group = this._groupElement(elementOrConnection, group, rootDi);
|
|
287
|
-
group.offsets = parentFlowElement.offsets;
|
|
288
|
-
if (elementOrConnection.$type === 'bpmn:SubProcess') {
|
|
289
|
-
this._layoutTreeBreadFirstSearch(elementOrConnection, rootDi);
|
|
290
|
-
}
|
|
291
|
-
if (elementOrConnection.$type !== 'bpmn:SequenceFlow') {
|
|
292
|
-
|
|
293
|
-
// only if source is an element
|
|
294
|
-
outgoings = getOutgoingConnection(elementOrConnection, children);
|
|
295
|
-
if (outgoings.length) {
|
|
296
|
-
outgoings.forEach(function(connection) {
|
|
297
|
-
|
|
298
|
-
// for layouting the connection
|
|
299
|
-
if (!connection.marked) {
|
|
300
|
-
connection.marked = true;
|
|
301
|
-
connection.dist = elementOrConnection.dist + 1;
|
|
302
|
-
queue.push(connection);
|
|
303
|
-
}
|
|
304
|
-
var target = connection.get('targetRef');
|
|
305
|
-
if (!target.marked) {
|
|
306
|
-
target.marked = true;
|
|
307
|
-
target.dist = elementOrConnection.dist + 1;
|
|
308
|
-
queue.push(target);
|
|
309
|
-
}
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
if (elementOrConnection && elementOrConnection.$type !== 'bpmn:SubProcess') {
|
|
315
|
-
this._layoutGroup(group, rootDi);
|
|
316
|
-
}
|
|
317
|
-
};
|
|
318
|
-
|
|
319
|
-
AutoLayout.prototype._groupElement = function(elementOrConnection, group, parentDi) {
|
|
320
|
-
if (elementOrConnection.dist === group.distance) {
|
|
321
|
-
if (elementOrConnection.$type === 'bpmn:SequenceFlow') {
|
|
322
|
-
group.connections.push(elementOrConnection);
|
|
323
|
-
} else {
|
|
324
|
-
group.elements.push(elementOrConnection);
|
|
325
|
-
}
|
|
326
|
-
} else {
|
|
327
|
-
this._layoutGroup(group, parentDi);
|
|
328
|
-
group = {
|
|
329
|
-
elements: elementOrConnection.$type === 'bpmn:SequenceFlow' ? [] : [ elementOrConnection ],
|
|
330
|
-
connections: elementOrConnection.$type === 'bpmn:SequenceFlow' ? [ elementOrConnection ] : [],
|
|
331
|
-
distance: elementOrConnection.dist
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
return group;
|
|
335
|
-
};
|
|
336
|
-
|
|
337
|
-
AutoLayout.prototype._layoutGroup = function(group, parentDi) {
|
|
338
|
-
this._layoutElements(group, parentDi);
|
|
339
|
-
this._layoutConnections(group, parentDi);
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
AutoLayout.prototype._layoutElements = function(group, parentDi) {
|
|
343
|
-
var self = this;
|
|
344
|
-
var createDi = this.DiFactory.createBpmnElementDi.bind(this.DiFactory);
|
|
345
|
-
var getDefaultSize = this.DiFactory._getDefaultSize.bind(this.DiFactory);
|
|
346
|
-
var _layoutTreeBreadFirstSearch = this._layoutTreeBreadFirstSearch.bind(this);
|
|
347
|
-
var elements = group.elements;
|
|
348
|
-
var childrenDi = parentDi.get('planeElement');
|
|
349
|
-
var elementDi;
|
|
350
|
-
var pos = {};
|
|
351
|
-
var size;
|
|
352
|
-
var offsets = (group && group.offsets) || { x: 0, y: 0 };
|
|
353
|
-
elements.forEach(function(element) {
|
|
354
|
-
|
|
355
|
-
// check for existing DI element
|
|
356
|
-
var found = childrenDi.find(childDi => {
|
|
357
|
-
return childDi.id.includes(element.id);
|
|
358
|
-
});
|
|
359
|
-
size = getDefaultSize(element);
|
|
360
|
-
var treeNode = self.tree.getNodeById(element.nodeId);
|
|
361
|
-
if (treeNode) {
|
|
362
|
-
pos.x = treeNode.XPosition + offsets.x;
|
|
363
|
-
pos.y = treeNode.YPosition + offsets.y;
|
|
364
|
-
}
|
|
365
|
-
element.bounds = Object.assign({}, size, pos);
|
|
366
|
-
elementDi = createDi('shape', element, pos);
|
|
367
|
-
if (found) {
|
|
368
|
-
|
|
369
|
-
// replace exisiting with latest
|
|
370
|
-
childrenDi.splice(childrenDi.indexOf(found), 1, elementDi);
|
|
371
|
-
} else {
|
|
372
|
-
childrenDi.push(elementDi);
|
|
373
|
-
}
|
|
374
|
-
if (element.flowElements && element.$type === 'bpmn:SubProcess') {
|
|
375
|
-
var bounds = getExpandedBounds(element);
|
|
376
|
-
element.flowElements.forEach(el => { el.marked = false; });
|
|
377
|
-
var offsetX = (element.bounds.x + element.bounds.width / 2) - (bounds.x + bounds.width / 2);
|
|
378
|
-
var offsetY = (element.bounds.y + element.bounds.height / 2) - (bounds.y + bounds.height / 2);
|
|
379
|
-
element.offsets = {
|
|
380
|
-
x: offsetX + offsets.x,
|
|
381
|
-
y: offsetY
|
|
382
|
-
};
|
|
383
|
-
_layoutTreeBreadFirstSearch(element, parentDi);
|
|
384
|
-
}
|
|
385
|
-
});
|
|
386
|
-
};
|
|
387
|
-
|
|
388
|
-
AutoLayout.prototype._layoutConnections = function(group, parentDi) {
|
|
389
|
-
var self = this;
|
|
390
|
-
var createDi = this.DiFactory.createBpmnElementDi.bind(this.DiFactory);
|
|
391
|
-
var createDiWaypoint = this.DiFactory.createDiWaypoint.bind(this.DiFactory);
|
|
392
|
-
var childrenDi = parentDi.get('planeElement');
|
|
393
|
-
var connections = group.connections;
|
|
394
|
-
connections.forEach(function(connection) {
|
|
395
|
-
|
|
396
|
-
// check for existing DI element
|
|
397
|
-
var found = childrenDi.find(childDi => {
|
|
398
|
-
return childDi.id.includes(connection.id);
|
|
399
|
-
});
|
|
400
|
-
var connectionDi = createDi('connection', connection);
|
|
401
|
-
var sourceRef = connection.get('sourceRef');
|
|
402
|
-
var targetRef = connection.get('targetRef');
|
|
403
|
-
var sourceNode = self.tree.getNodeByName(sourceRef.id);
|
|
404
|
-
var directTarget = is(sourceRef.$type, 'bpmn:SubProcess');
|
|
405
|
-
if (!directTarget && sourceNode && sourceNode.children && sourceNode.children.length > 0) {
|
|
406
|
-
sourceNode.children.forEach(function(node) {
|
|
407
|
-
if (node.dsc === targetRef.id) {
|
|
408
|
-
directTarget = true;
|
|
409
|
-
}
|
|
410
|
-
});
|
|
411
|
-
}
|
|
412
|
-
if (sourceNode && sourceNode.children && sourceNode.children.length > 0 && !directTarget) {
|
|
413
|
-
|
|
414
|
-
// this connection needs to accommodate padding nodes
|
|
415
|
-
// check for any padding nodes and go through those coords
|
|
416
|
-
var oldPoints = connectionDi.waypoint;
|
|
417
|
-
var newPoints = [ oldPoints[0] ];
|
|
418
|
-
|
|
419
|
-
// get node for sourceRef
|
|
420
|
-
var pathNodes = getPathToTarget(sourceNode, targetRef.id);
|
|
421
|
-
pathNodes.pop();
|
|
422
|
-
if (is(sourceRef.$type, 'bpmn:Gateway')) {
|
|
423
|
-
var start = oldPoints[0];
|
|
424
|
-
var first = {
|
|
425
|
-
x: pathNodes[1].XPosition + (group.offsets ? group.offsets.x : 0),
|
|
426
|
-
y: pathNodes[1].YPosition + (group.offsets ? group.offsets.y : 0)
|
|
427
|
-
};
|
|
428
|
-
getBendpoints(start, first, 'h:h').forEach(bendpoint => {
|
|
429
|
-
|
|
430
|
-
// console.log( `x: ${bendpoint.x}, y: ${bendpoint.y} - bend`)
|
|
431
|
-
newPoints.push(createDiWaypoint(bendpoint));
|
|
432
|
-
});
|
|
433
|
-
pathNodes.shift();
|
|
434
|
-
}
|
|
435
|
-
pathNodes.shift();
|
|
436
|
-
var points = [];
|
|
437
|
-
pathNodes.forEach(pathNode => {
|
|
438
|
-
|
|
439
|
-
// console.log( `x: ${pathNode.XPosition}, y: ${pathNode.YPosition}`)
|
|
440
|
-
points.push({
|
|
441
|
-
x: pathNode.XPosition + (group.offsets ? group.offsets.x : 0),
|
|
442
|
-
y: pathNode.YPosition + (group.offsets ? group.offsets.y : 0)
|
|
443
|
-
});
|
|
444
|
-
});
|
|
445
|
-
var lastPoint = oldPoints[oldPoints.length - 1];
|
|
446
|
-
if (points.length > 0) {
|
|
447
|
-
points.forEach(point => {
|
|
448
|
-
newPoints.push(createDiWaypoint(point));
|
|
449
|
-
});
|
|
450
|
-
var directions = 'h:v';
|
|
451
|
-
getBendpoints(points[points.length - 1], lastPoint, directions).forEach(bendpoint => {
|
|
452
|
-
newPoints.push(createDiWaypoint(bendpoint));
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
newPoints.push(lastPoint);
|
|
456
|
-
connectionDi.waypoint = newPoints;
|
|
457
|
-
}
|
|
458
|
-
if (found) {
|
|
459
|
-
|
|
460
|
-
// replace exisiting with latest
|
|
461
|
-
childrenDi.splice(childrenDi.indexOf(found), 1, connectionDi);
|
|
462
|
-
} else {
|
|
463
|
-
childrenDi.push(connectionDi);
|
|
464
|
-
}
|
|
465
|
-
});
|
|
466
|
-
};
|
|
467
|
-
|
|
468
|
-
function getPathToTarget(sourceNode, targetId) {
|
|
469
|
-
if (sourceNode === undefined) {
|
|
470
|
-
return undefined;
|
|
471
|
-
}
|
|
472
|
-
if (sourceNode.dsc === targetId) {
|
|
473
|
-
return [ sourceNode ];
|
|
474
|
-
}
|
|
475
|
-
if (sourceNode.children) {
|
|
476
|
-
let pathToTarget;
|
|
477
|
-
sourceNode.children.forEach(source => {
|
|
478
|
-
if (source.dsc === PADDING_NODE || source.dsc === targetId) {
|
|
479
|
-
var path = getPathToTarget(source, targetId);
|
|
480
|
-
if (path) {
|
|
481
|
-
pathToTarget = path;
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
});
|
|
485
|
-
if (pathToTarget) {
|
|
486
|
-
return [ sourceNode, ...pathToTarget ];
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
return undefined;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
function getStartEvents(flowElements) {
|
|
493
|
-
return flowElements ? flowElements.filter(e => {
|
|
494
|
-
return is(e.$type, 'bpmn:StartEvent');
|
|
495
|
-
}) : [];
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
function getEndEvents(flowElements) {
|
|
499
|
-
return flowElements ? flowElements.filter(e => {
|
|
500
|
-
return is(e.$type, 'bpmn:EndEvent');
|
|
501
|
-
}) : [];
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
function getOutgoingConnection(source, flowElements) {
|
|
505
|
-
return flowElements ? flowElements.filter(e => {
|
|
506
|
-
return is(e.$type, 'bpmn:SequenceFlow') && e.get('sourceRef').id === source.id;
|
|
507
|
-
}) : [];
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
function getIncomingConnection(target, flowElements) {
|
|
511
|
-
return flowElements ? flowElements.filter(e => {
|
|
512
|
-
return is(e.$type, 'bpmn:SequenceFlow') && e.get('targetRef').id === target.id;
|
|
513
|
-
}) : [];
|
|
514
|
-
}
|
package/lib/DiFactory.js
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
import { map, assign, pick } from 'min-dash';
|
|
4
|
-
import { is, connectRectangles, getExpandedBounds } from './DiUtil.js';
|
|
5
|
-
|
|
6
|
-
export default function DiFactory(moddle) {
|
|
7
|
-
this._model = moddle;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
DiFactory.prototype._isExpanded = function(element) {
|
|
11
|
-
return element && element.flowElements ? element.flowElements.length > 0 : false;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
DiFactory.prototype.create = function(type, attrs) {
|
|
15
|
-
return this._model.create(type, attrs || {});
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
DiFactory.prototype.createDiLabel = function() {
|
|
19
|
-
return this.create('bpmndi:BPMNLabel', {
|
|
20
|
-
bounds: this.createDiBounds()
|
|
21
|
-
});
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
DiFactory.prototype.createDiShape = function(semantic, bounds, attrs) {
|
|
25
|
-
return this.create('bpmndi:BPMNShape', assign({
|
|
26
|
-
bpmnElement: semantic,
|
|
27
|
-
bounds: this.createDiBounds(bounds)
|
|
28
|
-
}, attrs));
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
DiFactory.prototype.createDiBounds = function(bounds) {
|
|
32
|
-
return this.create('dc:Bounds', bounds);
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
DiFactory.prototype.createDiWaypoints = function(waypoints) {
|
|
36
|
-
var self = this;
|
|
37
|
-
|
|
38
|
-
return map(waypoints, function(pos) {
|
|
39
|
-
return self.createDiWaypoint(pos);
|
|
40
|
-
});
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
DiFactory.prototype.createDiWaypoint = function(point) {
|
|
44
|
-
return this.create('dc:Point', pick(point, [ 'x', 'y' ]));
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
DiFactory.prototype.createDiEdge = function(semantic, waypoints, attrs) {
|
|
48
|
-
return this.create('bpmndi:BPMNEdge', assign({
|
|
49
|
-
bpmnElement: semantic,
|
|
50
|
-
waypoint: this.createDiWaypoints(waypoints)
|
|
51
|
-
}, attrs));
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
DiFactory.prototype.createDiPlane = function(attrs) {
|
|
55
|
-
return this.create('bpmndi:BPMNPlane', attrs);
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
DiFactory.prototype.createDiDiagram = function(attrs) {
|
|
59
|
-
return this.create('bpmndi:BPMNDiagram', attrs);
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
// see documentation: bpmn.io/bpmn-js/lib/features/modeling/BpmnFactory
|
|
63
|
-
DiFactory.prototype.createBpmnElementDi = function(elementType, attrs, pos) {
|
|
64
|
-
let di;
|
|
65
|
-
let businessObject;
|
|
66
|
-
attrs = attrs || {};
|
|
67
|
-
if (elementType === 'diagram') {
|
|
68
|
-
di = this.createDiDiagram({
|
|
69
|
-
id: attrs.id
|
|
70
|
-
});
|
|
71
|
-
} else
|
|
72
|
-
if (elementType === 'root') {
|
|
73
|
-
di = this.createDiPlane(attrs);
|
|
74
|
-
} else
|
|
75
|
-
if (elementType === 'connection') {
|
|
76
|
-
var connection = attrs;
|
|
77
|
-
var targetRef = connection.get('targetRef');
|
|
78
|
-
var sourceRef = connection.get('sourceRef');
|
|
79
|
-
var targetBounds = targetRef.bounds;
|
|
80
|
-
var sourceBounds = sourceRef.bounds;
|
|
81
|
-
var preferredLayout = 'h:h';
|
|
82
|
-
if (is(sourceRef.$type, 'bpmn:StartEvent') || is(targetRef.$type, 'bpmn:EndEvent')) {
|
|
83
|
-
preferredLayout = 'h:v';
|
|
84
|
-
}
|
|
85
|
-
var waypoints = connectRectangles(sourceBounds, targetBounds, preferredLayout);
|
|
86
|
-
businessObject = this.create(attrs.$type, connection);
|
|
87
|
-
di = this.createDiEdge(businessObject, waypoints, {
|
|
88
|
-
id: '_BPMNConnection_' + connection.id
|
|
89
|
-
});
|
|
90
|
-
} else {
|
|
91
|
-
var isExpanded = this._isExpanded(attrs);
|
|
92
|
-
attrs.isExpanded = isExpanded;
|
|
93
|
-
var size = this._getDefaultSize(attrs);
|
|
94
|
-
var bounds = assign({}, size, pos);
|
|
95
|
-
businessObject = this.create(attrs.$type, attrs);
|
|
96
|
-
di = this.createDiShape(businessObject, bounds, {
|
|
97
|
-
id: '_BPMNShape_' + attrs.id,
|
|
98
|
-
isExpanded
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
return di;
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
DiFactory.prototype._getDefaultSize = function(element) {
|
|
105
|
-
var elementType = element.$type;
|
|
106
|
-
|
|
107
|
-
if (is(elementType, 'bpmn:SubProcess')) {
|
|
108
|
-
element.isExpanded = this._isExpanded(element);
|
|
109
|
-
if (element.isExpanded) {
|
|
110
|
-
var bounds = getExpandedBounds(element);
|
|
111
|
-
return bounds;
|
|
112
|
-
}
|
|
113
|
-
return { width: 100, height: 80 };
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (is(elementType, 'bpmn:Task')) {
|
|
117
|
-
return { width: 100, height: 80 };
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (is(elementType, 'bpmn:Gateway')) {
|
|
121
|
-
return { width: 50, height: 50 };
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (is(elementType, 'bpmn:Event')) {
|
|
125
|
-
return { width: 36, height: 36 };
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (is(elementType, 'bpmn:Participant')) {
|
|
129
|
-
if (element.isExpanded) {
|
|
130
|
-
return getExpandedBounds(element);
|
|
131
|
-
}
|
|
132
|
-
return { width: 400, height: 100 };
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (is(elementType, 'bpmn:Lane')) {
|
|
136
|
-
return { width: 400, height: 100 };
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (is(elementType, 'bpmn:DataObjectReference')) {
|
|
140
|
-
return { width: 36, height: 50 };
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (is(elementType, 'bpmn:DataStoreReference')) {
|
|
144
|
-
return { width: 50, height: 50 };
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (is(elementType, 'bpmn:TextAnnotation')) {
|
|
148
|
-
return { width: 100, height: 30 };
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return { width: 100, height: 80 };
|
|
152
|
-
};
|