| import "../arrays/merge"; | |
| import "../core/rebind"; | |
| import "layout"; | |
| d3.layout.hierarchy = function() { | |
| var sort = d3_layout_hierarchySort, | |
| children = d3_layout_hierarchyChildren, | |
| value = d3_layout_hierarchyValue; | |
| // Recursively compute the node depth and value. | |
| // Also converts to a standard hierarchy structure. | |
| function recurse(node, depth, nodes) { | |
| var childs = children.call(hierarchy, node, depth); | |
| node.depth = depth; | |
| nodes.push(node); | |
| if (childs && (n = childs.length)) { | |
| var i = -1, | |
| n, | |
| c = node.children = new Array(n), | |
| v = 0, | |
| j = depth + 1, | |
| d; | |
| while (++i < n) { | |
| d = c[i] = recurse(childs[i], j, nodes); | |
| d.parent = node; | |
| v += d.value; | |
| } | |
| if (sort) c.sort(sort); | |
| if (value) node.value = v; | |
| } else { | |
| delete node.children; | |
| if (value) { | |
| node.value = +value.call(hierarchy, node, depth) || 0; | |
| } | |
| } | |
| return node; | |
| } | |
| // Recursively re-evaluates the node value. | |
| function revalue(node, depth) { | |
| var children = node.children, | |
| v = 0; | |
| if (children && (n = children.length)) { | |
| var i = -1, | |
| n, | |
| j = depth + 1; | |
| while (++i < n) v += revalue(children[i], j); | |
| } else if (value) { | |
| v = +value.call(hierarchy, node, depth) || 0; | |
| } | |
| if (value) node.value = v; | |
| return v; | |
| } | |
| function hierarchy(d) { | |
| var nodes = []; | |
| recurse(d, 0, nodes); | |
| return nodes; | |
| } | |
| hierarchy.sort = function(x) { | |
| if (!arguments.length) return sort; | |
| sort = x; | |
| return hierarchy; | |
| }; | |
| hierarchy.children = function(x) { | |
| if (!arguments.length) return children; | |
| children = x; | |
| return hierarchy; | |
| }; | |
| hierarchy.value = function(x) { | |
| if (!arguments.length) return value; | |
| value = x; | |
| return hierarchy; | |
| }; | |
| // Re-evaluates the `value` property for the specified hierarchy. | |
| hierarchy.revalue = function(root) { | |
| revalue(root, 0); | |
| return root; | |
| }; | |
| return hierarchy; | |
| }; | |
| // A method assignment helper for hierarchy subclasses. | |
| function d3_layout_hierarchyRebind(object, hierarchy) { | |
| d3.rebind(object, hierarchy, "sort", "children", "value"); | |
| // Add an alias for nodes and links, for convenience. | |
| object.nodes = object; | |
| object.links = d3_layout_hierarchyLinks; | |
| return object; | |
| } | |
| function d3_layout_hierarchyChildren(d) { | |
| return d.children; | |
| } | |
| function d3_layout_hierarchyValue(d) { | |
| return d.value; | |
| } | |
| function d3_layout_hierarchySort(a, b) { | |
| return b.value - a.value; | |
| } | |
| // Returns an array source+target objects for the specified nodes. | |
| function d3_layout_hierarchyLinks(nodes) { | |
| return d3.merge(nodes.map(function(parent) { | |
| return (parent.children || []).map(function(child) { | |
| return {source: parent, target: child}; | |
| }); | |
| })); | |
| } |