bpmn-auto-layout 0.2.0 → 0.3.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 -4
- package/dist/index.esm.js +578 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +580 -0
- package/dist/index.js.map +1 -0
- package/package.json +20 -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/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
|
-
};
|
package/lib/DiUtil.js
DELETED
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var ORIENTATION_THRESHOLD = {
|
|
4
|
-
'h:h': 20,
|
|
5
|
-
'v:v': 20,
|
|
6
|
-
'h:v': -10,
|
|
7
|
-
'v:h': -10
|
|
8
|
-
};
|
|
9
|
-
var ALIGNED_THRESHOLD = 2;
|
|
10
|
-
|
|
11
|
-
function getExpandedBounds(element) {
|
|
12
|
-
var bounds = {
|
|
13
|
-
x: Number.MAX_SAFE_INTEGER,
|
|
14
|
-
y: Number.MAX_SAFE_INTEGER,
|
|
15
|
-
width: 100,
|
|
16
|
-
height: 80
|
|
17
|
-
};
|
|
18
|
-
var padding = 36 / 2;
|
|
19
|
-
if (element.flowElements) {
|
|
20
|
-
|
|
21
|
-
// determine x/y bounds
|
|
22
|
-
element.flowElements.forEach(flowElement => {
|
|
23
|
-
var flowBounds = flowElement.bounds;
|
|
24
|
-
if (flowBounds) {
|
|
25
|
-
bounds.x = flowBounds.x < bounds.x ? flowBounds.x : bounds.x;
|
|
26
|
-
bounds.y = flowBounds.y < bounds.y ? flowBounds.y : bounds.y;
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
// determine width/height bounds
|
|
31
|
-
element.flowElements.forEach(flowElement => {
|
|
32
|
-
var flowBounds = flowElement.bounds;
|
|
33
|
-
if (flowBounds) {
|
|
34
|
-
var newWidth = (flowBounds.x - bounds.x) + flowBounds.width;
|
|
35
|
-
var newHeight = (flowBounds.y - bounds.y) + flowBounds.height;
|
|
36
|
-
bounds.width = bounds.width < newWidth ? newWidth : bounds.width;
|
|
37
|
-
bounds.height = bounds.height < newHeight ? newHeight : bounds.height;
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
bounds.x -= padding;
|
|
41
|
-
bounds.y -= padding;
|
|
42
|
-
bounds.width += (padding * 2);
|
|
43
|
-
bounds.height += padding * 2;
|
|
44
|
-
}
|
|
45
|
-
return bounds;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// see documentation bpmn.io/diagram-js/layout/ManhattanLayout
|
|
49
|
-
function connectRectangles(source, target, preferredLayout = 'h:h') {
|
|
50
|
-
var threshold = ORIENTATION_THRESHOLD[preferredLayout] || 0;
|
|
51
|
-
var orientation = getOrientation(source, target, threshold);
|
|
52
|
-
var directions = getDirections(orientation, preferredLayout);
|
|
53
|
-
var start = getMid(source);
|
|
54
|
-
var end = getMid(target);
|
|
55
|
-
|
|
56
|
-
// overlapping elements
|
|
57
|
-
if (!directions) {
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
if (directions === 'h:h') {
|
|
61
|
-
switch (orientation) {
|
|
62
|
-
case 'top-right':
|
|
63
|
-
case 'right':
|
|
64
|
-
case 'bottom-right':
|
|
65
|
-
start = { original: start, x: source.x, y: start.y };
|
|
66
|
-
end = { original: end, x: target.x + target.width, y: end.y };
|
|
67
|
-
break;
|
|
68
|
-
case 'top-left':
|
|
69
|
-
case 'left':
|
|
70
|
-
case 'bottom-left':
|
|
71
|
-
start = { original: start, x: source.x + source.width, y: start.y };
|
|
72
|
-
end = { original: end, x: target.x, y: end.y };
|
|
73
|
-
break;
|
|
74
|
-
}
|
|
75
|
-
} else if (directions === 'v:v') {
|
|
76
|
-
switch (orientation) {
|
|
77
|
-
case 'top-left':
|
|
78
|
-
case 'top':
|
|
79
|
-
case 'top-right':
|
|
80
|
-
start = { original: start, x: start.x, y: source.y + source.height };
|
|
81
|
-
end = { original: end, x: end.x, y: target.y };
|
|
82
|
-
break;
|
|
83
|
-
case 'bottom-left':
|
|
84
|
-
case 'bottom':
|
|
85
|
-
case 'bottom-right':
|
|
86
|
-
start = { original: start, x: start.x, y: source.y };
|
|
87
|
-
end = { original: end, x: end.x, y: target.y + target.height };
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
} else if (directions === 'v:h') {
|
|
91
|
-
switch (orientation) {
|
|
92
|
-
case 'top-left':
|
|
93
|
-
case 'top':
|
|
94
|
-
case 'top-right':
|
|
95
|
-
start = { original: start, x: start.x, y: source.y + source.height };
|
|
96
|
-
end = { original: end, x: target.x + target.width, y: end.y };
|
|
97
|
-
break;
|
|
98
|
-
case 'bottom-left':
|
|
99
|
-
case 'bottom':
|
|
100
|
-
case 'bottom-right':
|
|
101
|
-
start = { original: start, x: start.x, y: source.y };
|
|
102
|
-
end = { original: end, x: target.x, y: end.y };
|
|
103
|
-
break;
|
|
104
|
-
}
|
|
105
|
-
} else if (directions === 'h:v') {
|
|
106
|
-
switch (orientation) {
|
|
107
|
-
case 'top-left':
|
|
108
|
-
case 'top':
|
|
109
|
-
case 'top-right':
|
|
110
|
-
start = { original: start, x: source.x, y: start.y };
|
|
111
|
-
end = { original: end, x: end.x, y: target.y };
|
|
112
|
-
break;
|
|
113
|
-
case 'bottom-left':
|
|
114
|
-
case 'bottom':
|
|
115
|
-
case 'bottom-right':
|
|
116
|
-
start = { original: start, x: start.x, y: source.y };
|
|
117
|
-
start = { original: start, x: source.x + source.width, y: start.y };
|
|
118
|
-
break;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return connectPoints(start, end, directions);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function connectPoints(a, b, directions) {
|
|
126
|
-
var points = [];
|
|
127
|
-
if (!pointsAligned(a, b)) {
|
|
128
|
-
points = getBendpoints(a, b, directions);
|
|
129
|
-
}
|
|
130
|
-
points.unshift(a);
|
|
131
|
-
points.push(b);
|
|
132
|
-
return points;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function getBendpoints(a, b, directions) {
|
|
136
|
-
directions = directions || 'h:h';
|
|
137
|
-
var xmid, ymid;
|
|
138
|
-
|
|
139
|
-
// one point, next to a
|
|
140
|
-
if (directions === 'h:v') {
|
|
141
|
-
return [ { x: b.x, y: a.y } ];
|
|
142
|
-
} else
|
|
143
|
-
|
|
144
|
-
// one point, above a
|
|
145
|
-
if (directions === 'v:h') {
|
|
146
|
-
return [ { x: a.x, y: b.y } ];
|
|
147
|
-
} else {
|
|
148
|
-
|
|
149
|
-
// vertical edge xmid
|
|
150
|
-
if (directions === 'h:h') {
|
|
151
|
-
xmid = Math.round((b.x - a.x) / 2 + a.x);
|
|
152
|
-
return [
|
|
153
|
-
{ x: xmid, y: a.y },
|
|
154
|
-
{ x: xmid, y: b.y }
|
|
155
|
-
];
|
|
156
|
-
} else {
|
|
157
|
-
|
|
158
|
-
// horizontal edge ymid
|
|
159
|
-
if (directions === 'v:v') {
|
|
160
|
-
ymid = Math.round((b.y - a.y) / 2 + a.y);
|
|
161
|
-
return [
|
|
162
|
-
{ x: a.x, y: ymid },
|
|
163
|
-
{ x: b.x, y: ymid }
|
|
164
|
-
];
|
|
165
|
-
} else {
|
|
166
|
-
throw new Error(
|
|
167
|
-
'unknown directions: <' + directions + '>: ' +
|
|
168
|
-
'directions must be specified as {a direction}:{b direction} (direction in h|v)');
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// see documentation bpmn.io/diagram-js/layout/LayoutUtil &&
|
|
175
|
-
// bpmn.io/diagram-js/util/geometry
|
|
176
|
-
function getMid(bounds) {
|
|
177
|
-
return roundPoint({
|
|
178
|
-
x: bounds.x + (bounds.width || 0) / 2,
|
|
179
|
-
y: bounds.y + (bounds.height || 0) / 2
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function pointsAligned(a, b) {
|
|
184
|
-
if (Math.abs(a.x - b.x) <= ALIGNED_THRESHOLD) {
|
|
185
|
-
return 'h';
|
|
186
|
-
}
|
|
187
|
-
if (Math.abs(a.y - b.y) <= ALIGNED_THRESHOLD) {
|
|
188
|
-
return 'v';
|
|
189
|
-
}
|
|
190
|
-
return false;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function getDirections(orientation, defaultLayout) {
|
|
194
|
-
switch (orientation) {
|
|
195
|
-
case 'intersect':
|
|
196
|
-
return null;
|
|
197
|
-
case 'top':
|
|
198
|
-
case 'bottom':
|
|
199
|
-
return 'v:v';
|
|
200
|
-
case 'left':
|
|
201
|
-
case 'right':
|
|
202
|
-
return 'h:h';
|
|
203
|
-
|
|
204
|
-
// 'top-left'
|
|
205
|
-
// 'top-right'
|
|
206
|
-
// 'bottom-left'
|
|
207
|
-
// 'bottom-right'
|
|
208
|
-
default:
|
|
209
|
-
return defaultLayout;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function roundPoint(point) {
|
|
214
|
-
return {
|
|
215
|
-
x: Math.round(point.x),
|
|
216
|
-
y: Math.round(point.y)
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function getOrientation(rect, reference, padding) {
|
|
221
|
-
var rectOrientation = asTRBL(rect);
|
|
222
|
-
var referenceOrientation = asTRBL(reference);
|
|
223
|
-
var top = rectOrientation.bottom + padding <= referenceOrientation.top;
|
|
224
|
-
var right = rectOrientation.left - padding >= referenceOrientation.right;
|
|
225
|
-
var bottom = rectOrientation.top - padding >= referenceOrientation.bottom;
|
|
226
|
-
var left = rectOrientation.right + padding <= referenceOrientation.left;
|
|
227
|
-
var vertical = top ? 'top' : (bottom ? 'bottom' : null);
|
|
228
|
-
var horizontal = left ? 'left' : (right ? 'right' : null);
|
|
229
|
-
if (horizontal && vertical) {
|
|
230
|
-
return vertical + '-' + horizontal;
|
|
231
|
-
} else {
|
|
232
|
-
return horizontal || vertical || 'intersect';
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function asTRBL(bounds) {
|
|
237
|
-
return {
|
|
238
|
-
top: bounds.y,
|
|
239
|
-
right: bounds.x + (bounds.width || 0),
|
|
240
|
-
bottom: bounds.y + (bounds.height || 0),
|
|
241
|
-
left: bounds.x
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
function is(type, expected) {
|
|
246
|
-
var baseType = expected.split(':')[1];
|
|
247
|
-
var findType = type.indexOf(baseType) !== -1;
|
|
248
|
-
return findType;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
export {
|
|
252
|
-
getExpandedBounds,
|
|
253
|
-
connectRectangles,
|
|
254
|
-
connectPoints,
|
|
255
|
-
getBendpoints,
|
|
256
|
-
getMid,
|
|
257
|
-
pointsAligned,
|
|
258
|
-
getDirections,
|
|
259
|
-
roundPoint,
|
|
260
|
-
getOrientation,
|
|
261
|
-
asTRBL,
|
|
262
|
-
is
|
|
263
|
-
};
|