mirror of
https://github.com/d3/d3.git
synced 2025-12-08 19:46:24 +00:00
110 lines
2.6 KiB
HTML
110 lines
2.6 KiB
HTML
<!DOCTYPE html>
|
|
<meta charset="utf-8">
|
|
<title>Quadtree</title>
|
|
<style>
|
|
|
|
svg {
|
|
padding: 2px;
|
|
}
|
|
|
|
circle {
|
|
fill: lightsteelblue;
|
|
stroke: steelblue;
|
|
stroke-width: 1.5px;
|
|
}
|
|
|
|
rect {
|
|
fill: none;
|
|
stroke: #000;
|
|
stroke-opacity: .3;
|
|
}
|
|
|
|
</style>
|
|
<body>
|
|
<script src="../../d3.js"></script>
|
|
<script>
|
|
|
|
var width = 500;
|
|
|
|
// Generate random points.
|
|
var data = d3.range(500).map(function() {
|
|
return {
|
|
x: Math.random() * width,
|
|
y: Math.random() * width
|
|
};
|
|
});
|
|
|
|
// Generate a quadtree of the specified data.
|
|
var quadtree = d3.geom.quadtree(data, 0, width);
|
|
|
|
var vis = d3.select("body").append("svg")
|
|
.attr("width", width)
|
|
.attr("height", width)
|
|
.style("pointer-events", "all");
|
|
|
|
vis.selectAll("rect")
|
|
.data(nodes(quadtree))
|
|
.enter().append("rect")
|
|
.attr("x", function(d) { return d.x; })
|
|
.attr("y", function(d) { return d.y; })
|
|
.attr("width", function(d) { return d.width; })
|
|
.attr("height", function(d) { return d.height; });
|
|
|
|
vis.selectAll("circle")
|
|
.data(data)
|
|
.enter().append("circle")
|
|
.attr("cx", function(d) { return d.x; })
|
|
.attr("cy", function(d) { return d.y; })
|
|
.attr("r", 4.5);
|
|
|
|
// Highlight selected nodes using the quadtree.
|
|
vis.on("mousedown", function() {
|
|
var m0 = d3.mouse(this);
|
|
|
|
var rect = d3.select(this).append("rect")
|
|
.style("fill", "#999")
|
|
.style("fill-opacity", .5);
|
|
|
|
d3.select(window).on("mousemove", function() {
|
|
var m1 = d3.mouse(rect.node()),
|
|
x0 = Math.min(width, m0[0], m1[0]),
|
|
y0 = Math.min(width, m0[1], m1[1]),
|
|
x1 = Math.max(0, m0[0], m1[0]),
|
|
y1 = Math.max(0, m0[1], m1[1]);
|
|
|
|
data.forEach(function(d) { d.z = 0; })
|
|
find(quadtree, x0, y0, x1, y1).forEach(function(d) { d.z = 1; });
|
|
vis.selectAll("circle").style("fill", function(d) { return d.z ? "red" : null; });
|
|
rect.attr("x", x0).attr("y", y0).attr("width", x1 - x0).attr("height", y1 - y0);
|
|
});
|
|
|
|
d3.select(window).on("mouseup", function() {
|
|
rect.remove();
|
|
d3.select(window).on("mousemove", null).on("mouseup", null);
|
|
});
|
|
|
|
d3.event.preventDefault();
|
|
});
|
|
|
|
// Collapse the quadtree into an array of rectangles.
|
|
function nodes(quadtree) {
|
|
var nodes = [];
|
|
quadtree.visit(function(node, x1, y1, x2, y2) {
|
|
nodes.push({x: x1, y: y1, width: x2 - x1, height: y2 - y1});
|
|
});
|
|
return nodes;
|
|
}
|
|
|
|
// Find the nodes within the specified rectangle.
|
|
function find(quadtree, x0, y0, x3, y3) {
|
|
var points = [];
|
|
quadtree.visit(function(node, x1, y1, x2, y2) {
|
|
var p = node.point;
|
|
if (p && (p.x >= x0) && (p.x < x3) && (p.y >= y0) && (p.y < y3)) points.push(p);
|
|
return x1 >= x3 || y1 >= y3 || x2 < x0 || y2 < y0;
|
|
});
|
|
return points;
|
|
}
|
|
|
|
</script>
|