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);
+}