@antv/hierarchy 0.6.13 → 0.7.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 +51 -3
- package/dist/hierarchy.es.js +2 -0
- package/dist/hierarchy.es.js.map +1 -0
- package/dist/hierarchy.umd.js +2 -0
- package/dist/hierarchy.umd.js.map +1 -0
- package/lib/compact-box.d.ts +3 -0
- package/lib/compact-box.d.ts.map +1 -0
- package/lib/dendrogram.d.ts +3 -0
- package/lib/dendrogram.d.ts.map +1 -0
- package/lib/indented.d.ts +3 -0
- package/lib/indented.d.ts.map +1 -0
- package/lib/index.d.ts +15 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/layout/base.d.ts +8 -0
- package/lib/layout/base.d.ts.map +1 -0
- package/lib/layout/dendrogram.d.ts +3 -0
- package/lib/layout/dendrogram.d.ts.map +1 -0
- package/lib/layout/do-layout.d.ts +5 -0
- package/lib/layout/do-layout.d.ts.map +1 -0
- package/lib/layout/hierarchy.d.ts +3 -0
- package/lib/layout/hierarchy.d.ts.map +1 -0
- package/lib/layout/indented.d.ts +3 -0
- package/lib/layout/indented.d.ts.map +1 -0
- package/lib/layout/mindmap.d.ts +3 -0
- package/lib/layout/mindmap.d.ts.map +1 -0
- package/lib/layout/non-layered-tidy.d.ts +3 -0
- package/lib/layout/non-layered-tidy.d.ts.map +1 -0
- package/lib/layout/separate-root.d.ts +6 -0
- package/lib/layout/separate-root.d.ts.map +1 -0
- package/lib/mindmap.d.ts +3 -0
- package/lib/mindmap.d.ts.map +1 -0
- package/lib/types.d.ts +90 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/util.d.ts +17 -0
- package/lib/util.d.ts.map +1 -0
- package/package.json +48 -53
- package/.babelrc +0 -14
- package/.editorconfig +0 -20
- package/.eslintignore +0 -7
- package/.eslintrc +0 -28
- package/.github/workflows/build.yml +0 -32
- package/CHANGELOG.md +0 -0
- package/CONTRIBUTING.md +0 -142
- package/CONTRIBUTING.zh-CN.md +0 -148
- package/assets/compact-box-bt.png +0 -0
- package/assets/compact-box-h.png +0 -0
- package/assets/compact-box-lr.png +0 -0
- package/assets/compact-box-rl.png +0 -0
- package/assets/compact-box-tb.png +0 -0
- package/assets/compact-box-v.png +0 -0
- package/assets/dendrogram-bt.png +0 -0
- package/assets/dendrogram-h.png +0 -0
- package/assets/dendrogram-lr.png +0 -0
- package/assets/dendrogram-rl.png +0 -0
- package/assets/dendrogram-tb.png +0 -0
- package/assets/dendrogram-v.png +0 -0
- package/assets/indented-h.png +0 -0
- package/assets/indented-lr.png +0 -0
- package/assets/indented-rl.png +0 -0
- package/assets/layered-tidy-bt.png +0 -0
- package/assets/layered-tidy-h.png +0 -0
- package/assets/layered-tidy-lr.png +0 -0
- package/assets/layered-tidy-rl.png +0 -0
- package/assets/layered-tidy-tb.png +0 -0
- package/assets/layered-tidy-v.png +0 -0
- package/assets/mindmap.png +0 -0
- package/bin/mkdir-dist.js +0 -8
- package/bin/screenshot.js +0 -81
- package/bin/win-dev.js +0 -14
- package/build/hierarchy.js +0 -1131
- package/build/hierarchy.js.map +0 -1
- package/dist/hierarchy.min.js +0 -1
- package/lib/compact-box.js +0 -24
- package/lib/dendrogram.js +0 -25
- package/lib/indented.js +0 -65
- package/lib/index.js +0 -7
- package/lib/layout/base.js +0 -17
- package/lib/layout/dendrogram.js +0 -108
- package/lib/layout/do-layout.js +0 -107
- package/lib/layout/hierarchy.js +0 -184
- package/lib/layout/indented.js +0 -36
- package/lib/layout/mindmap.js +0 -92
- package/lib/layout/non-layered-tidy.js +0 -236
- package/lib/layout/separate-root.js +0 -39
- package/lib/mindmap.js +0 -24
- package/lib/util.js +0 -18
- package/src/compact-box.js +0 -21
- package/src/dendrogram.js +0 -22
- package/src/indented.js +0 -52
- package/src/index.js +0 -9
- package/src/layout/base.js +0 -16
- package/src/layout/dendrogram.js +0 -105
- package/src/layout/do-layout.js +0 -106
- package/src/layout/hierarchy.js +0 -187
- package/src/layout/indented.js +0 -40
- package/src/layout/mindmap.js +0 -93
- package/src/layout/non-layered-tidy.js +0 -250
- package/src/layout/separate-root.js +0 -40
- package/src/mindmap.js +0 -21
- package/src/util.js +0 -16
package/src/indented.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
const TreeLayout = require('./layout/base');
|
|
2
|
-
const indentedTree = require('./layout/indented');
|
|
3
|
-
const separateTree = require('./layout/separate-root');
|
|
4
|
-
const util = require('./util');
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const VALID_DIRECTIONS = [
|
|
8
|
-
'LR', // left to right
|
|
9
|
-
'RL', // right to left
|
|
10
|
-
'H' // horizontal
|
|
11
|
-
];
|
|
12
|
-
const DEFAULT_DIRECTION = VALID_DIRECTIONS[0];
|
|
13
|
-
|
|
14
|
-
class IndentedLayout extends TreeLayout {
|
|
15
|
-
execute() {
|
|
16
|
-
const me = this;
|
|
17
|
-
const options = me.options;
|
|
18
|
-
const root = me.rootNode;
|
|
19
|
-
options.isHorizontal = true;
|
|
20
|
-
// default indent 20 and sink first children;
|
|
21
|
-
const { indent = 20, dropCap = true, direction = DEFAULT_DIRECTION, align } = options;
|
|
22
|
-
if (direction && VALID_DIRECTIONS.indexOf(direction) === -1) {
|
|
23
|
-
throw new TypeError(`Invalid direction: ${direction}`);
|
|
24
|
-
}
|
|
25
|
-
if (direction === VALID_DIRECTIONS[0]) { // LR
|
|
26
|
-
indentedTree(root, indent, dropCap, align);
|
|
27
|
-
} else if (direction === VALID_DIRECTIONS[1]) { // RL
|
|
28
|
-
indentedTree(root, indent, dropCap, align);
|
|
29
|
-
root.right2left();
|
|
30
|
-
} else if (direction === VALID_DIRECTIONS[2]) { // H
|
|
31
|
-
// separate into left and right trees
|
|
32
|
-
const { left, right } = separateTree(root, options);
|
|
33
|
-
indentedTree(left, indent, dropCap, align);
|
|
34
|
-
left.right2left();
|
|
35
|
-
indentedTree(right, indent, dropCap, align);
|
|
36
|
-
const bbox = left.getBoundingBox();
|
|
37
|
-
right.translate(bbox.width, 0);
|
|
38
|
-
root.x = right.x - root.width / 2;
|
|
39
|
-
}
|
|
40
|
-
return root;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const DEFAULT_OPTIONS = {
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
function indentedLayout(root, options) {
|
|
48
|
-
options = util.assign({}, DEFAULT_OPTIONS, options);
|
|
49
|
-
return new IndentedLayout(root, options).execute();
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
module.exports = indentedLayout;
|
package/src/index.js
DELETED
package/src/layout/base.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
const hierarchy = require('./hierarchy');
|
|
3
|
-
|
|
4
|
-
class Layout {
|
|
5
|
-
constructor(root, options = {}) {
|
|
6
|
-
const me = this;
|
|
7
|
-
me.options = options;
|
|
8
|
-
me.rootNode = hierarchy(root, options);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
execute() {
|
|
12
|
-
throw new Error('please override this method');
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
module.exports = Layout;
|
package/src/layout/dendrogram.js
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
// wrap tree node
|
|
2
|
-
// TODO considering size
|
|
3
|
-
const util = require('../util');
|
|
4
|
-
|
|
5
|
-
function WrappedTree(height = 0, children = []) {
|
|
6
|
-
const me = this;
|
|
7
|
-
me.x = me.y = 0;
|
|
8
|
-
me.leftChild = me.rightChild = null;
|
|
9
|
-
me.height = 0;
|
|
10
|
-
me.children = children;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const DEFAULT_OPTIONS = {
|
|
14
|
-
isHorizontal: true,
|
|
15
|
-
nodeSep: 20,
|
|
16
|
-
nodeSize: 20,
|
|
17
|
-
rankSep: 200,
|
|
18
|
-
subTreeSep: 10
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
function convertBack(converted/* WrappedTree */, root/* TreeNode */, isHorizontal) {
|
|
22
|
-
if (isHorizontal) {
|
|
23
|
-
root.x = converted.x;
|
|
24
|
-
root.y = converted.y;
|
|
25
|
-
} else {
|
|
26
|
-
root.x = converted.y;
|
|
27
|
-
root.y = converted.x;
|
|
28
|
-
}
|
|
29
|
-
converted.children.forEach((child, i) => {
|
|
30
|
-
convertBack(child, root.children[i], isHorizontal);
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
module.exports = (root, options = {}) => {
|
|
35
|
-
options = util.assign({}, DEFAULT_OPTIONS, options);
|
|
36
|
-
|
|
37
|
-
let maxDepth = 0;
|
|
38
|
-
function wrappedTreeFromNode(n) {
|
|
39
|
-
if (!n) return null;
|
|
40
|
-
n.width = 0;
|
|
41
|
-
if (n.depth && n.depth > maxDepth) {
|
|
42
|
-
maxDepth = n.depth; // get the max depth
|
|
43
|
-
}
|
|
44
|
-
const children = n.children;
|
|
45
|
-
const childrenCount = children.length;
|
|
46
|
-
const t = new WrappedTree(n.height, []);
|
|
47
|
-
children.forEach((child, i) => {
|
|
48
|
-
const childWT = wrappedTreeFromNode(child);
|
|
49
|
-
t.children.push(childWT);
|
|
50
|
-
if (i === 0) {
|
|
51
|
-
// t.leftChild = childWT.leftChild ? childWT.leftChild : childWT
|
|
52
|
-
t.leftChild = childWT;
|
|
53
|
-
}
|
|
54
|
-
if (i === (childrenCount - 1)) {
|
|
55
|
-
// t.rightChild = childWT.rightChild ? childWT.rightChild : childWT
|
|
56
|
-
t.rightChild = childWT;
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
t.originNode = n;
|
|
60
|
-
t.isLeaf = n.isLeaf();
|
|
61
|
-
return t;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function getDrawingDepth(t) {
|
|
65
|
-
if (t.isLeaf || t.children.length === 0) {
|
|
66
|
-
t.drawingDepth = maxDepth;
|
|
67
|
-
} else {
|
|
68
|
-
const depths = t.children.map(child => getDrawingDepth(child));
|
|
69
|
-
const minChildDepth = Math.min.apply(null, depths);
|
|
70
|
-
t.drawingDepth = minChildDepth - 1;
|
|
71
|
-
}
|
|
72
|
-
return t.drawingDepth;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
let prevLeaf;
|
|
76
|
-
|
|
77
|
-
function position(t) {
|
|
78
|
-
t.x = t.drawingDepth * options.rankSep;
|
|
79
|
-
if (t.isLeaf) {
|
|
80
|
-
t.y = 0;
|
|
81
|
-
if (prevLeaf) {
|
|
82
|
-
t.y = prevLeaf.y + prevLeaf.height + options.nodeSep;
|
|
83
|
-
if (t.originNode.parent !== prevLeaf.originNode.parent) {
|
|
84
|
-
t.y += options.subTreeSep;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
prevLeaf = t;
|
|
88
|
-
} else {
|
|
89
|
-
t.children.forEach(child => {
|
|
90
|
-
position(child);
|
|
91
|
-
});
|
|
92
|
-
t.y = (t.leftChild.y + t.rightChild.y) / 2;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// wrap node
|
|
97
|
-
const wt = wrappedTreeFromNode(root);
|
|
98
|
-
// get depth for drawing
|
|
99
|
-
getDrawingDepth(wt);
|
|
100
|
-
// get position
|
|
101
|
-
position(wt);
|
|
102
|
-
// get x, y
|
|
103
|
-
convertBack(wt, root, options.isHorizontal);
|
|
104
|
-
return root;
|
|
105
|
-
};
|
package/src/layout/do-layout.js
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
const separateTree = require('./separate-root');
|
|
2
|
-
const VALID_DIRECTIONS = [
|
|
3
|
-
'LR', // left to right
|
|
4
|
-
'RL', // right to left
|
|
5
|
-
'TB', // top to bottom
|
|
6
|
-
'BT', // bottom to top
|
|
7
|
-
'H', // horizontal
|
|
8
|
-
'V' // vertical
|
|
9
|
-
];
|
|
10
|
-
const HORIZONTAL_DIRECTIONS = [
|
|
11
|
-
'LR',
|
|
12
|
-
'RL',
|
|
13
|
-
'H'
|
|
14
|
-
];
|
|
15
|
-
const isHorizontal = direction => HORIZONTAL_DIRECTIONS.indexOf(direction) > -1;
|
|
16
|
-
const DEFAULT_DIRECTION = VALID_DIRECTIONS[0];
|
|
17
|
-
|
|
18
|
-
module.exports = (root, options, layoutAlgrithm) => {
|
|
19
|
-
const direction = options.direction || DEFAULT_DIRECTION;
|
|
20
|
-
options.isHorizontal = isHorizontal(direction);
|
|
21
|
-
if (direction && VALID_DIRECTIONS.indexOf(direction) === -1) {
|
|
22
|
-
throw new TypeError(`Invalid direction: ${direction}`);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (direction === VALID_DIRECTIONS[0]) {
|
|
26
|
-
// LR
|
|
27
|
-
layoutAlgrithm(root, options);
|
|
28
|
-
} else if (direction === VALID_DIRECTIONS[1]) {
|
|
29
|
-
// RL
|
|
30
|
-
layoutAlgrithm(root, options);
|
|
31
|
-
root.right2left();
|
|
32
|
-
} else if (direction === VALID_DIRECTIONS[2]) {
|
|
33
|
-
// TB
|
|
34
|
-
layoutAlgrithm(root, options);
|
|
35
|
-
} else if (direction === VALID_DIRECTIONS[3]) {
|
|
36
|
-
// BT
|
|
37
|
-
layoutAlgrithm(root, options);
|
|
38
|
-
root.bottom2top();
|
|
39
|
-
} else if (direction === VALID_DIRECTIONS[4] || direction === VALID_DIRECTIONS[5]) {
|
|
40
|
-
// H or V
|
|
41
|
-
// separate into left and right trees
|
|
42
|
-
const { left, right } = separateTree(root, options);
|
|
43
|
-
// do layout for left and right trees
|
|
44
|
-
layoutAlgrithm(left, options);
|
|
45
|
-
layoutAlgrithm(right, options);
|
|
46
|
-
options.isHorizontal ? (left.right2left()) : (left.bottom2top());
|
|
47
|
-
// combine left and right trees
|
|
48
|
-
right.translate(left.x - right.x, left.y - right.y);
|
|
49
|
-
// translate root
|
|
50
|
-
root.x = left.x;
|
|
51
|
-
root.y = right.y;
|
|
52
|
-
const bb = root.getBoundingBox();
|
|
53
|
-
if (options.isHorizontal) {
|
|
54
|
-
if (bb.top < 0) {
|
|
55
|
-
root.translate(0, -bb.top);
|
|
56
|
-
}
|
|
57
|
-
} else {
|
|
58
|
-
if (bb.left < 0) {
|
|
59
|
-
root.translate(-bb.left, 0);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
// fixed root position, default value is true
|
|
64
|
-
let fixedRoot = options.fixedRoot;
|
|
65
|
-
if (fixedRoot === undefined) fixedRoot = true;
|
|
66
|
-
if (fixedRoot) {
|
|
67
|
-
root.translate(-(root.x + root.width / 2 + root.hgap), -(root.y + root.height / 2 + root.vgap));
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
reassignXYIfRadial(root, options);
|
|
71
|
-
|
|
72
|
-
return root;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
function reassignXYIfRadial(root, options) {
|
|
77
|
-
if (options.radial) {
|
|
78
|
-
const [ rScale, radScale ] = options.isHorizontal ? [ "x", "y" ] : [ "y", "x" ];
|
|
79
|
-
|
|
80
|
-
const min = { x: Infinity, y: Infinity };
|
|
81
|
-
const max = { x: -Infinity, y: -Infinity };
|
|
82
|
-
|
|
83
|
-
let count = 0;
|
|
84
|
-
root.DFTraverse((node) => {
|
|
85
|
-
count++;
|
|
86
|
-
const { x, y } = node;
|
|
87
|
-
min.x = Math.min(min.x, x);
|
|
88
|
-
min.y = Math.min(min.y, y);
|
|
89
|
-
max.x = Math.max(max.x, x);
|
|
90
|
-
max.y = Math.max(max.y, y);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
const radDiff = max[radScale] - min[radScale];
|
|
94
|
-
if (radDiff === 0) return;
|
|
95
|
-
|
|
96
|
-
const avgRad = (Math.PI * 2) / count;
|
|
97
|
-
root.DFTraverse((node) => {
|
|
98
|
-
const rad =
|
|
99
|
-
((node[radScale] - min[radScale]) / radDiff) * (Math.PI * 2 - avgRad) +
|
|
100
|
-
avgRad;
|
|
101
|
-
const r = node[rScale] - root[rScale];
|
|
102
|
-
node.x = Math.cos(rad) * r;
|
|
103
|
-
node.y = Math.sin(rad) * r;
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
}
|
package/src/layout/hierarchy.js
DELETED
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-cond-assign */
|
|
2
|
-
const util = require('../util');
|
|
3
|
-
|
|
4
|
-
const PEM = 18;
|
|
5
|
-
const DEFAULT_HEIGHT = PEM * 2;
|
|
6
|
-
const DEFAULT_GAP = PEM;
|
|
7
|
-
|
|
8
|
-
const DEFAULT_OPTIONS = {
|
|
9
|
-
getId(d) {
|
|
10
|
-
return d.id || d.name;
|
|
11
|
-
},
|
|
12
|
-
getPreH(d) {
|
|
13
|
-
return d.preH || 0;
|
|
14
|
-
},
|
|
15
|
-
getPreV(d) {
|
|
16
|
-
return d.preV || 0;
|
|
17
|
-
},
|
|
18
|
-
getHGap(d) {
|
|
19
|
-
return d.hgap || DEFAULT_GAP;
|
|
20
|
-
},
|
|
21
|
-
getVGap(d) {
|
|
22
|
-
return d.vgap || DEFAULT_GAP;
|
|
23
|
-
},
|
|
24
|
-
getChildren(d) {
|
|
25
|
-
return d.children;
|
|
26
|
-
},
|
|
27
|
-
getHeight(d) {
|
|
28
|
-
return d.height || DEFAULT_HEIGHT;
|
|
29
|
-
},
|
|
30
|
-
getWidth(d) {
|
|
31
|
-
const label = d.label || ' ';
|
|
32
|
-
return d.width || (label.split('').length * PEM); // FIXME DO NOT get width like this
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
function Node(data, options) {
|
|
37
|
-
const me = this;
|
|
38
|
-
me.vgap = me.hgap = 0;
|
|
39
|
-
if (data instanceof Node) return data;
|
|
40
|
-
me.data = data;
|
|
41
|
-
/*
|
|
42
|
-
* Gaps: filling space between nodes
|
|
43
|
-
* (x, y) ----------------------
|
|
44
|
-
* | vgap |
|
|
45
|
-
* | -------------------- h
|
|
46
|
-
* | h | | e
|
|
47
|
-
* | g | | i
|
|
48
|
-
* | a | | g
|
|
49
|
-
* | p | | h
|
|
50
|
-
* | --------------------- t
|
|
51
|
-
* | |
|
|
52
|
-
* -----------width------------
|
|
53
|
-
*/
|
|
54
|
-
const hgap = options.getHGap(data);
|
|
55
|
-
const vgap = options.getVGap(data);
|
|
56
|
-
me.preH = options.getPreH(data);
|
|
57
|
-
me.preV = options.getPreV(data);
|
|
58
|
-
me.width = options.getWidth(data);
|
|
59
|
-
me.height = options.getHeight(data);
|
|
60
|
-
me.width += me.preH;
|
|
61
|
-
me.height += me.preV;
|
|
62
|
-
me.id = options.getId(data);
|
|
63
|
-
me.x = me.y = 0;
|
|
64
|
-
me.depth = 0;
|
|
65
|
-
if (!me.children) {
|
|
66
|
-
me.children = [];
|
|
67
|
-
}
|
|
68
|
-
me.addGap(hgap, vgap);
|
|
69
|
-
return me;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
util.assign(Node.prototype, {
|
|
73
|
-
isRoot() {
|
|
74
|
-
return (this.depth === 0);
|
|
75
|
-
},
|
|
76
|
-
|
|
77
|
-
isLeaf() {
|
|
78
|
-
return (this.children.length === 0);
|
|
79
|
-
},
|
|
80
|
-
|
|
81
|
-
addGap(hgap, vgap) {
|
|
82
|
-
const me = this;
|
|
83
|
-
me.hgap += hgap;
|
|
84
|
-
me.vgap += vgap;
|
|
85
|
-
me.width += 2 * hgap;
|
|
86
|
-
me.height += 2 * vgap;
|
|
87
|
-
},
|
|
88
|
-
|
|
89
|
-
eachNode(callback) { // Depth First traverse
|
|
90
|
-
const me = this;
|
|
91
|
-
let nodes = [ me ];
|
|
92
|
-
let current;
|
|
93
|
-
while (current = nodes.shift()) {
|
|
94
|
-
callback(current);
|
|
95
|
-
nodes = current.children.concat(nodes);
|
|
96
|
-
}
|
|
97
|
-
},
|
|
98
|
-
|
|
99
|
-
DFTraverse(callback) { // Depth First traverse
|
|
100
|
-
this.eachNode(callback);
|
|
101
|
-
},
|
|
102
|
-
|
|
103
|
-
BFTraverse(callback) { // Breadth First traverse
|
|
104
|
-
const me = this;
|
|
105
|
-
let nodes = [ me ];
|
|
106
|
-
let current;
|
|
107
|
-
while (current = nodes.shift()) {
|
|
108
|
-
callback(current);
|
|
109
|
-
nodes = nodes.concat(current.children);
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
|
|
113
|
-
getBoundingBox() {
|
|
114
|
-
// BBox for just one tree node
|
|
115
|
-
const bb = {
|
|
116
|
-
left: Number.MAX_VALUE,
|
|
117
|
-
top: Number.MAX_VALUE,
|
|
118
|
-
width: 0,
|
|
119
|
-
height: 0
|
|
120
|
-
};
|
|
121
|
-
this.eachNode(node => {
|
|
122
|
-
bb.left = Math.min(bb.left, node.x);
|
|
123
|
-
bb.top = Math.min(bb.top, node.y);
|
|
124
|
-
bb.width = Math.max(bb.width, node.x + node.width);
|
|
125
|
-
bb.height = Math.max(bb.height, node.y + node.height);
|
|
126
|
-
});
|
|
127
|
-
return bb;
|
|
128
|
-
},
|
|
129
|
-
|
|
130
|
-
// translate
|
|
131
|
-
translate(tx = 0, ty = 0) {
|
|
132
|
-
this.eachNode(node => {
|
|
133
|
-
node.x += tx;
|
|
134
|
-
node.y += ty;
|
|
135
|
-
node.x += node.preH;
|
|
136
|
-
node.y += node.preV;
|
|
137
|
-
});
|
|
138
|
-
},
|
|
139
|
-
|
|
140
|
-
right2left() {
|
|
141
|
-
const me = this;
|
|
142
|
-
const bb = me.getBoundingBox();
|
|
143
|
-
me.eachNode(node => {
|
|
144
|
-
node.x = node.x - (node.x - bb.left) * 2 - node.width;
|
|
145
|
-
// node.x = - node.x;
|
|
146
|
-
});
|
|
147
|
-
me.translate(bb.width, 0);
|
|
148
|
-
},
|
|
149
|
-
|
|
150
|
-
bottom2top() {
|
|
151
|
-
const me = this;
|
|
152
|
-
const bb = me.getBoundingBox();
|
|
153
|
-
me.eachNode(node => {
|
|
154
|
-
node.y = node.y - (node.y - bb.top) * 2 - node.height;
|
|
155
|
-
// node.y = - node.y;
|
|
156
|
-
});
|
|
157
|
-
me.translate(0, bb.height);
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
function hierarchy(data, options = {}, isolated) {
|
|
162
|
-
options = util.assign({}, DEFAULT_OPTIONS, options);
|
|
163
|
-
const root = new Node(data, options);
|
|
164
|
-
const nodes = [ root ];
|
|
165
|
-
let node;
|
|
166
|
-
if (!isolated && !data.collapsed) {
|
|
167
|
-
while (node = nodes.shift()) {
|
|
168
|
-
if (!node.data.collapsed) {
|
|
169
|
-
const children = options.getChildren(node.data);
|
|
170
|
-
const length = children ? children.length : 0;
|
|
171
|
-
node.children = new Array(length);
|
|
172
|
-
if (children && length) {
|
|
173
|
-
for (let i = 0; i < length; i++) {
|
|
174
|
-
const child = new Node(children[i], options);
|
|
175
|
-
node.children[i] = child;
|
|
176
|
-
nodes.push(child);
|
|
177
|
-
child.parent = node;
|
|
178
|
-
child.depth = node.depth + 1;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
return root;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
module.exports = hierarchy;
|
package/src/layout/indented.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
const util = require("../util");
|
|
2
|
-
|
|
3
|
-
function positionNode(node, previousNode, indent, dropCap, align) {
|
|
4
|
-
// caculate the node's horizontal offset DX, dx's type might be number or function
|
|
5
|
-
const displacementX =
|
|
6
|
-
typeof indent === "function" ? indent(node) : indent * node.depth;
|
|
7
|
-
|
|
8
|
-
if (!dropCap) {
|
|
9
|
-
try {
|
|
10
|
-
if (node.id === node.parent.children[0].id) {
|
|
11
|
-
node.x += displacementX;
|
|
12
|
-
node.y = previousNode ? previousNode.y : 0;
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
} catch (e) {
|
|
16
|
-
// skip to normal when a node has no parent
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
node.x += displacementX;
|
|
21
|
-
if (previousNode) {
|
|
22
|
-
node.y = previousNode.y + util.getHeight(previousNode, node, align);
|
|
23
|
-
if (previousNode.parent && node.parent.id !== previousNode.parent.id) {
|
|
24
|
-
// previous node has different parent
|
|
25
|
-
const prevParent = previousNode.parent;
|
|
26
|
-
const preY = prevParent.y + util.getHeight(prevParent, node, align);
|
|
27
|
-
node.y = preY > node.y ? preY : node.y;
|
|
28
|
-
}
|
|
29
|
-
} else {
|
|
30
|
-
node.y = 0;
|
|
31
|
-
}
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
module.exports = (root, indent, dropCap, align) => {
|
|
35
|
-
let previousNode = null;
|
|
36
|
-
root.eachNode((node) => {
|
|
37
|
-
positionNode(node, previousNode, indent, dropCap, align);
|
|
38
|
-
previousNode = node;
|
|
39
|
-
});
|
|
40
|
-
};
|
package/src/layout/mindmap.js
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
const util = require('../util');
|
|
2
|
-
|
|
3
|
-
function secondWalk(node, options) {
|
|
4
|
-
let totalHeight = 0;
|
|
5
|
-
if (!node.children.length) {
|
|
6
|
-
totalHeight = node.height;
|
|
7
|
-
} else {
|
|
8
|
-
node.children.forEach(c => {
|
|
9
|
-
totalHeight += secondWalk(c, options);
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
node._subTreeSep = options.getSubTreeSep(node.data);
|
|
13
|
-
node.totalHeight = Math.max(node.height, totalHeight) + 2 * node._subTreeSep;
|
|
14
|
-
return node.totalHeight;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function thirdWalk(node) {
|
|
18
|
-
const children = node.children;
|
|
19
|
-
const len = children.length;
|
|
20
|
-
if (len) {
|
|
21
|
-
children.forEach(c => {
|
|
22
|
-
thirdWalk(c);
|
|
23
|
-
});
|
|
24
|
-
const first = children[0];
|
|
25
|
-
const last = children[len - 1];
|
|
26
|
-
const childrenHeight = last.y - first.y + last.height;
|
|
27
|
-
let childrenTotalHeight = 0;
|
|
28
|
-
children.forEach(child => {
|
|
29
|
-
childrenTotalHeight += child.totalHeight;
|
|
30
|
-
});
|
|
31
|
-
if (childrenHeight > node.height) {
|
|
32
|
-
// 当子节点总高度大于父节点高度
|
|
33
|
-
node.y = first.y + childrenHeight / 2 - node.height / 2;
|
|
34
|
-
} else if (children.length !== 1 || node.height > childrenTotalHeight) {
|
|
35
|
-
// 多于一个子节点或者父节点大于所有子节点的总高度
|
|
36
|
-
const offset = node.y + (node.height - childrenHeight) / 2 - first.y;
|
|
37
|
-
children.forEach(c => {
|
|
38
|
-
c.translate(0, offset);
|
|
39
|
-
});
|
|
40
|
-
} else {
|
|
41
|
-
// 只有一个子节点
|
|
42
|
-
node.y = (first.y + first.height / 2 + last.y + last.height / 2) / 2 - node.height / 2;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const DEFAULT_OPTIONS = {
|
|
48
|
-
getSubTreeSep() {
|
|
49
|
-
return 0;
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
module.exports = (root, options = {}) => {
|
|
54
|
-
options = util.assign({}, DEFAULT_OPTIONS, options);
|
|
55
|
-
root.parent = {
|
|
56
|
-
x: 0,
|
|
57
|
-
width: 0,
|
|
58
|
-
height: 0,
|
|
59
|
-
y: 0
|
|
60
|
-
};
|
|
61
|
-
// first walk
|
|
62
|
-
root.BFTraverse(node => {
|
|
63
|
-
node.x = node.parent.x + node.parent.width; // simply get x
|
|
64
|
-
});
|
|
65
|
-
root.parent = null;
|
|
66
|
-
// second walk
|
|
67
|
-
secondWalk(root, options); // assign sub tree totalHeight
|
|
68
|
-
// adjusting
|
|
69
|
-
// separating nodes
|
|
70
|
-
root.startY = 0;
|
|
71
|
-
root.y = root.totalHeight / 2 - root.height / 2;
|
|
72
|
-
root.eachNode(node => {
|
|
73
|
-
const children = node.children;
|
|
74
|
-
const len = children.length;
|
|
75
|
-
if (len) {
|
|
76
|
-
const first = children[0];
|
|
77
|
-
first.startY = node.startY + node._subTreeSep;
|
|
78
|
-
if (len === 1) {
|
|
79
|
-
first.y = node.y + node.height / 2 - first.height / 2;
|
|
80
|
-
} else {
|
|
81
|
-
first.y = first.startY + first.totalHeight / 2 - first.height / 2;
|
|
82
|
-
for (let i = 1; i < len; i++) {
|
|
83
|
-
const c = children[i];
|
|
84
|
-
c.startY = children[i - 1].startY + children[i - 1].totalHeight;
|
|
85
|
-
c.y = c.startY + c.totalHeight / 2 - c.height / 2;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
// third walk
|
|
92
|
-
thirdWalk(root);
|
|
93
|
-
};
|