block by alexmacy eb284831aff6f9d0119b

Brush Slider Test

Full Screen

Update 1/27/2017

This has been updated to d3.js v4 with comments explaining some of the changes. Brushes have been one of the more difficult aspects of moving from v3 to v4, but updating this block has clarified a lot for me.


Testing a brush-style slider, loosely based on Mike Bostock’s Brush Handles example.

The number feedback at the top can be sent to a chart as a filter.

index.html

<!DOCTYPE html>
<meta charset="utf-8">
  <script src="//d3js.org/d3.v4.min.js"></script>
<!-- 
  axes and brushes are styled out of the box, 
    so this is no longer needed
<style>
  
  .axis path, .axis line {
    fill: none;
    stroke: #000;
    shape-rendering: crispEdges;
  }
  .brush .extent {
    fill-opacity: .125;
    shape-rendering: crispEdges;
  }

</style>
-->

<body>
  <div style="margin-left: 20px;margin-top: 20px">
    <span></span> to <span></span>
  </div>
</body>

<script>

    var margin = 20,
        width = 400 - margin * 2,
        height = 20;

    // v3 = var x = d3.scale.linear()
    var x = d3.scaleLinear()
        .domain([0,100])
        .range([0, width]);

    /*
    var brush = d3.svg.brush()
      .x(x)
      .extent([20, 50]);
    */
    var brush = d3.brushX()
        .extent([[0,0], [width,height]])
        .on("brush", brushed);

    var svg = d3.select("body").append("svg")
        .attr("width", width + margin * 2)
        .attr("height", height + margin)
      .append("g")
        .attr("transform", "translate(" + margin + "," + margin + ")")
        .call(d3.axisBottom()
            .scale(x)
            .ticks(5));

    var brushg = svg.append("g")
        .attr("class", "brush")
        .call(brush)
    
    /* 
      Height of the brush's rect is now 
        generated by brush.extent():
    brushg.selectAll("rect")
        .attr("height", height);
    */

    function brushed() {
      /*
        The brush attributes are no longer stored 
        in the brush itself, but rather in the 
        element it is brushing. That's where much of
        the confusion around v4's brushes seems to be.
        The new method is a little difficult to adapt
        to, but seems more efficient. I think much of
        this confusion comes from the fact that 
        brush.extent() still exists, but means
        something completely different.

        Instead of calling brush.extent() to get the 
        range of the brush, call 
        d3.brushSelection(node) on what is being 
        brushed.

      d3.select('#start-number')
        .text(Math.round(brush.extent()[0]));
      d3.select('#end-number')
        .text(Math.round(brush.extent()[1]));
      */


      var range = d3.brushSelection(this)
          .map(x.invert);
      
      d3.selectAll("span")
          .text(function(d, i) {
            return Math.round(range[i])
          })
    }

    // v3:  brushed();
    brush.move(brushg, [20, 50].map(x));

</script>