While studying how d3-quadtree was built, I wanted to be able to interactively modify a quadtree.
This is a remix of Mike Bostock's example.
In diving through d3-quadtree, one finds "fun" bits of code like this one.
license: gpl-3.0 | |
height: 960 |
While studying how d3-quadtree was built, I wanted to be able to interactively modify a quadtree.
This is a remix of Mike Bostock's example.
In diving through d3-quadtree, one finds "fun" bits of code like this one.
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
svg { | |
cursor: crosshair; | |
position: absolute; | |
} | |
circle { | |
fill: rgba(240,0,0,1); | |
} | |
rect { | |
fill: none; | |
stroke-dasharray: 5, 5; | |
stroke: rgba(0,0,0,1); | |
stroke-width: 1px; | |
} | |
rect.leaf { | |
stroke-dasharray: none; | |
fill: rgba(0,0,0,0.1); | |
} | |
rect.leaf:hover { | |
fill: rgba(0,0,240,0.3); | |
} | |
text { | |
font-family: Helvetica; | |
font-size: 24px; | |
font-weight: bold; | |
text-anchor: middle; | |
} | |
</style> | |
<svg id="quadtree" width="960" height="960"></svg> | |
<script src="https://d3js.org/d3.v4.js"></script> | |
<script> | |
var svg = d3.select("#quadtree"); | |
var width = 960, | |
height = 960, | |
radius = 1.5; | |
var text = svg.append("text") | |
.text("Click to add a point.") | |
.attr("x", width / 2) | |
.attr("y", height / 2); | |
svg.on("click", click); | |
let points = [], | |
quads = [], | |
extent = [[1, 1],[width - 1, height - 1]]; | |
var quadtree = d3.quadtree() | |
.x(function(d) { return d.x; }) | |
.y(function(d) { return d.y; }); | |
function click() { | |
if (text) { | |
text.remove(); | |
text = undefined; | |
} | |
var mouse = d3.mouse(this), | |
newPoint = {x: mouse[0], y: mouse[1]}; | |
points.push(newPoint); | |
quadtree.add(newPoint); | |
quads = []; | |
// Pre-order traversal of the quadtree. | |
quadtree.visit(function(node, x0, y0, x1, y1) { | |
if (node.data) { // Leaf node to be rendered. | |
quads.push({ | |
"data": node.data, | |
"x0": x0, | |
"y0": y0, | |
"x1": x1, | |
"y1": y1 | |
}); | |
} | |
}); | |
extent = quadtree.extent(); | |
quads.push({ | |
"x0": extent[0][0], | |
"y0": extent[0][1], | |
"x1": extent[1][0], | |
"y1": extent[1][1] | |
}); | |
update(); | |
} | |
function update() { | |
var circle, rectangle; | |
circle = svg.selectAll("circle") | |
.data(points); | |
circle.exit().remove(); | |
circle.enter().append("circle") | |
.attr("cx", function(d) { return d.x; }) | |
.attr("cy", function(d) { return d.y; }) | |
.attr("r", radius) | |
.merge(circle); | |
// Rather than attempt to "key" quads, simply redraw them all. | |
rectangle = svg.selectAll("rect").remove(); | |
rectangle = svg.selectAll("rect") | |
.data(quads); | |
rectangle.exit().remove(); | |
rectangle.enter().append("rect") | |
.attr("x", function(d) { return d.x0; }) | |
.attr("y", function(d) { return d.y0; }) | |
.attr("width", function(d) { return d.x1 - d.x0; }) | |
.attr("height", function(d) { return d.y1 - d.y0; }) | |
.classed("leaf", function(d) { return d.data; }) | |
.merge(circle); | |
} | |
</script> |
TODO
Right click on square to delete a point from the quadtree.