diff --git a/README.md b/README.md index c2a2e800..bf1520f5 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,16 @@ root You must call *node*.sort before invoking a hierarchical layout if you want the new sort order to affect the layout; see [*node*.sum](#node_sum) for an example. +# node[Symbol.iterator]() [<>](https://github.com/d3/d3-hierarchy/blob/master/src/hierarchy/iterator.js "Source") + +Returns an iterator over the *node*’s descendants in breadth-first order. For example: + +```js +for (const descendant of node) { + console.log(descendant); +} +``` + # node.each(function[, that]) · [Source](https://github.com/d3/d3-hierarchy/blob/master/src/hierarchy/each.js), [Examples](https://observablehq.com/@d3/visiting-a-d3-hierarchy) Invokes the specified *function* for *node* and each descendant in [breadth-first order](https://en.wikipedia.org/wiki/Breadth-first_search), such that a given *node* is only visited if all nodes of lesser depth have already been visited, as well as all preceding nodes of the same depth. The specified function is passed the current *descendant*, the zero-based traversal *index*, and this *node*. If *that* is specified, it is the this context of the callback. diff --git a/src/hierarchy/descendants.js b/src/hierarchy/descendants.js index 1e3b5e6b..7f38090d 100644 --- a/src/hierarchy/descendants.js +++ b/src/hierarchy/descendants.js @@ -1,7 +1,3 @@ export default function() { - var nodes = []; - this.each(function(node) { - nodes.push(node); - }); - return nodes; + return Array.from(this); } diff --git a/src/hierarchy/each.js b/src/hierarchy/each.js index f1a9bad8..af911cc7 100644 --- a/src/hierarchy/each.js +++ b/src/hierarchy/each.js @@ -1,15 +1,7 @@ export default function(callback, that) { - var node = this, current, next = [node], children, i, n, index = -1; - do { - current = next.reverse(), next = []; - while (node = current.pop()) { - callback.call(that, node, ++index, this); - if (children = node.children) { - for (i = 0, n = children.length; i < n; ++i) { - next.push(children[i]); - } - } - } - } while (next.length); + let index = -1; + for (const node of this) { + callback.call(that, node, ++index, this); + } return this; } diff --git a/src/hierarchy/find.js b/src/hierarchy/find.js new file mode 100644 index 00000000..b7fa76f0 --- /dev/null +++ b/src/hierarchy/find.js @@ -0,0 +1,9 @@ +export default function(callback, that) { + if (typeof callback !== "function") throw new Error("not a function"); + let index = -1; + for (const node of this) { + if (callback.call(that, node, ++index, this)) { + return node; + } + } +} diff --git a/src/hierarchy/index.js b/src/hierarchy/index.js index 82985378..2e262592 100644 --- a/src/hierarchy/index.js +++ b/src/hierarchy/index.js @@ -2,6 +2,7 @@ import node_count from "./count.js"; import node_each from "./each.js"; import node_eachBefore from "./eachBefore.js"; import node_eachAfter from "./eachAfter.js"; +import node_find from "./find.js"; import node_sum from "./sum.js"; import node_sort from "./sort.js"; import node_path from "./path.js"; @@ -9,6 +10,7 @@ import node_ancestors from "./ancestors.js"; import node_descendants from "./descendants.js"; import node_leaves from "./leaves.js"; import node_links from "./links.js"; +import node_iterator from "./iterator.js"; export default function hierarchy(data, children) { var root = new Node(data), @@ -68,6 +70,7 @@ Node.prototype = hierarchy.prototype = { each: node_each, eachAfter: node_eachAfter, eachBefore: node_eachBefore, + find: node_find, sum: node_sum, sort: node_sort, path: node_path, @@ -75,5 +78,6 @@ Node.prototype = hierarchy.prototype = { descendants: node_descendants, leaves: node_leaves, links: node_links, - copy: node_copy + copy: node_copy, + [Symbol.iterator]: node_iterator }; diff --git a/src/hierarchy/iterator.js b/src/hierarchy/iterator.js new file mode 100644 index 00000000..7e06b620 --- /dev/null +++ b/src/hierarchy/iterator.js @@ -0,0 +1,14 @@ +export default function*() { + var node = this, current, next = [node], children, i, n; + do { + current = next.reverse(), next = []; + while (node = current.pop()) { + yield node; + if (children = node.children) { + for (i = 0, n = children.length; i < n; ++i) { + next.push(children[i]); + } + } + } + } while (next.length); +}