Tree.js
3.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/**
* (c) 2016 Highsoft AS
* Authors: Jon Arild Nygard
*
* License: www.highcharts.com/license
*/
/* eslint no-console: 0 */
'use strict';
import H from '../parts/Globals.js';
import '../parts/Utilities.js';
var each = H.each,
extend = H.extend,
isNumber = H.isNumber,
keys = H.keys,
map = H.map,
pick = H.pick,
reduce = H.reduce,
isFunction = function (x) {
return typeof x === 'function';
};
/**
* Creates an object map from parent id to childrens index.
* @param {Array} data List of points set in options.
* @param {string} data[].parent Parent id of point.
* @param {Array} ids List of all point ids.
* @returns {Object} Map from parent id to children index in data
*/
var getListOfParents = function (data, ids) {
var listOfParents = reduce(data, function (prev, curr) {
var parent = pick(curr.parent, '');
if (prev[parent] === undefined) {
prev[parent] = [];
}
prev[parent].push(curr);
return prev;
}, {}),
parents = keys(listOfParents);
// If parent does not exist, hoist parent to root of tree.
each(parents, function (parent, list) {
var children = listOfParents[parent];
if ((parent !== '') && (H.inArray(parent, ids) === -1)) {
each(children, function (child) {
list[''].push(child);
});
delete list[parent];
}
});
return listOfParents;
};
var getNode = function (id, parent, level, data, mapOfIdToChildren, options) {
var descendants = 0,
height = 0,
after = options && options.after,
before = options && options.before,
node = {
data: data,
depth: level - 1,
id: id,
level: level,
parent: parent
},
start,
end,
children;
// Allow custom logic before the children has been created.
if (isFunction(before)) {
before(node, options);
}
/**
* Call getNode recursively on the children. Calulate the height of the
* node, and the number of descendants.
*/
children = map((mapOfIdToChildren[id] || []), function (child) {
var node = getNode(
child.id,
id,
(level + 1),
child,
mapOfIdToChildren,
options
),
childStart = child.start,
childEnd = (
child.milestone === true ?
childStart :
child.end
);
// Start should be the lowest child.start.
start = (
(!isNumber(start) || childStart < start) ?
childStart :
start
);
// End should be the largest child.end.
// If child is milestone, then use start as end.
end = (
(!isNumber(end) || childEnd > end) ?
childEnd :
end
);
descendants = descendants + 1 + node.descendants;
height = Math.max(node.height + 1, height);
return node;
});
// Calculate start and end for point if it is not already explicitly set.
if (data) {
data.start = pick(data.start, start);
data.end = pick(data.end, end);
}
extend(node, {
children: children,
descendants: descendants,
height: height
});
// Allow custom logic after the children has been created.
if (isFunction(after)) {
after(node, options);
}
return node;
};
var getTree = function (data, options) {
var ids = map(data, function (d) {
return d.id;
}),
mapOfIdToChildren = getListOfParents(data, ids);
return getNode('', null, 1, null, mapOfIdToChildren, options);
};
var Tree = {
getListOfParents: getListOfParents,
getNode: getNode,
getTree: getTree
};
export default Tree;