diff --git a/README.md b/README.md
index 05692ff..2eed0f9 100644
--- a/README.md
+++ b/README.md
@@ -126,6 +126,11 @@ Returns the total number of data in the quadtree.
Returns the datum closest to the position ⟨*x*,*y*⟩ with the given search *radius*. If *radius* is not specified, it defaults to infinity. If there is no datum within the search area, returns undefined.
+# quadtree.findInCircle(x, y[, radius][, filter])
+ [<>](https://github.com/d3/d3-quadtree/blob/master/src/findInCircle.js "Source")
+
+Returns all the data within the given search *radius* of the position ⟨*x*,*y*⟩ that satisfy the filter *filter*, if specified. If *radius* is not specified, it defaults to infinity. If there is no acceptable datum within the search area, returns an empty array.
+
# quadtree.visit(callback)
[<>](https://github.com/d3/d3-quadtree/blob/master/src/visit.js "Source")
diff --git a/src/findInCircle.js b/src/findInCircle.js
new file mode 100644
index 0000000..1ad3a10
--- /dev/null
+++ b/src/findInCircle.js
@@ -0,0 +1,22 @@
+export default function(x, y, radius, filter) {
+ const quadtree = this,
+ result = [],
+ radius2 = radius * radius,
+ accept = filter
+ ? d => filter(d) && result.push(d)
+ : d => result.push(d);
+
+ quadtree.visit(function(node, x1, y1, x2, y2) {
+ if (node.length) {
+ return x1 >= x + radius || y1 >= y + radius || x2 < x - radius || y2 < y - radius;
+ }
+
+ const dx = +quadtree._x.call(null, node.data) - x,
+ dy = +quadtree._y.call(null, node.data) - y;
+ if (dx * dx + dy * dy < radius2) {
+ do { accept(node.data); } while (node = node.next);
+ }
+ });
+
+ return result;
+}
diff --git a/src/quadtree.js b/src/quadtree.js
index 5d58593..2bad3d4 100644
--- a/src/quadtree.js
+++ b/src/quadtree.js
@@ -3,6 +3,7 @@ import tree_cover from "./cover.js";
import tree_data from "./data.js";
import tree_extent from "./extent.js";
import tree_find from "./find.js";
+import tree_findInCircle from "./findInCircle.js";
import tree_remove, {removeAll as tree_removeAll} from "./remove.js";
import tree_root from "./root.js";
import tree_size from "./size.js";
@@ -63,6 +64,7 @@ treeProto.cover = tree_cover;
treeProto.data = tree_data;
treeProto.extent = tree_extent;
treeProto.find = tree_find;
+treeProto.findInCircle = tree_findInCircle;
treeProto.remove = tree_remove;
treeProto.removeAll = tree_removeAll;
treeProto.root = tree_root;
diff --git a/test/findInCircle-test.js b/test/findInCircle-test.js
new file mode 100644
index 0000000..c0ea45a
--- /dev/null
+++ b/test/findInCircle-test.js
@@ -0,0 +1,21 @@
+var tape = require("tape"),
+ d3_quadtree = require("../");
+
+tape("quadtree.findInCircle(x, y, radius) returns all the points within the search radius of the given [x, y]", function(test) {
+ const points = [[0, 0], [100, 0], [0, 100], [100, 100]];
+ const q = d3_quadtree.quadtree(points);
+ test.deepEqual(q.findInCircle(20, 20, Infinity), points);
+ test.deepEqual(q.findInCircle(20, 20, 20 * Math.SQRT2 + 1e-6), [points[0]]);
+ test.deepEqual(q.findInCircle(20, 20, 20 * Math.SQRT2 - 1e-6), []);
+ test.deepEqual(q.findInCircle(50, 0, 51), [points[0], points[1]]);
+ test.end();
+});
+
+tape("quadtree.findInCircle(x, y, radius, filter) returns all the points within the search radius of the given [x, y] and passing filter", function(test) {
+ const points = [[0, 0, "a"], [0, 0, "b"], [100, 0, "a"], [0, 100, "b"], [100, 100, "a"]];
+ const q = d3_quadtree.quadtree(points);
+ const filter = d => d[2] === "a";
+ test.deepEqual(q.findInCircle(20, 20, Infinity, filter), points.filter(filter));
+ test.deepEqual(q.findInCircle(0, 0, 2, filter), [points[0]]);
+ test.end();
+});