Skip to content

Instantly share code, notes, and snippets.

@mbostock
Last active February 9, 2016 02:02
Show Gist options
  • Save mbostock/6216724 to your computer and use it in GitHub Desktop.
Save mbostock/6216724 to your computer and use it in GitHub Desktop.
Brush Transitions
license: gpl-3.0

This example demonstrates brush transitions, a new feature in D3 3.3.

Try dragging the brush or selecting a new region. When you mouseup, the brush transitions smoothly back to its original position. The transition is initiated simply by applying the brush to a transition (rather than a selection), similar to automatic axis transitions. Note that interacting with the brush interrupts the current transition!

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
position: relative;
width: 960px;
}
.point {
fill: #999;
stroke: #fff;
}
.point.selected {
fill: red;
fill-opacity: 1;
stroke: brown;
}
.brush .extent {
stroke: #fff;
fill-opacity: .125;
shape-rendering: crispEdges;
}
button {
position: absolute;
right: 30px;
top: 30px;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 960,
height = 500,
defaultExtent = [[100, 100], [300, 300]],
data = d3.range(5000).map(function() { return [Math.random() * width, Math.random() * width]; });
var quadtree = d3.geom.quadtree()
.extent([[-1, -1], [width + 1, height + 1]])
(data);
var x = d3.scale.identity().domain([0, width]),
y = d3.scale.identity().domain([0, height]);
var brush = d3.svg.brush()
.x(x)
.y(y)
.extent(defaultExtent)
.on("brush", brushed)
.on("brushend", brushended);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var point = svg.selectAll(".point")
.data(data)
.enter().append("circle")
.attr("class", "point")
.attr("cx", function(d) { return d[0]; })
.attr("cy", function(d) { return d[1]; })
.attr("r", 4);
svg.append("g")
.attr("class", "brush")
.call(brush)
.call(brush.event);
function brushed() {
var extent = brush.extent();
point.each(function(d) { d.selected = false; });
search(quadtree, extent[0][0], extent[0][1], extent[1][0], extent[1][1]);
point.classed("selected", function(d) { return d.selected; });
}
function brushended() {
if (!d3.event.sourceEvent) return; // only transition after input
d3.select(this).transition()
.duration(brush.empty() ? 0 : 750)
.call(brush.extent(defaultExtent))
.call(brush.event);
}
// Find the nodes within the specified rectangle.
function search(quadtree, x0, y0, x3, y3) {
quadtree.visit(function(node, x1, y1, x2, y2) {
var p = node.point;
if (p) p.selected = (p[0] >= x0) && (p[0] < x3) && (p[1] >= y0) && (p[1] < y3);
return x1 >= x3 || y1 >= y3 || x2 < x0 || y2 < y0;
});
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment