title: Issue w/ Programmatic Zoom v4
body: <p>I'm using <code>d3.js v4</code>. I'm currently implementing programmatic zoom. This <a href="http://emptypipes.org/2016/07/03/d3-panning-and-zooming/">Panning and Zooming Tutorial</a> has helped tremendously. My zoom works with scrolling wheel, but I want to create buttons to zoom. I know what necessary for zooming and panning is a translation <code>[tx, ty]</code> and a scale factor <code>k</code>. I'm using timescale for my x-Axis. I've managed to get <code>tx</code> and scale factor of <code>k</code>, by getting the pixel value of <code>p1 (point 1)</code> and <code>p2(point 2)</code> on the x-axis and then using those values to get a k (Scale factor). Like such:</p>
  
  <pre><code>var k = 500 / (xScale(p2) - xScale(p1)); //500 is desired pixel diff. between p1 and p2, and xScale is my d3.scaleTime() accessor function.
  // for this zoom i just want the first value and last value to be at scale difference of the entire width.
  </code></pre>
  
  <p>Then I calculate tx by this:</p>
  
  <pre><code>var tx = 0 - k * p1;
  </code></pre>
  
  <p>Then feeding it into a <code>d3.zoomIdentity()</code> and rescaling my xdomain. I created a button to zoom back out. The issue is when I zoom in and then try to use the button to zoom out, it zooms out, but shrinks the x-axis. I can't seem to findout why its shrinking the x-axis instead of zooming back out correctly.</p>
  
  <p><strong>My JSFiddle</strong></p>
  
  <p><a href="https://jsfiddle.net/codekhalifah/Lmdfrho7/2/">https://jsfiddle.net/codekhalifah/Lmdfrho7/2/</a></p>
  
  <p><strong>What I've Tried</strong></p>
  
  <ul>
  <li>Read zoom <a href="https://github.com/d3/d3/blob/master/API.md#zooming-d3-zoom">Documentation</a></li>
  <li>Read through chapter on zoom in <a href="https://www.manning.com/books/d3-js-in-action">D3.js in action</a></li>
  </ul>
  
  <p><strong>My Code</strong></p>
  
  <p>After wheel zoom is applied I run this function:</p>
  
  <pre><code> function zoomed() {
          if (d3.event.sourceEvent &amp;&amp; d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush  
  var t = d3.event.transform;
  console.log(t);
  console.log(xScale.domain());
  xScale.domain(t.rescaleX(x2).domain());
  usageAreaPath.attr("d", area);
  usageLinePath.attr('d',line);
  weatherAreaPath.attr('d',weatherChart.area);
  focus.select(".axis--x").call(xAxis);
  focus.selectAll('.circle')
      .attr('cx', function(d) { return xScale(getDate(d)); })
      .attr('cy', function(d) { return yScale(d.kWh); })
      .attr("transform", "translate(0," + 80 + ")");
  
          ... other non related items
      }
  </code></pre>
  
  <p>The zoom works properly, but after zooming in and then manually attempting to zoom back normal position I want.
  My manual zoom button function</p>
  
  <pre><code>function programmaticZoom(){
   var currDataSet = usageLinePath.data()[0], //current data set
          currDataSetLength = currDataSet.length,//current data set length
          x1 = currDataSet[0].usageTime, //getting first data item
          x2 = currDataSet[currDataSetLength-1].usageTime, //2nd data item
          x1px = xScale(moment(x1)), //Get current point 1
          x2px = xScale(moment(x2)); // Get current point 2
  
          // calculate scale factor
          var k = width / (x2px - x1px); // get scale factor
          var tx = 0 - k * x1px; // get tx
          var t = d3.zoomIdentity.translate(tx).scale(k); //create zoom identity
  
          xScale.domain(t.rescaleX(window.x2).domain());
          usageAreaPath.attr("d", area);
          usageLinePath.attr('d',line);
          weatherAreaPath.attr('d',weatherChart.area);
          focus.select(".axis--x").call(xAxis);
          focus.selectAll('.circle')
              .attr('cx', function(d) { return xScale(getDate(d)); })
              .attr('cy', function(d) { return yScale(d.kWh); })
              .attr("transform", "translate(0," + 80 + ")");
  
  }
  </code></pre>