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/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
|
-
};
|
package/lib/Tree.js
DELETED
|
@@ -1,335 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
This tree is a version of ECOTree.js (by Emilio Cortegoso Lobato), with modifications.
|
|
3
|
-
These modifications include:
|
|
4
|
-
- supporting multiple parents
|
|
5
|
-
- removed all node styling code
|
|
6
|
-
- removed tree orientation code in favour of left to right orientation
|
|
7
|
-
References:
|
|
8
|
-
- ECOTree.js, Emilio Cortegoso Lobato
|
|
9
|
-
- "A Node-Positioning Algorithm for General Trees", Walker II, J. Q.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
function TreeNode(id, dsc, w, h) {
|
|
13
|
-
this.id = id;
|
|
14
|
-
this.dsc = dsc;
|
|
15
|
-
this.w = w;
|
|
16
|
-
this.h = h;
|
|
17
|
-
this.dbIndex = 0;
|
|
18
|
-
this.XPosition = 0;
|
|
19
|
-
this.YPosition = 0;
|
|
20
|
-
this.prelim = 0;
|
|
21
|
-
this.modifier = 0;
|
|
22
|
-
this.leftNeighbor = null;
|
|
23
|
-
this.rightNeighbor = null;
|
|
24
|
-
this.parents = [];
|
|
25
|
-
this.children = [];
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
TreeNode.prototype._getLevel = function() {
|
|
29
|
-
if (this.id === -1 || this.parents === undefined || this.parents.length === 0) {
|
|
30
|
-
return 0;
|
|
31
|
-
} else {
|
|
32
|
-
let maxLevel = 0;
|
|
33
|
-
this.parents.forEach(parent => {
|
|
34
|
-
var parentLevel = parent._getLevel();
|
|
35
|
-
maxLevel = (maxLevel < parentLevel) ? parentLevel : maxLevel;
|
|
36
|
-
});
|
|
37
|
-
return maxLevel + 1;
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
TreeNode.prototype._getChildrenCount = function() {
|
|
42
|
-
return this.children ? this.children.length : 0;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
TreeNode.prototype._getLeftSibling = function() {
|
|
46
|
-
if (!this.leftNeighbor) {
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
var haveSameParent = this.leftNeighbor.parents.find(lParent => {
|
|
50
|
-
return this.parents.find(tParent => tParent.id === lParent.id);
|
|
51
|
-
});
|
|
52
|
-
return haveSameParent ? this.leftNeighbor : null;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
TreeNode.prototype._getRightSibling = function() {
|
|
56
|
-
if (!this.rightNeighbor) {
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
var haveSameParent = this.rightNeighbor.parents.find(rParent => {
|
|
60
|
-
return this.parents.find(tParent => tParent.id === rParent.id);
|
|
61
|
-
});
|
|
62
|
-
return haveSameParent ? this.rightNeighbor : null;
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
TreeNode.prototype._getChildAt = function(i) {
|
|
66
|
-
return this.children[i];
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
TreeNode.prototype._getChildrenCenter = function(tree) {
|
|
70
|
-
var first = this._getFirstChild();
|
|
71
|
-
var last = this._getLastChild();
|
|
72
|
-
return first.prelim + ((last.prelim - first.prelim) + tree._getNodeSize(last)) / 2;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
TreeNode.prototype._getFirstChild = function() {
|
|
76
|
-
return this._getChildAt(0);
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
TreeNode.prototype._getLastChild = function() {
|
|
80
|
-
return this._getChildAt(this._getChildrenCount() - 1);
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
export default function Tree() {
|
|
84
|
-
this.config = {
|
|
85
|
-
iMaxDepth: 1000,
|
|
86
|
-
iLevelSeparation: 40,
|
|
87
|
-
iSiblingSeparation: 40,
|
|
88
|
-
iSubtreeSeparation: 60,
|
|
89
|
-
topXAdjustment: 0,
|
|
90
|
-
topYAdjustment: 0
|
|
91
|
-
};
|
|
92
|
-
this.self = this;
|
|
93
|
-
this.maxLevelHeight = [];
|
|
94
|
-
this.maxLevelWidth = [];
|
|
95
|
-
this.previousLevelNode = [];
|
|
96
|
-
this.rootYOffset = 0;
|
|
97
|
-
this.rootXOffset = 0;
|
|
98
|
-
this.nDatabaseNodes = [];
|
|
99
|
-
this.mapIDs = {};
|
|
100
|
-
this.root = new TreeNode(-1, null, null, 2, 2);
|
|
101
|
-
this.iLastSearch = 0;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Layout algorithm
|
|
105
|
-
Tree._firstWalk = function(tree, node, level, prevSiblings = []) {
|
|
106
|
-
|
|
107
|
-
// console.log('_firstWalk()')
|
|
108
|
-
var leftSibling = null;
|
|
109
|
-
node.XPosition = 0;
|
|
110
|
-
node.YPosition = 0;
|
|
111
|
-
node.prelim = 0;
|
|
112
|
-
node.modifier = 0;
|
|
113
|
-
node.leftNeighbor = null;
|
|
114
|
-
node.rightNeighbor = null;
|
|
115
|
-
tree._setLevelHeight(node, level);
|
|
116
|
-
tree._setLevelWidth(node, level);
|
|
117
|
-
tree._setNeighbors(node, level);
|
|
118
|
-
if (node._getChildrenCount() === 0 || level === tree.config.iMaxDepth) {
|
|
119
|
-
leftSibling = node._getLeftSibling();
|
|
120
|
-
if (leftSibling != null) {
|
|
121
|
-
node.prelim = leftSibling.prelim + tree._getNodeSize(leftSibling) + tree.config.iSiblingSeparation;
|
|
122
|
-
} else {
|
|
123
|
-
node.prelim = 0;
|
|
124
|
-
}
|
|
125
|
-
} else {
|
|
126
|
-
var n = node._getChildrenCount();
|
|
127
|
-
for (var i = 0; i < n; i++) {
|
|
128
|
-
var iChild = node._getChildAt(i);
|
|
129
|
-
Tree._firstWalk(tree, iChild, level + 1, [ ...prevSiblings, iChild.id ]);
|
|
130
|
-
}
|
|
131
|
-
var midPoint = node._getChildrenCenter(tree);
|
|
132
|
-
midPoint -= tree._getNodeSize(node) / 2;
|
|
133
|
-
leftSibling = node._getLeftSibling();
|
|
134
|
-
if (leftSibling != null && !prevSiblings.includes(leftSibling.id)) {
|
|
135
|
-
node.prelim = leftSibling.prelim + tree._getNodeSize(leftSibling) + tree.config.iSiblingSeparation;
|
|
136
|
-
node.modifier = node.prelim - midPoint;
|
|
137
|
-
Tree._apportion(tree, node, level);
|
|
138
|
-
} else {
|
|
139
|
-
node.prelim = midPoint;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
Tree._apportion = function(tree, node, level) {
|
|
145
|
-
|
|
146
|
-
// console.log('_apportion()')
|
|
147
|
-
var firstChild = node._getFirstChild();
|
|
148
|
-
var firstChildLeftNeighbor = firstChild.leftNeighbor;
|
|
149
|
-
var j = 1;
|
|
150
|
-
for (var k = tree.config.iMaxDepth - level; firstChild != null && firstChildLeftNeighbor != null && j <= k;) {
|
|
151
|
-
var modifierSumRight = 0;
|
|
152
|
-
var modifierSumLeft = 0;
|
|
153
|
-
var rightAncestor = firstChild;
|
|
154
|
-
var leftAncestor = firstChildLeftNeighbor;
|
|
155
|
-
for (var l = 0; l < j; l++) {
|
|
156
|
-
rightAncestor = rightAncestor.parents[0];
|
|
157
|
-
leftAncestor = leftAncestor.parents[0];
|
|
158
|
-
modifierSumRight += rightAncestor.modifier;
|
|
159
|
-
modifierSumLeft += leftAncestor.modifier;
|
|
160
|
-
}
|
|
161
|
-
var totalGap = (firstChildLeftNeighbor.prelim + modifierSumLeft + tree._getNodeSize(firstChildLeftNeighbor) + tree.config.iSubtreeSeparation) - (firstChild.prelim + modifierSumRight);
|
|
162
|
-
if (totalGap > 0) {
|
|
163
|
-
var subtreeAux = node;
|
|
164
|
-
var numSubtrees = 0;
|
|
165
|
-
for (; subtreeAux != null && subtreeAux !== leftAncestor; subtreeAux = subtreeAux._getLeftSibling()) {
|
|
166
|
-
numSubtrees++;
|
|
167
|
-
}
|
|
168
|
-
if (subtreeAux != null) {
|
|
169
|
-
var subtreeMoveAux = node;
|
|
170
|
-
var singleGap = totalGap / numSubtrees;
|
|
171
|
-
for (; subtreeMoveAux !== leftAncestor; subtreeMoveAux = subtreeMoveAux._getLeftSibling()) {
|
|
172
|
-
subtreeMoveAux.prelim += totalGap;
|
|
173
|
-
subtreeMoveAux.modifier += totalGap;
|
|
174
|
-
totalGap -= singleGap;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
j++;
|
|
179
|
-
if (firstChild._getChildrenCount() === 0) {
|
|
180
|
-
firstChild = tree._getLeftmost(node, 0, j);
|
|
181
|
-
} else {
|
|
182
|
-
firstChild = firstChild._getFirstChild();
|
|
183
|
-
}
|
|
184
|
-
if (firstChild != null) {
|
|
185
|
-
firstChildLeftNeighbor = firstChild.leftNeighbor;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
Tree._secondWalk = function(tree, node, level, X, Y, prevSiblings = []) {
|
|
191
|
-
|
|
192
|
-
// console.log('_secondWalk()')
|
|
193
|
-
if (level <= tree.config.iMaxDepth) {
|
|
194
|
-
var xTmp = tree.rootXOffset + node.prelim + X;
|
|
195
|
-
var yTmp = tree.rootYOffset + Y;
|
|
196
|
-
var maxsizeTmp = 0;
|
|
197
|
-
var nodesizeTmp = 0;
|
|
198
|
-
var flag = false;
|
|
199
|
-
|
|
200
|
-
maxsizeTmp = tree.maxLevelWidth[level];
|
|
201
|
-
flag = true;
|
|
202
|
-
nodesizeTmp = node.w;
|
|
203
|
-
|
|
204
|
-
node.XPosition = xTmp;
|
|
205
|
-
node.YPosition = yTmp + (maxsizeTmp - nodesizeTmp) / 2;
|
|
206
|
-
|
|
207
|
-
if (flag) {
|
|
208
|
-
var swapTmp = node.XPosition;
|
|
209
|
-
node.XPosition = node.YPosition;
|
|
210
|
-
node.YPosition = swapTmp;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
if (node._getChildrenCount() !== 0) {
|
|
214
|
-
Tree._secondWalk(tree, node._getFirstChild(), level + 1, X + node.modifier, Y + maxsizeTmp + tree.config.iLevelSeparation, [ ...prevSiblings, node.id ]);
|
|
215
|
-
}
|
|
216
|
-
var rightSibling = node._getRightSibling();
|
|
217
|
-
if (rightSibling != null && !prevSiblings.includes(rightSibling.id)) { Tree._secondWalk(tree, rightSibling, level, X, Y, [ ...prevSiblings, node.id ]); }
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
Tree.prototype._positionTree = function() {
|
|
222
|
-
|
|
223
|
-
// console.log('_positionTree()')
|
|
224
|
-
this.maxLevelHeight = [];
|
|
225
|
-
this.maxLevelWidth = [];
|
|
226
|
-
this.previousLevelNode = [];
|
|
227
|
-
Tree._firstWalk(this.self, this.root, 0);
|
|
228
|
-
this.rootXOffset = this.config.topXAdjustment + this.root.XPosition;
|
|
229
|
-
this.rootYOffset = this.config.topYAdjustment + this.root.YPosition;
|
|
230
|
-
Tree._secondWalk(this.self, this.root, 0, 0, 0);
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
Tree.prototype._setLevelHeight = function(node, level) {
|
|
234
|
-
if (this.maxLevelHeight[level] == null) { this.maxLevelHeight[level] = 0; }
|
|
235
|
-
if (this.maxLevelHeight[level] < node.h) { this.maxLevelHeight[level] = node.h; }
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
Tree.prototype._setLevelWidth = function(node, level) {
|
|
239
|
-
if (this.maxLevelWidth[level] == null) { this.maxLevelWidth[level] = 0; }
|
|
240
|
-
if (this.maxLevelWidth[level] < node.w) { this.maxLevelWidth[level] = node.w; }
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
Tree.prototype._setNeighbors = function(node, level) {
|
|
244
|
-
var tempNeighbour = this.previousLevelNode[level];
|
|
245
|
-
if (tempNeighbour && tempNeighbour.id !== node.id) {
|
|
246
|
-
node.leftNeighbor = this.previousLevelNode[level];
|
|
247
|
-
if (node.leftNeighbor != null) {
|
|
248
|
-
node.leftNeighbor.rightNeighbor = node;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
this.previousLevelNode[level] = node;
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
Tree.prototype._getNodeSize = function(node) {
|
|
255
|
-
return node.h;
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
Tree.prototype._getLeftmost = function(node, level, maxlevel) {
|
|
259
|
-
if (level >= maxlevel) return node;
|
|
260
|
-
if (node._getChildrenCount() === 0) return null;
|
|
261
|
-
|
|
262
|
-
var n = node._getChildrenCount();
|
|
263
|
-
for (var i = 0; i < n; i++) {
|
|
264
|
-
var iChild = node._getChildAt(i);
|
|
265
|
-
var leftmostDescendant = this._getLeftmost(iChild, level + 1, maxlevel);
|
|
266
|
-
if (leftmostDescendant != null) { return leftmostDescendant; }
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
return null;
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
Tree.prototype.UpdateTree = function() {
|
|
273
|
-
this._positionTree();
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
Tree.prototype.add = function(id, dsc, w, h) {
|
|
277
|
-
var node = new TreeNode(id, dsc, w, h);
|
|
278
|
-
var i = this.nDatabaseNodes.length;
|
|
279
|
-
node.dbIndex = this.mapIDs[id] = i;
|
|
280
|
-
this.nDatabaseNodes[i] = node;
|
|
281
|
-
return node;
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
Tree.prototype.addParentToNode = function(nodeId, parentId) {
|
|
285
|
-
|
|
286
|
-
// retrieve nodes from list
|
|
287
|
-
var node = this.getNodeById(nodeId);
|
|
288
|
-
var parent = (parentId === -1) ? this.root : this.getNodeById(parentId);
|
|
289
|
-
if (node === undefined) {
|
|
290
|
-
throw new Error('Node not found');
|
|
291
|
-
}
|
|
292
|
-
if (parent === undefined) {
|
|
293
|
-
throw new Error('Parent node not found');
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// confirm this parents hasn't already been added to this node
|
|
297
|
-
var found = node.parents.find(parent => parent.id === parentId);
|
|
298
|
-
if (found === undefined) {
|
|
299
|
-
node.parents.push(parent);
|
|
300
|
-
|
|
301
|
-
// confirm that the child hasnt been added to the parents children list
|
|
302
|
-
found = parent.children.find(child => child.id === nodeId);
|
|
303
|
-
|
|
304
|
-
if (found === undefined) {
|
|
305
|
-
parent.children.push(node);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
};
|
|
309
|
-
|
|
310
|
-
Tree.prototype.removeParentFromNode = function(nodeId, parentId) {
|
|
311
|
-
|
|
312
|
-
// retrieve nodes from list
|
|
313
|
-
var node = this.getNodeById(nodeId);
|
|
314
|
-
var parent = (parentId === -1) ? this.root : this.getNodeById(parentId);
|
|
315
|
-
if (node === undefined) {
|
|
316
|
-
throw new Error('Node not found');
|
|
317
|
-
}
|
|
318
|
-
if (parent === undefined) {
|
|
319
|
-
throw new Error('Parent node not found');
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// remove the parent node from node parents
|
|
323
|
-
node.parents = node.parents.filter(parent => parent.id !== parentId);
|
|
324
|
-
|
|
325
|
-
// remove the ndoe form the parent children list
|
|
326
|
-
parent.children = parent.children.filter(child => child.id !== nodeId);
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
Tree.prototype.getNodeById = function(id) {
|
|
330
|
-
return this.nDatabaseNodes.find(node => node.id === id);
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
Tree.prototype.getNodeByName = function(name) {
|
|
334
|
-
return this.nDatabaseNodes.find(node => node.dsc === name);
|
|
335
|
-
};
|