title: D3.js: Combining Zoom/Brush
body: <p>I'm currently working off of Mike Bostock's <a href="https://bl.ocks.org/mbostock/34f08d5e11952a80609169b7917d4172" rel="nofollow noreferrer">Brush &amp; Zoom</a> example although instead of having an overlayed rect object over the svg, I have it attached to my chart so that I can still use mouseover events and whatnot.</p>
  
  <p>I'm having great difficulty combining both brush and zoom functionalities. Both work fine but do not "remember" their current state. For instance, if I'm to pan/resize the brush, all is fine with zoom but if I was to then use mouse/touchpad events to zoom, it would jump along the brush and completely lose where I was in the chart.</p>
  
  <p>How would I get the zoom to "remember" where it was in the brush viewport, and to work fluidly?</p>
  
  <pre><code>function brushed() {
      if (d3.event.sourceEvent &amp;&amp; d3.event.sourceEvent.type === "zoom") return;
      var selection = d3.event.selection;
      x.domain(selection.map(x2.invert, x2));
      focus.selectAll(".point")
          .attr("cx", function(d){
              var time = timeParser(d.timestamp);
              return x(time);
          })
          .attr("cy", function(d){
              return y(d.value);
          });
      focus.selectAll(".trendline")
          .attr("d", function(d){
              return line(d);
          });
      focus.selectAll(".area")
          .attr("d", function(d){
              return area(d);
          });
      focus.select(".axis.x").call(xAxis);
      svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
          .scale(width / (selection[1] - selection[0]))
          .translate(-selection[0], 0));
  }
  
  function zoomed() {
      if (d3.event.sourceEvent &amp;&amp; d3.event.sourceEvent.type === "brush") return;
      var t = d3.event.transform;
      x.domain(t.rescaleX(x2).domain());
      focus.selectAll(".point")
          .attr("cx", function(d){
              var time = timeParser(d.timestamp);
              return x(time);
          })
          .attr("cy", function(d){
              return y(d.value);
          });
      focus.selectAll(".trendline")
          .attr("d", function(d){
              return line(d);
          });
      focus.selectAll(".area")
          .attr("d", function(d){
              return area(d);
          });
      focus.select(".axis.x").call(xAxis);
      context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
  }
  </code></pre>
  
  <p>And here's how the chart looks to give a sort of rough idea:</p>
  
  <p><a href="https://i.stack.imgur.com/0MLoX.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/0MLoX.png" alt="enter image description here"></a></p>