score:2

Accepted answer

Here is a working example based on your code: http://jsfiddle.net/26sd8uc9/4/

1 - You are right about the .extent, the problem is that you haven't specify the domain for you x2 scale. By adding the following code it works:

x2 = d3.time.scale()
   .domain([
     parseDate("2014-08-11 05:30:00"), 
     parseDate("2014-08-12 19:25:00")
   ])
   .nice(d3.time.minute)
   .range([0, width]);

And to initialize the circles, you also have to call the brushed event after creating the brush by adding .call(brush.event):

  // brush slider display
  context.append("g")
      .attr("class", "x brush")
      .call(brush)
      .call(brush.event)
      .selectAll("rect")
      .attr("y", -6)
      .attr("height", height2 + 7);

2 - use a variable to keep track where is the current range under the brush, and hide the circles that are not in the range by setting the radius to zero(alternatively you can set the visibility)

var currentRange;

var inRange = function(d) { 
    if(!currentRange || d.time < currentRange[0] || d.time > currentRange[1] ) {
        return 0;
    } else {
        return 5;
    }
}

function brushed() {

  currentRange = (brush.empty()? undefined : brush.extent());

  x.domain(brush.empty() ? x2.domain() : brush.extent());
  focus.select(".x.axis").call(xAxis);
  mydots.selectAll(".circle")
   .attr("cx", xMap)
   .attr("cy", yMap)
   .attr("r", inRange); // set radius to zero if it's not in range
  console.log(brush.extent())
}

For the scale definition, it will be better to write something like this:

        .domain([
            d3.min(dataset, function(d){ return d.time; }), 
            d3.max(dataset, function(d){ return d.time; })
        ])

In your example, you have to make sure to parse and initialize the data before you do this.

score:3

For your first question, you need to call brush.event to get the brush to pick up the new extent.

  brush = d3.svg.brush()
      .x(x)
      .extent([config.start, d3.time.day.offset(config.start, config.range)])
      .on("brush", brushmove)
      .on("brushend", brushend);

  gBrush = svg.select('.brush')
    .call(brush);

  gBrush.call(brush.event);

For your second question, I usually just filter out the data that is outside the brush extent such that I am only drawing the visible data. Here is an example that would be called on your brush move/zoom event:

  // update the data so that only visible points are shown
  var points= svg.selectAll('.point')
      .data(function(d) { return onScreen(d, brush.extent); },
            function(d) { return d.id; });

  // draw the points that are now onscreen
  var pointsEnter = points.enter().append('g').attr('class', 'point');

  // remove any points that are now offscreen
  points.exit().remove();

  // up date the x/y position of your points based on the new axis.
  // ... left up to you

It's helpful to have a unique id for the points so that they can just be translated to their new positions as the brush moves instead of having to destroy them and redraw them.

I have an example that uses these techniques at http://bl.ocks.org/bunkat/1962173.


Related Query

More Query from same tag