block by mbostock 6216724

Brush Transitions

Full Screen

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!

index.html

<!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>