|
1 d3.layout.hierarchy = function() { |
|
2 var sort = d3_layout_hierarchySort, |
|
3 children = d3_layout_hierarchyChildren, |
|
4 value = d3_layout_hierarchyValue; |
|
5 |
|
6 // Recursively compute the node depth and value. |
|
7 // Also converts the data representation into a standard hierarchy structure. |
|
8 function recurse(data, depth, nodes) { |
|
9 var childs = children.call(hierarchy, data, depth), |
|
10 node = d3_layout_hierarchyInline ? data : {data: data}; |
|
11 node.depth = depth; |
|
12 nodes.push(node); |
|
13 if (childs && (n = childs.length)) { |
|
14 var i = -1, |
|
15 n, |
|
16 c = node.children = [], |
|
17 v = 0, |
|
18 j = depth + 1; |
|
19 while (++i < n) { |
|
20 d = recurse(childs[i], j, nodes); |
|
21 d.parent = node; |
|
22 c.push(d); |
|
23 v += d.value; |
|
24 } |
|
25 if (sort) c.sort(sort); |
|
26 if (value) node.value = v; |
|
27 } else if (value) { |
|
28 node.value = +value.call(hierarchy, data, depth) || 0; |
|
29 } |
|
30 return node; |
|
31 } |
|
32 |
|
33 // Recursively re-evaluates the node value. |
|
34 function revalue(node, depth) { |
|
35 var children = node.children, |
|
36 v = 0; |
|
37 if (children && (n = children.length)) { |
|
38 var i = -1, |
|
39 n, |
|
40 j = depth + 1; |
|
41 while (++i < n) v += revalue(children[i], j); |
|
42 } else if (value) { |
|
43 v = +value.call(hierarchy, d3_layout_hierarchyInline ? node : node.data, depth) || 0; |
|
44 } |
|
45 if (value) node.value = v; |
|
46 return v; |
|
47 } |
|
48 |
|
49 function hierarchy(d) { |
|
50 var nodes = []; |
|
51 recurse(d, 0, nodes); |
|
52 return nodes; |
|
53 } |
|
54 |
|
55 hierarchy.sort = function(x) { |
|
56 if (!arguments.length) return sort; |
|
57 sort = x; |
|
58 return hierarchy; |
|
59 }; |
|
60 |
|
61 hierarchy.children = function(x) { |
|
62 if (!arguments.length) return children; |
|
63 children = x; |
|
64 return hierarchy; |
|
65 }; |
|
66 |
|
67 hierarchy.value = function(x) { |
|
68 if (!arguments.length) return value; |
|
69 value = x; |
|
70 return hierarchy; |
|
71 }; |
|
72 |
|
73 // Re-evaluates the `value` property for the specified hierarchy. |
|
74 hierarchy.revalue = function(root) { |
|
75 revalue(root, 0); |
|
76 return root; |
|
77 }; |
|
78 |
|
79 return hierarchy; |
|
80 }; |
|
81 |
|
82 // A method assignment helper for hierarchy subclasses. |
|
83 function d3_layout_hierarchyRebind(object, hierarchy) { |
|
84 object.sort = d3.rebind(object, hierarchy.sort); |
|
85 object.children = d3.rebind(object, hierarchy.children); |
|
86 object.links = d3_layout_hierarchyLinks; |
|
87 object.value = d3.rebind(object, hierarchy.value); |
|
88 |
|
89 // If the new API is used, enabling inlining. |
|
90 object.nodes = function(d) { |
|
91 d3_layout_hierarchyInline = true; |
|
92 return (object.nodes = object)(d); |
|
93 }; |
|
94 |
|
95 return object; |
|
96 } |
|
97 |
|
98 function d3_layout_hierarchyChildren(d) { |
|
99 return d.children; |
|
100 } |
|
101 |
|
102 function d3_layout_hierarchyValue(d) { |
|
103 return d.value; |
|
104 } |
|
105 |
|
106 function d3_layout_hierarchySort(a, b) { |
|
107 return b.value - a.value; |
|
108 } |
|
109 |
|
110 // Returns an array source+target objects for the specified nodes. |
|
111 function d3_layout_hierarchyLinks(nodes) { |
|
112 return d3.merge(nodes.map(function(parent) { |
|
113 return (parent.children || []).map(function(child) { |
|
114 return {source: parent, target: child}; |
|
115 }); |
|
116 })); |
|
117 } |
|
118 |
|
119 // For backwards-compatibility, don't enable inlining by default. |
|
120 var d3_layout_hierarchyInline = false; |